1 /* Copyright 2001-2003 Roger Dingledine, Matej Pfajfar. */
2 /* See LICENSE for licensing information */
5 #define OR_PUBLICKEY_BEGIN_TAG "-----BEGIN RSA PUBLIC KEY-----\n"
6 #define OR_PUBLICKEY_END_TAG "-----END RSA PUBLIC KEY-----\n"
7 #define OR_SIGNATURE_BEGIN_TAG "-----BEGIN SIGNATURE-----\n"
8 #define OR_SIGNATURE_END_TAG "-----END SIGNATURE-----\n"
11 /* XXX this is required on rh7 to make strptime not complain. how bad
12 * is this for portability?
17 /****************************************************************************/
19 static routerlist_t
*routerlist
= NULL
; /* router array */
20 extern or_options_t options
; /* command-line and config-file options */
22 /****************************************************************************/
24 /* Enumeration of possible token types. The ones starting with K_ correspond
25 * to directory 'keywords'. _SIGNATURE and _PUBLIC_KEY are self-explanitory.
26 * _ERR is an error in the tokenizing process, _EOF is an end-of-file marker,
27 * and _NIL is used to encode not-a-token.
31 K_DIRECTORY_SIGNATURE
,
32 K_RECOMMENDED_SOFTWARE
,
50 /* Struct containing a directory token. */
52 typedef struct directory_token_t
{
53 directory_keyword tp
; /* Type of the token. */
56 char *args
[MAX_ARGS
+1]; /* For K_xxx tokens only: an array and count */
57 int n_args
; /* of arguments provided on the same line */
59 char *signature
; /* For _SIGNATURE tokens only. */
60 char *error
; /* For _ERR tokens only. */
61 crypto_pk_env_t
*public_key
; /* For _PUBLIC_KEY tokens only. */
65 /****************************************************************************/
69 /* static function prototypes */
70 static int router_set_routerlist_from_string(const char *s
);
72 router_get_list_from_string_impl(const char **s
, routerlist_t
**dest
,
74 const char **good_nickname_lst
);
76 router_get_routerlist_from_directory_impl(const char *s
, routerlist_t
**dest
,
77 crypto_pk_env_t
*pkey
);
78 static int router_add_exit_policy(routerinfo_t
*router
,
79 directory_token_t
*tok
);
80 static int router_resolve_routerlist(routerlist_t
*dir
);
84 static int _router_get_next_token(const char **s
, directory_token_t
*tok
);
85 #ifdef DEBUG_ROUTER_TOKENS
86 static int router_get_next_token(const char **s
, directory_token_t
*tok
);
88 #define router_get_next_token _router_get_next_token
90 static int router_get_hash_impl(const char *s
, char *digest
,
91 const char *start_str
,
93 static void router_release_token(directory_token_t
*tok
);
96 /****************************************************************************/
97 routerinfo_t
*router_pick_directory_server(void) {
98 /* pick a random running router with a positive dir_port */
100 routerinfo_t
*router
, *dirserver
=NULL
;
101 int num_dirservers
=0;
106 for(i
=0;i
<routerlist
->n_routers
;i
++) {
107 router
= routerlist
->routers
[i
];
108 if(router
->dir_port
> 0 && router
->is_running
)
112 if(!num_dirservers
) {
113 log_fn(LOG_INFO
,"No dirservers are reachable. Trying them all again.");
114 /* no running dir servers found? go through and mark them all as up,
115 * and we'll cycle through the list again. */
116 for(i
=0;i
<routerlist
->n_routers
;i
++) {
117 router
= routerlist
->routers
[i
];
118 if(router
->dir_port
> 0) {
119 router
->is_running
= 1;
126 j
= crypto_pseudo_rand_int(num_dirservers
);
127 for (i
=0;i
<routerlist
->n_routers
;i
++) {
128 router
= routerlist
->routers
[i
];
129 if (router
->dir_port
> 0 && router
->is_running
) {
133 log_fn(LOG_DEBUG
, "Chose server '%s'", router
->nickname
);
142 routerinfo_t
*router_pick_randomly_from_running(void) {
149 for(i
=0;i
<routerlist
->n_routers
;i
++) {
150 if(routerlist
->routers
[i
]->is_running
)
155 log_fn(LOG_INFO
,"No routers are running. Returning NULL.");
158 j
= crypto_pseudo_rand_int(num_running
);
159 for (i
=0;i
<routerlist
->n_routers
;i
++) {
160 if (routerlist
->routers
[i
]->is_running
) {
164 log_fn(LOG_DEBUG
, "Chose server '%s'", routerlist
->routers
[i
]->nickname
);
165 return routerlist
->routers
[i
];
173 routerinfo_t
*router_get_by_addr_port(uint32_t addr
, uint16_t port
) {
175 routerinfo_t
*router
;
179 for(i
=0;i
<routerlist
->n_routers
;i
++) {
180 router
= routerlist
->routers
[i
];
181 if ((router
->addr
== addr
) && (router
->or_port
== port
))
187 routerinfo_t
*router_get_by_link_pk(crypto_pk_env_t
*pk
)
190 routerinfo_t
*router
;
194 for(i
=0;i
<routerlist
->n_routers
;i
++) {
195 router
= routerlist
->routers
[i
];
196 if (0 == crypto_pk_cmp_keys(router
->link_pkey
, pk
))
202 routerinfo_t
*router_get_by_nickname(char *nickname
)
205 routerinfo_t
*router
;
209 for(i
=0;i
<routerlist
->n_routers
;i
++) {
210 router
= routerlist
->routers
[i
];
211 if (0 == strcmp(router
->nickname
, nickname
))
217 /* a way to access routerlist outside this file */
218 void router_get_routerlist(routerlist_t
**prouterlist
) {
219 *prouterlist
= routerlist
;
222 /* delete a router from memory */
223 void routerinfo_free(routerinfo_t
*router
)
225 struct exit_policy_t
*e
;
230 tor_free(router
->address
);
231 tor_free(router
->nickname
);
232 if (router
->onion_pkey
)
233 crypto_free_pk_env(router
->onion_pkey
);
234 if (router
->link_pkey
)
235 crypto_free_pk_env(router
->link_pkey
);
236 if (router
->identity_pkey
)
237 crypto_free_pk_env(router
->identity_pkey
);
238 while (router
->exit_policy
) {
239 e
= router
->exit_policy
;
240 router
->exit_policy
= e
->next
;
247 static void routerlist_free(routerlist_t
*rl
)
250 for (i
= 0; i
< rl
->n_routers
; ++i
)
251 routerinfo_free(rl
->routers
[i
]);
252 tor_free(rl
->routers
);
253 tor_free(rl
->software_versions
);
257 void router_mark_as_down(char *nickname
) {
258 routerinfo_t
*router
= router_get_by_nickname(nickname
);
259 if(!router
) /* we don't seem to know about him in the first place */
261 log_fn(LOG_DEBUG
,"Marking %s as down.",router
->nickname
);
262 router
->is_running
= 0;
265 /* ------------------------------------------------------------ */
267 /* Replace the current router list with the one stored in 'routerfile'. */
268 int router_set_routerlist_from_file(char *routerfile
)
272 string
= read_file_to_str(routerfile
);
274 log_fn(LOG_WARN
,"Failed to load routerfile %s.",routerfile
);
278 if(router_set_routerlist_from_string(string
) < 0) {
279 log_fn(LOG_WARN
,"The routerfile itself was corrupt.");
289 /* Helper function: read routerinfo elements from s, and throw out the
290 * ones that don't parse and resolve. Replace the current
292 static int router_set_routerlist_from_string(const char *s
)
294 if (router_get_list_from_string_impl(&s
, &routerlist
, -1, NULL
)) {
295 log(LOG_WARN
, "Error parsing router file");
298 if (router_resolve_routerlist(routerlist
)) {
299 log(LOG_WARN
, "Error resolving routerlist");
305 /* Set 'digest' to the SHA-1 digest of the hash of the directory in 's'.
306 * Return 0 on success, nonzero on failure.
308 int router_get_dir_hash(const char *s
, char *digest
)
310 return router_get_hash_impl(s
,digest
,
311 "signed-directory","directory-signature");
313 /* Set 'digest' to the SHA-1 digest of the hash of the first router in 's'.
314 * Return 0 on success, nonzero on failure.
316 int router_get_router_hash(const char *s
, char *digest
)
318 return router_get_hash_impl(s
,digest
,
319 "router ","router-signature");
322 /* return 0 if myversion is in versionlist. Else return -1. (versionlist
323 * contains a comma-separated list of versions.) */
324 int compare_recommended_versions(const char *myversion
,
325 const char *versionlist
) {
326 int len_myversion
= strlen(myversion
);
328 const char *end
= versionlist
+ strlen(versionlist
);
330 log_fn(LOG_DEBUG
,"checking '%s' in '%s'.", myversion
, versionlist
);
333 comma
= strchr(versionlist
, ',');
334 if( ((comma
? comma
: end
) - versionlist
== len_myversion
) &&
335 !strncmp(versionlist
, myversion
, len_myversion
))
336 /* only do strncmp if the length matches */
337 return 0; /* success, it's there */
339 return -1; /* nope */
340 versionlist
= comma
+1;
344 /* Replace the current routerlist with the routers stored in the directory
345 * 's'. If pkey is provided, make sure that 's' is signed with pkey.
347 int router_set_routerlist_from_directory(const char *s
, crypto_pk_env_t
*pkey
)
349 if (router_get_routerlist_from_directory_impl(s
, &routerlist
, pkey
)) {
350 log_fn(LOG_WARN
, "Couldn't parse directory.");
353 if (router_resolve_routerlist(routerlist
)) {
354 log_fn(LOG_WARN
, "Error resolving routerlist");
357 if (compare_recommended_versions(VERSION
, routerlist
->software_versions
) < 0) {
358 log(options
.IgnoreVersion
? LOG_WARN
: LOG_ERR
,
359 "You are running Tor version %s, which is not recommended.\n"
360 "Please upgrade to one of %s.",
361 VERSION
, routerlist
->software_versions
);
362 if(options
.IgnoreVersion
) {
363 log(LOG_WARN
, "IgnoreVersion is set. If it breaks, we told you so.");
373 /* Helper function: resolve the hostname for 'router' */
375 router_resolve(routerinfo_t
*router
)
377 struct hostent
*rent
;
379 rent
= (struct hostent
*)gethostbyname(router
->address
);
381 log_fn(LOG_WARN
,"Could not get address for router %s.",router
->address
);
384 assert(rent
->h_length
== 4);
385 memcpy(&router
->addr
, rent
->h_addr
,rent
->h_length
);
386 router
->addr
= ntohl(router
->addr
); /* get it back into host order */
391 /* Helper function: resolve every router in rl. */
393 router_resolve_routerlist(routerlist_t
*rl
)
400 for (i
= 0; i
< max
; ++i
) {
402 if (router_resolve(rl
->routers
[i
])) {
403 log_fn(LOG_WARN
, "Couldn't resolve router %s; not using",
404 rl
->routers
[i
]->address
);
406 } else if (options
.Nickname
&&
407 !strcmp(rl
->routers
[i
]->nickname
, options
.Nickname
)) {
411 routerinfo_free(rl
->routers
[i
]);
412 rl
->routers
[i
] = rl
->routers
[--max
];
421 /* Addr is 0 for "IP unknown".
423 * Returns -1 for 'rejected', 0 for accepted, 1 for 'maybe' (since IP is
426 int router_supports_exit_address(uint32_t addr
, uint16_t port
,
427 routerinfo_t
*router
)
429 return router_compare_addr_to_exit_policy(addr
, port
, router
->exit_policy
);
432 /* Addr is 0 for "IP unknown".
434 * Returns -1 for 'rejected', 0 for accepted, 1 for 'maybe' (since IP is
437 int router_compare_addr_to_exit_policy(uint32_t addr
, uint16_t port
,
438 struct exit_policy_t
*policy
)
440 int maybe_reject
= 0;
443 struct exit_policy_t
*tmpe
;
445 for(tmpe
=policy
; tmpe
; tmpe
=tmpe
->next
) {
446 log_fn(LOG_DEBUG
,"Considering exit policy %s", tmpe
->string
);
448 /* Address is unknown. */
449 if (tmpe
->msk
== 0 && (!tmpe
|| port
== tmpe
->prt
)) {
450 /* The exit policy is accept/reject *:port */
452 } else if ((!tmpe
->prt
|| port
== tmpe
->prt
) &&
453 tmpe
->policy_type
== EXIT_POLICY_REJECT
) {
454 /* The exit policy is reject ???:port */
458 /* Address is known */
459 if ( (addr
& tmpe
->msk
) == (tmpe
->addr
& tmpe
->msk
) &&
460 (!tmpe
->prt
|| port
== tmpe
->prt
) ) {
461 /* Exact match for the policy */
466 in
.s_addr
= htonl(addr
);
467 log_fn(LOG_INFO
,"Address %s:%d matches exit policy '%s'",
468 inet_ntoa(in
), port
, tmpe
->string
);
469 if(tmpe
->policy_type
== EXIT_POLICY_ACCEPT
)
478 return 0; /* accept all by default. */
481 /* return 1 if all running routers will reject addr:port, return 0 if
482 any might accept it. */
483 int router_exit_policy_all_routers_reject(uint32_t addr
, uint16_t port
) {
485 routerinfo_t
*router
;
487 for (i
=0;i
<routerlist
->n_routers
;i
++) {
488 router
= routerlist
->routers
[i
];
489 if (router
->is_running
&& router_compare_addr_to_exit_policy(addr
,
490 port
, router
->exit_policy
) >= 0)
491 return 0; /* this one could be ok. good enough. */
493 return 1; /* all will reject. */
496 int router_exit_policy_rejects_all(routerinfo_t
*router
) {
497 if (router_compare_addr_to_exit_policy(0, 0, router
->exit_policy
) < 0)
498 return 1; /* yes, rejects all */
500 return 0; /* no, might accept some */
504 /* Helper function: parse a directory from 's' and, when done, store the
505 * resulting routerlist in *dest, freeing the old value if necessary.
506 * If pkey is provided, we check the directory signature with pkey.
509 router_get_routerlist_from_directory_impl(const char *s
, routerlist_t
**dest
,
510 crypto_pk_env_t
*pkey
)
512 directory_token_t tok
;
514 char signed_digest
[128];
515 routerlist_t
*new_dir
= NULL
;
516 char *versions
= NULL
;
519 char *good_nickname_lst
[1024];
520 int n_good_nicknames
= 0;
523 /* Local helper macro: get the next token from s (advancing s) and
524 * bail on failure. */
527 if (router_get_next_token(&s, &tok)) { \
528 log_fn(LOG_WARN, "Error reading directory: %s", tok.val.error); \
531 /* Local helper macro: bail if the most recently read token is not of
533 #define TOK_IS(type,name) \
535 if (tok.tp != type) { \
536 router_release_token(&tok); \
537 log_fn(LOG_WARN, "Error reading directory: expected %s", name); \
540 /* Local helper macro: Number of args in most recent token. */
541 #define N_ARGS tok.val.cmd.n_args
542 /* Local helper macro: Array of args to most recent token. */
543 #define ARGS tok.val.cmd.args
547 if (router_get_dir_hash(s
, digest
)) {
548 log_fn(LOG_WARN
, "Unable to compute digest of directory");
551 log(LOG_DEBUG
,"Received directory hashes to %02x:%02x:%02x:%02x",
552 ((int)digest
[0])&0xff,((int)digest
[1])&0xff,
553 ((int)digest
[2])&0xff,((int)digest
[3])&0xff);
556 TOK_IS(K_SIGNED_DIRECTORY
, "signed-directory");
559 TOK_IS(K_PUBLISHED
, "published");
561 if (!strptime(ARGS
[0], "%Y-%m-%d %H:%M:%S", &published
)) {
562 log_fn(LOG_WARN
, "Published time was unparseable"); goto err
;
564 published_on
= tor_timegm(&published
);
567 TOK_IS(K_RECOMMENDED_SOFTWARE
, "recommended-software");
569 log_fn(LOG_WARN
, "Invalid recommended-software line");
573 tok
.val
.cmd
.n_args
= 0; /* Don't let the versions string get freed. */
576 TOK_IS(K_RUNNING_ROUTERS
, "running-routers");
577 n_good_nicknames
= N_ARGS
;
578 memcpy(good_nickname_lst
, ARGS
, n_good_nicknames
*sizeof(char *));
579 N_ARGS
= 0; /* Don't free the strings in good_nickname_lst. */
581 /* Read the router list from s, advancing s up past the end of the last
583 if (router_get_list_from_string_impl(&s
, &new_dir
,
585 (const char**)good_nickname_lst
)) {
586 log_fn(LOG_WARN
, "Error reading routers from directory");
589 new_dir
->software_versions
= versions
; versions
= NULL
;
590 new_dir
->published_on
= published_on
;
593 TOK_IS(K_DIRECTORY_SIGNATURE
, "directory-signature");
595 TOK_IS(_SIGNATURE
, "signature");
597 if (crypto_pk_public_checksig(pkey
, tok
.val
.signature
, 128, signed_digest
)
599 log_fn(LOG_WARN
, "Error reading directory: invalid signature.");
602 log(LOG_DEBUG
,"Signed directory hash starts %02x:%02x:%02x:%02x",
603 ((int)signed_digest
[0])&0xff,((int)signed_digest
[1])&0xff,
604 ((int)signed_digest
[2])&0xff,((int)signed_digest
[3])&0xff);
605 if (memcmp(digest
, signed_digest
, 20)) {
606 log_fn(LOG_WARN
, "Error reading directory: signature does not match.");
612 TOK_IS(_EOF
, "end of directory");
615 routerlist_free(*dest
);
621 router_release_token(&tok
);
623 routerlist_free(new_dir
);
625 for (i
= 0; i
< n_good_nicknames
; ++i
) {
626 tor_free(good_nickname_lst
[i
]);
635 /* Helper function: Given a string *s containing a concatenated
636 * sequence of router descriptors, parses them and stores the result
637 * in *dest. If good_nickname_lst is provided, then routers whose
638 * nicknames are not listed are marked as nonrunning. Advances *s to
639 * a point immediately following the last router entry. Returns 0 on
640 * success and -1 on failure.
643 router_get_list_from_string_impl(const char **s
, routerlist_t
**dest
,
644 int n_good_nicknames
,
645 const char **good_nickname_lst
)
647 routerinfo_t
*router
;
648 routerinfo_t
**rarray
;
654 rarray
= (routerinfo_t
**)
655 tor_malloc((sizeof(routerinfo_t
*))*MAX_ROUTERS_IN_DIR
);
658 *s
= eat_whitespace(*s
);
659 /* Don't start parsing the rest of *s unless it contains a router. */
660 if (strncmp(*s
, "router ", 7)!=0)
662 router
= router_get_entry_from_string(s
);
664 log_fn(LOG_WARN
, "Error reading router");
665 for(i
=0;i
<rarray_len
;i
++)
666 routerinfo_free(rarray
[i
]);
670 if (rarray_len
>= MAX_ROUTERS_IN_DIR
) {
671 log_fn(LOG_WARN
, "too many routers");
672 routerinfo_free(router
);
675 if (n_good_nicknames
>=0) {
676 router
->is_running
= 0;
677 for (i
= 0; i
< n_good_nicknames
; ++i
) {
678 if (0==strcasecmp(good_nickname_lst
[i
], router
->nickname
)) {
679 router
->is_running
= 1;
684 router
->is_running
= 1; /* start out assuming all dirservers are up */
686 rarray
[rarray_len
++] = router
;
687 log_fn(LOG_DEBUG
,"just added router #%d.",rarray_len
);
691 routerlist_free(*dest
);
692 *dest
= (routerlist_t
*)tor_malloc(sizeof(routerlist_t
));
693 (*dest
)->routers
= rarray
;
694 (*dest
)->n_routers
= rarray_len
;
695 (*dest
)->software_versions
= NULL
;
700 /* Helper function: reads a single router entry from *s, and advances
701 * *s so it points to just after the router it just read.
702 * mallocs a new router and returns it if all goes well, else returns
705 routerinfo_t
*router_get_entry_from_string(const char**s
) {
706 routerinfo_t
*router
= NULL
;
707 char signed_digest
[128];
709 directory_token_t _tok
;
710 directory_token_t
*tok
= &_tok
;
714 /* Helper macro: read the next token from *s, advance *s, and bail
715 if there's an error */
716 #define NEXT_TOKEN() \
717 do { if (router_get_next_token(s, tok)) { \
718 log_fn(LOG_WARN, "Error reading directory: %s", tok->val.error);\
722 #define ARGS tok->val.cmd.args
723 #define N_ARGS tok->val.cmd.n_args
727 if (router_get_router_hash(*s
, digest
) < 0) {
728 log_fn(LOG_WARN
, "Couldn't compute router hash.");
734 if (tok
->tp
!= K_ROUTER
) {
735 log_fn(LOG_WARN
,"Entry does not start with \"router\"");
739 router
= tor_malloc_zero(sizeof(routerinfo_t
));
740 router
->onion_pkey
= router
->identity_pkey
= router
->link_pkey
= NULL
;
743 log_fn(LOG_WARN
,"Wrong # of arguments to \"router\"");
746 router
->nickname
= tor_strdup(ARGS
[0]);
747 if (strlen(router
->nickname
) > MAX_NICKNAME_LEN
) {
748 log_fn(LOG_WARN
,"Router nickname too long.");
751 if (strspn(router
->nickname
, LEGAL_NICKNAME_CHARACTERS
) !=
752 strlen(router
->nickname
)) {
753 log_fn(LOG_WARN
, "Router nickname contains illegal characters.");
757 /* read router.address */
758 router
->address
= tor_strdup(ARGS
[1]);
761 /* Read router->or_port */
762 router
->or_port
= atoi(ARGS
[2]);
763 if(!router
->or_port
) {
764 log_fn(LOG_WARN
,"or_port unreadable or 0. Failing.");
768 /* Router->socks_port */
769 router
->socks_port
= atoi(ARGS
[3]);
771 /* Router->dir_port */
772 router
->dir_port
= atoi(ARGS
[4]);
774 /* Router->bandwidth */
775 router
->bandwidth
= atoi(ARGS
[5]);
776 if (!router
->bandwidth
) {
777 log_fn(LOG_WARN
,"bandwidth unreadable or 0. Failing.");
781 log_fn(LOG_DEBUG
,"or_port %d, socks_port %d, dir_port %d, bandwidth %d.",
782 router
->or_port
, router
->socks_port
, router
->dir_port
, router
->bandwidth
);
784 /* XXX Later, require platform before published. */
786 if (tok
->tp
== K_PLATFORM
) {
790 if (tok
->tp
!= K_PUBLISHED
) {
791 log_fn(LOG_WARN
, "Missing published time"); goto err
;
794 if (!strptime(ARGS
[0], "%Y-%m-%d %H:%M:%S", &published
)) {
795 log_fn(LOG_WARN
, "Published time was unparseable"); goto err
;
797 router
->published_on
= tor_timegm(&published
);
800 if (tok
->tp
!= K_ONION_KEY
) {
801 log_fn(LOG_WARN
, "Missing onion-key"); goto err
;
804 if (tok
->tp
!= _PUBLIC_KEY
) {
805 log_fn(LOG_WARN
, "Missing onion key"); goto err
;
806 } /* XXX Check key length */
807 router
->onion_pkey
= tok
->val
.public_key
;
810 if (tok
->tp
!= K_LINK_KEY
) {
811 log_fn(LOG_WARN
, "Missing link-key"); goto err
;
814 if (tok
->tp
!= _PUBLIC_KEY
) {
815 log_fn(LOG_WARN
, "Missing link key"); goto err
;
816 } /* XXX Check key length */
817 router
->link_pkey
= tok
->val
.public_key
;
820 if (tok
->tp
!= K_SIGNING_KEY
) {
821 log_fn(LOG_WARN
, "Missing signing-key"); goto err
;
824 if (tok
->tp
!= _PUBLIC_KEY
) {
825 log_fn(LOG_WARN
, "Missing signing key"); goto err
;
827 router
->identity_pkey
= tok
->val
.public_key
;
830 while (tok
->tp
== K_ACCEPT
|| tok
->tp
== K_REJECT
) {
831 router_add_exit_policy(router
, tok
);
835 if (tok
->tp
!= K_ROUTER_SIGNATURE
) {
836 log_fn(LOG_WARN
,"Missing router signature");
840 if (tok
->tp
!= _SIGNATURE
) {
841 log_fn(LOG_WARN
,"Missing router signature");
844 assert (router
->identity_pkey
);
846 if ((t
=crypto_pk_public_checksig(router
->identity_pkey
, tok
->val
.signature
,
847 128, signed_digest
)) != 20) {
848 log_fn(LOG_WARN
, "Invalid signature %d",t
);
851 if (memcmp(digest
, signed_digest
, 20)) {
852 log_fn(LOG_WARN
, "Mismatched signature");
856 router_release_token(tok
); /* free the signature */
860 router_release_token(tok
);
861 routerinfo_free(router
);
868 /* Parse the exit policy in the string 's' and add it to 'router'.
871 router_add_exit_policy_from_string(routerinfo_t
*router
, const char *s
)
873 directory_token_t tok
;
881 /* *s might not end with \n, so we need to extend it with one. */
883 cp
= tmp
= tor_malloc(len
+2);
884 for (idx
= 0; idx
< len
; ++idx
) {
885 tmp
[idx
] = tolower(s
[idx
]);
889 if (router_get_next_token(&cp
, &tok
)) {
890 log_fn(LOG_WARN
, "Error reading exit policy: %s", tok
.val
.error
);
894 if (tok
.tp
!= K_ACCEPT
&& tok
.tp
!= K_REJECT
) {
895 log_fn(LOG_WARN
, "Expected 'accept' or 'reject'.");
900 /* Now that we've gotten an exit policy, add it to the router. */
901 r
= router_add_exit_policy(router
, &tok
);
906 /* Given a K_ACCEPT or K_REJECT token and a router, create a new exit_policy_t
907 * corresponding to the token, and add it to 'router' */
908 static int router_add_exit_policy(routerinfo_t
*router
,
909 directory_token_t
*tok
) {
911 struct exit_policy_t
*tmpe
, *newe
;
913 char *arg
, *address
, *mask
, *port
, *endptr
;
916 assert(tok
->tp
== K_REJECT
|| tok
->tp
== K_ACCEPT
);
918 if (tok
->val
.cmd
.n_args
!= 1)
920 arg
= tok
->val
.cmd
.args
[0];
922 newe
= tor_malloc_zero(sizeof(struct exit_policy_t
));
924 newe
->string
= tor_malloc(8+strlen(arg
));
925 if (tok
->tp
== K_REJECT
) {
926 strcpy(newe
->string
, "reject ");
927 newe
->policy_type
= EXIT_POLICY_REJECT
;
929 strcpy(newe
->string
, "accept ");
930 newe
->policy_type
= EXIT_POLICY_ACCEPT
;
932 strcat(newe
->string
, arg
);
935 mask
= strchr(arg
,'/');
936 port
= strchr(mask
?mask
:arg
,':');
938 goto policy_read_failed
;
943 if (strcmp(address
, "*") == 0) {
945 } else if (inet_aton(address
, &in
) != 0) {
946 newe
->addr
= ntohl(in
.s_addr
);
948 log_fn(LOG_WARN
, "Malformed IP %s in exit policy; rejecting.",
950 goto policy_read_failed
;
953 if (strcmp(address
, "*") == 0)
956 newe
->msk
= 0xFFFFFFFFu
;
959 bits
= (int) strtol(mask
, &endptr
, 10);
961 /* strtol handled the whole mask. */
962 newe
->msk
= ~((1<<(32-bits
))-1);
963 } else if (inet_aton(mask
, &in
) != 0) {
964 newe
->msk
= ntohl(in
.s_addr
);
966 log_fn(LOG_WARN
, "Malformed mask %s on exit policy; rejecting.",
968 goto policy_read_failed
;
971 if (strcmp(port
, "*") == 0) {
975 newe
->prt
= strtol(port
, &endptr
, 10);
977 log_fn(LOG_WARN
, "Malformed port %s on exit policy; rejecting.",
979 goto policy_read_failed
;
983 in
.s_addr
= htonl(newe
->addr
);
984 address
= tor_strdup(inet_ntoa(in
));
985 in
.s_addr
= htonl(newe
->msk
);
986 log_fn(LOG_DEBUG
,"%s %s/%s:%d",
987 newe
->policy_type
== EXIT_POLICY_REJECT
? "reject" : "accept",
988 address
, inet_ntoa(in
), newe
->prt
);
991 /* now link newe onto the end of exit_policy */
993 if(!router
->exit_policy
) {
994 router
->exit_policy
= newe
;
998 for(tmpe
=router
->exit_policy
; tmpe
->next
; tmpe
=tmpe
->next
) ;
1004 assert(newe
->string
);
1005 log_fn(LOG_WARN
,"Couldn't parse line '%s'. Dropping", newe
->string
);
1006 tor_free(newe
->string
);
1011 /* ------------------------------------------------------------ */
1012 /* Tokenizer for router descriptors and directories. */
1014 /* Every keyword takes either... */
1016 NO_ARGS
, /* (1) no arguments, ever */
1017 ARGS
, /* (2) a list of arguments separated by spaces */
1018 CONCAT_ARGS
, /* or (3) the rest of the line, treated as a single argument. */
1021 /* Table mapping keywods to token value and to argument rules. */
1022 static struct { char *t
; int v
; arg_syntax s
; } token_table
[] = {
1023 { "accept", K_ACCEPT
, ARGS
},
1024 { "directory-signature", K_DIRECTORY_SIGNATURE
, NO_ARGS
},
1025 { "reject", K_REJECT
, ARGS
},
1026 { "router", K_ROUTER
, ARGS
},
1027 { "recommended-software", K_RECOMMENDED_SOFTWARE
, ARGS
},
1028 { "signed-directory", K_SIGNED_DIRECTORY
, NO_ARGS
},
1029 { "signing-key", K_SIGNING_KEY
, NO_ARGS
},
1030 { "onion-key", K_ONION_KEY
, NO_ARGS
},
1031 { "link-key", K_LINK_KEY
, NO_ARGS
},
1032 { "router-signature", K_ROUTER_SIGNATURE
, NO_ARGS
},
1033 { "published", K_PUBLISHED
, CONCAT_ARGS
},
1034 { "running-routers", K_RUNNING_ROUTERS
, ARGS
},
1035 { "platform", K_PLATFORM
, ARGS
},
1039 /* Free any malloced resources allocated for a token. Does not free
1043 router_release_token(directory_token_t
*tok
)
1049 free(tok
->val
.signature
);
1052 crypto_free_pk_env(tok
->val
.public_key
);
1059 for (i
= 0; i
< tok
->val
.cmd
.n_args
; ++i
) {
1060 tor_free(tok
->val
.cmd
.args
[i
]);
1066 /* Helper function: read the next token from *s, and stores it into *tok.
1067 * If *tok already contains a token (tok->tp != _NIL), free the resources
1068 * held by *tok. Advance *s to a point immediately after the token.
1073 _router_get_next_token(const char **s
, directory_token_t
*tok
) {
1075 crypto_pk_env_t
*pkey
= NULL
;
1076 char *signature
= NULL
;
1080 tok
->val
.error
= "";
1082 router_release_token(tok
);
1084 *s
= eat_whitespace(*s
);
1088 } else if (**s
== '-') {
1089 next
= strchr(*s
, '\n');
1090 if (! next
) { tok
->val
.error
= "No newline at EOF"; return -1; }
1092 if (! strncmp(*s
, OR_PUBLICKEY_BEGIN_TAG
, next
-*s
)) {
1093 /* We have a ----BEGIN PUBLIC KEY----- */
1094 next
= strstr(*s
, OR_PUBLICKEY_END_TAG
);
1095 if (!next
) { tok
->val
.error
= "No public key end tag found"; return -1; }
1096 next
= strchr(next
, '\n'); /* Part of OR_PUBLICKEY_END_TAG; can't fail.*/
1098 if (!(pkey
= crypto_new_pk_env(CRYPTO_PK_RSA
)))
1100 if (crypto_pk_read_public_key_from_string(pkey
, *s
, next
-*s
)) {
1101 crypto_free_pk_env(pkey
);
1102 tok
->val
.error
= "Couldn't parse public key.";
1105 tok
->tp
= _PUBLIC_KEY
;
1106 tok
->val
.public_key
= pkey
;
1109 } else if (! strncmp(*s
, OR_SIGNATURE_BEGIN_TAG
, next
-*s
)) {
1110 /* We have a -----BEGIN SIGNATURE----- */
1111 /* Advance past newline; can't fail. */
1112 *s
= strchr(*s
, '\n');
1114 /* Find end of base64'd data */
1115 next
= strstr(*s
, OR_SIGNATURE_END_TAG
);
1116 if (!next
) { tok
->val
.error
= "No signature end tag found"; return -1; }
1118 signature
= tor_malloc(256);
1119 i
= base64_decode(signature
, 256, *s
, next
-*s
);
1122 tok
->val
.error
= "Error decoding signature."; return -1;
1123 } else if (i
!= 128) {
1125 tok
->val
.error
= "Bad length on decoded signature."; return -1;
1127 tok
->tp
= _SIGNATURE
;
1128 tok
->val
.signature
= signature
;
1130 next
= strchr(next
, '\n'); /* Part of OR_SIGNATURE_END_TAG; can't fail.*/
1134 tok
->val
.error
= "Unrecognized begin line"; return -1;
1137 next
= find_whitespace(*s
);
1139 tok
->val
.error
= "Unexpected EOF"; return -1;
1141 /* It's a keyword... but which one? */
1142 for (i
= 0 ; token_table
[i
].t
; ++i
) {
1143 if (!strncmp(token_table
[i
].t
, *s
, next
-*s
)) {
1144 /* We've found the keyword. */
1145 tok
->tp
= token_table
[i
].v
;
1147 if (token_table
[i
].s
== ARGS
) {
1148 /* This keyword takes multiple arguments. */
1150 done
= (*next
== '\n');
1151 *s
= eat_whitespace_no_nl(next
);
1152 while (**s
!= '\n' && i
< MAX_ARGS
&& !done
) {
1153 next
= find_whitespace(*s
);
1156 tok
->val
.cmd
.args
[i
++] = tor_strndup(*s
,next
-*s
);
1157 *s
= eat_whitespace_no_nl(next
+1);
1159 tok
->val
.cmd
.n_args
= i
;
1160 if (i
>= MAX_ARGS
) {
1161 /* XXX free args[0..i] */
1163 tok
->val
.error
= "Too many arguments"; return -1;
1165 } else if (token_table
[i
].s
== CONCAT_ARGS
) {
1166 /* The keyword takes the line as a single argument */
1167 *s
= eat_whitespace_no_nl(next
);
1168 next
= strchr(*s
, '\n');
1171 tok
->val
.error
= "Unexpected EOF"; return -1;
1173 tok
->val
.cmd
.args
[0] = tor_strndup(*s
,next
-*s
);
1174 tok
->val
.cmd
.n_args
= 1;
1175 *s
= eat_whitespace_no_nl(next
+1);
1177 /* The keyword takes no arguments. */
1178 *s
= eat_whitespace_no_nl(next
);
1181 tok
->val
.error
= "Unexpected arguments"; return -1;
1183 tok
->val
.cmd
.n_args
= 0;
1184 *s
= eat_whitespace_no_nl(*s
+1);
1189 tok
->val
.error
= "Unrecognized command"; return -1;
1193 #ifdef DEBUG_ROUTER_TOKENS
1195 router_dump_token(directory_token_t
*tok
) {
1200 puts("(signature)");
1203 puts("(public key)");
1206 printf("(Error: %s\n)", tok
->val
.error
);
1211 case K_ACCEPT
: printf("Accept"); break;
1212 case K_DIRECTORY_SIGNATURE
: printf("Directory-Signature"); break;
1213 case K_REJECT
: printf("Reject"); break;
1214 case K_RECOMMENDED_SOFTWARE
: printf("Server-Software"); break;
1215 case K_ROUTER
: printf("Router"); break;
1216 case K_SIGNED_DIRECTORY
: printf("Signed-Directory"); break;
1217 case K_SIGNING_KEY
: printf("Signing-Key"); break;
1218 case K_ONION_KEY
: printf("Onion-key"); break;
1219 case K_LINK_KEY
: printf("Link-key"); break;
1220 case K_ROUTER_SIGNATURE
: printf("Router-signature"); break;
1221 case K_PUBLISHED
: printf("Published"); break;
1222 case K_RUNNING_ROUTERS
: printf("Running-routers"); break;
1223 case K_PLATFORM
: printf("Platform"); break;
1225 printf("?????? %d\n", tok
->tp
); return;
1227 for (i
= 0; i
< tok
->val
.cmd
.n_args
; ++i
) {
1228 printf(" \"%s\"", tok
->val
.cmd
.args
[i
]);
1234 router_get_next_token(const char **s
, directory_token_t
*tok
) {
1236 i
= _router_get_next_token(s
, tok
);
1237 router_dump_token(tok
);
1241 #define router_get_next_token _router_get_next_token
1244 /* Compute the SHA digest of the substring of s taken from the first
1245 * occurrence of start_str through the first newline after the first
1246 * subsequent occurrence of end_str; store the 20-byte result in 'digest';
1247 * return 0 on success.
1249 * If no such substring exists, return -1.
1251 static int router_get_hash_impl(const char *s
, char *digest
,
1252 const char *start_str
,
1253 const char *end_str
)
1256 start
= strstr(s
, start_str
);
1258 log_fn(LOG_WARN
,"couldn't find \"%s\"",start_str
);
1261 end
= strstr(start
+strlen(start_str
), end_str
);
1263 log_fn(LOG_WARN
,"couldn't find \"%s\"",end_str
);
1266 end
= strchr(end
, '\n');
1268 log_fn(LOG_WARN
,"couldn't find EOL");
1273 if (crypto_SHA_digest(start
, end
-start
, digest
)) {
1274 log_fn(LOG_WARN
,"couldn't compute digest");
1286 indent-tabs-mode:nil