terminology shift:
[tor.git] / src / or / routers.c
blobccaa7f72ece99f5e85e209613b2071229087c3f8
1 /* Copyright 2001-2003 Roger Dingledine, Matej Pfajfar. */
2 /* See LICENSE for licensing information */
3 /* $Id$ */
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"
10 #define _GNU_SOURCE
11 /* XXX this is required on rh7 to make strptime not complain. how bad
12 * is this for portability?
15 #include "or.h"
17 /****************************************************************************/
19 static routerlist_t *routerlist = NULL; /* router array */
20 static routerinfo_t *desc_routerinfo = NULL; /* my descriptor */
21 static char descriptor[8192]; /* string representation of my descriptor */
23 extern or_options_t options; /* command-line and config-file options */
25 /****************************************************************************/
27 struct directory_token;
28 typedef struct directory_token directory_token_t;
30 /* static function prototypes */
31 static int router_add_exit_policy_from_string(routerinfo_t *router, char *s);
32 static int router_add_exit_policy(routerinfo_t *router,
33 directory_token_t *tok);
34 static int router_resolve_routerlist(routerlist_t *dir);
36 /****************************************************************************/
38 void router_retry_connections(void) {
39 int i;
40 routerinfo_t *router;
42 for (i=0;i<routerlist->n_routers;i++) {
43 router = routerlist->routers[i];
44 if(!connection_exact_get_by_addr_port(router->addr,router->or_port)) {
45 /* not in the list */
46 log_fn(LOG_DEBUG,"connecting to OR %s:%u.",router->address,router->or_port);
47 connection_or_connect(router);
52 routerinfo_t *router_pick_directory_server(void) {
53 /* pick a random running router with a positive dir_port */
54 int i,j;
55 routerinfo_t *router, *dirserver=NULL;
56 int num_dirservers=0;
58 if(!routerlist)
59 return NULL;
61 for(i=0;i<routerlist->n_routers;i++) {
62 router = routerlist->routers[i];
63 if(router->dir_port > 0 && router->is_running)
64 num_dirservers++;
67 if(!num_dirservers) {
68 log_fn(LOG_INFO,"No dirservers are reachable. Trying them all again.");
69 /* no running dir servers found? go through and mark them all as up,
70 * and we'll cycle through the list again. */
71 for(i=0;i<routerlist->n_routers;i++) {
72 router = routerlist->routers[i];
73 if(router->dir_port > 0) {
74 router->is_running = 1;
75 dirserver = router;
78 return dirserver;
81 j = crypto_pseudo_rand_int(num_dirservers);
82 for (i=0;i<routerlist->n_routers;i++) {
83 router = routerlist->routers[i];
84 if (router->dir_port > 0 && router->is_running) {
85 if (j)
86 --j;
87 else {
88 log_fn(LOG_DEBUG, "Chose server '%s'", router->nickname);
89 return router;
93 assert(0);
94 return NULL;
97 routerinfo_t *router_pick_randomly_from_running(void) {
98 int i,j;
99 int num_running=0;
101 if(!routerlist)
102 return NULL;
104 for(i=0;i<routerlist->n_routers;i++) {
105 if(routerlist->routers[i]->is_running)
106 num_running++;
109 if(!num_running) {
110 log_fn(LOG_INFO,"No routers are running. Returning NULL.");
111 return NULL;
113 j = crypto_pseudo_rand_int(num_running);
114 for (i=0;i<routerlist->n_routers;i++) {
115 if (routerlist->routers[i]->is_running) {
116 if (j)
117 --j;
118 else {
119 log_fn(LOG_DEBUG, "Chose server '%s'", routerlist->routers[i]->nickname);
120 return routerlist->routers[i];
124 assert(0);
125 return NULL;
128 void router_upload_desc_to_dirservers(void) {
129 int i;
130 routerinfo_t *router;
132 if(!routerlist)
133 return;
135 if (!router_get_my_descriptor()) {
136 log_fn(LOG_WARN, "No descriptor; skipping upload");
137 return;
140 for(i=0;i<routerlist->n_routers;i++) {
141 router = routerlist->routers[i];
142 if(router->dir_port > 0)
143 directory_initiate_command(router, DIR_CONN_STATE_CONNECTING_UPLOAD);
147 routerinfo_t *router_get_by_addr_port(uint32_t addr, uint16_t port) {
148 int i;
149 routerinfo_t *router;
151 assert(routerlist);
153 for(i=0;i<routerlist->n_routers;i++) {
154 router = routerlist->routers[i];
155 if ((router->addr == addr) && (router->or_port == port))
156 return router;
158 return NULL;
161 routerinfo_t *router_get_by_link_pk(crypto_pk_env_t *pk)
163 int i;
164 routerinfo_t *router;
166 assert(routerlist);
168 for(i=0;i<routerlist->n_routers;i++) {
169 router = routerlist->routers[i];
170 if (0 == crypto_pk_cmp_keys(router->link_pkey, pk))
171 return router;
173 return NULL;
176 routerinfo_t *router_get_by_nickname(char *nickname)
178 int i;
179 routerinfo_t *router;
181 assert(routerlist);
183 for(i=0;i<routerlist->n_routers;i++) {
184 router = routerlist->routers[i];
185 if (0 == strcmp(router->nickname, nickname))
186 return router;
188 return NULL;
191 /* a way to access routerlist outside this file */
192 void router_get_routerlist(routerlist_t **prouterlist) {
193 *prouterlist = routerlist;
196 /* delete a router from memory */
197 void routerinfo_free(routerinfo_t *router)
199 struct exit_policy_t *e;
201 if (!router)
202 return;
204 tor_free(router->address);
205 tor_free(router->nickname);
206 if (router->onion_pkey)
207 crypto_free_pk_env(router->onion_pkey);
208 if (router->link_pkey)
209 crypto_free_pk_env(router->link_pkey);
210 if (router->identity_pkey)
211 crypto_free_pk_env(router->identity_pkey);
212 while (router->exit_policy) {
213 e = router->exit_policy;
214 router->exit_policy = e->next;
215 tor_free(e->string);
216 free(e);
218 free(router);
221 void routerlist_free(routerlist_t *rl)
223 int i;
224 for (i = 0; i < rl->n_routers; ++i)
225 routerinfo_free(rl->routers[i]);
226 tor_free(rl->routers);
227 tor_free(rl->software_versions);
228 free(rl);
231 void router_mark_as_down(char *nickname) {
232 routerinfo_t *router = router_get_by_nickname(nickname);
233 if(!router) /* we don't seem to know about him in the first place */
234 return;
235 log_fn(LOG_DEBUG,"Marking %s as down.",router->nickname);
236 router->is_running = 0;
239 /* load the router list */
240 int router_set_routerlist_from_file(char *routerfile)
242 char *string;
244 string = read_file_to_str(routerfile);
245 if(!string) {
246 log_fn(LOG_WARN,"Failed to load routerfile %s.",routerfile);
247 return -1;
250 if(router_set_routerlist_from_string(string) < 0) {
251 log_fn(LOG_WARN,"The routerfile itself was corrupt.");
252 free(string);
253 return -1;
256 free(string);
257 return 0;
260 typedef enum {
261 K_ACCEPT,
262 K_DIRECTORY_SIGNATURE,
263 K_RECOMMENDED_SOFTWARE,
264 K_REJECT,
265 K_ROUTER,
266 K_SIGNED_DIRECTORY,
267 K_SIGNING_KEY,
268 K_ONION_KEY,
269 K_LINK_KEY,
270 K_ROUTER_SIGNATURE,
271 K_PUBLISHED,
272 K_RUNNING_ROUTERS,
273 K_PLATFORM,
274 _SIGNATURE,
275 _PUBLIC_KEY,
276 _ERR,
277 _EOF
278 } directory_keyword;
280 struct token_table_ent { char *t; int v; };
282 static struct token_table_ent token_table[] = {
283 { "accept", K_ACCEPT },
284 { "directory-signature", K_DIRECTORY_SIGNATURE },
285 { "reject", K_REJECT },
286 { "router", K_ROUTER },
287 { "recommended-software", K_RECOMMENDED_SOFTWARE },
288 { "signed-directory", K_SIGNED_DIRECTORY },
289 { "signing-key", K_SIGNING_KEY },
290 { "onion-key", K_ONION_KEY },
291 { "link-key", K_LINK_KEY },
292 { "router-signature", K_ROUTER_SIGNATURE },
293 { "published", K_PUBLISHED },
294 { "running-routers", K_RUNNING_ROUTERS },
295 { "platform", K_PLATFORM },
296 { NULL, -1 }
299 #define MAX_ARGS 1024
300 struct directory_token {
301 directory_keyword tp;
302 union {
303 struct {
304 char *args[MAX_ARGS+1];
305 int n_args;
306 } cmd;
307 char *signature;
308 char *error;
309 crypto_pk_env_t *public_key;
310 } val;
313 /* Free any malloced resources allocated for a token. Don't call this if
314 you inherit the reference to those resources.
316 static void
317 router_release_token(directory_token_t *tok)
319 switch (tok->tp)
321 case _SIGNATURE:
322 free(tok->val.signature);
323 break;
324 case _PUBLIC_KEY:
325 crypto_free_pk_env(tok->val.public_key);
326 break;
327 default:
328 break;
332 static int
333 _router_get_next_token(char **s, directory_token_t *tok) {
334 char *next;
335 crypto_pk_env_t *pkey = NULL;
336 char *signature = NULL;
337 int i, done;
339 tok->tp = _ERR;
340 tok->val.error = "";
342 *s = eat_whitespace(*s);
343 if (!**s) {
344 tok->tp = _EOF;
345 return 0;
346 } else if (**s == '-') {
347 next = strchr(*s, '\n');
348 if (! next) { tok->val.error = "No newline at EOF"; return -1; }
349 ++next;
350 if (! strncmp(*s, OR_PUBLICKEY_BEGIN_TAG, next-*s)) {
351 next = strstr(*s, OR_PUBLICKEY_END_TAG);
352 if (!next) { tok->val.error = "No public key end tag found"; return -1; }
353 next = strchr(next, '\n'); /* Part of OR_PUBLICKEY_END_TAG; can't fail.*/
354 ++next;
355 if (!(pkey = crypto_new_pk_env(CRYPTO_PK_RSA)))
356 return -1;
357 if (crypto_pk_read_public_key_from_string(pkey, *s, next-*s)) {
358 crypto_free_pk_env(pkey);
359 tok->val.error = "Couldn't parse public key.";
360 return -1;
362 tok->tp = _PUBLIC_KEY;
363 tok->val.public_key = pkey;
364 *s = next;
365 return 0;
366 } else if (! strncmp(*s, OR_SIGNATURE_BEGIN_TAG, next-*s)) {
367 /* Advance past newline; can't fail. */
368 *s = strchr(*s, '\n');
369 ++*s;
370 /* Find end of base64'd data */
371 next = strstr(*s, OR_SIGNATURE_END_TAG);
372 if (!next) { tok->val.error = "No signature end tag found"; return -1; }
374 signature = tor_malloc(256);
375 i = base64_decode(signature, 256, *s, next-*s);
376 if (i<0) {
377 free(signature);
378 tok->val.error = "Error decoding signature."; return -1;
379 } else if (i != 128) {
380 free(signature);
381 tok->val.error = "Bad length on decoded signature."; return -1;
383 tok->tp = _SIGNATURE;
384 tok->val.signature = signature;
386 next = strchr(next, '\n'); /* Part of OR_SIGNATURE_END_TAG; can't fail.*/
387 *s = next+1;
388 return 0;
389 } else {
390 tok->val.error = "Unrecognized begin line"; return -1;
392 } else {
393 next = find_whitespace(*s);
394 if (!next) {
395 tok->val.error = "Unexpected EOF"; return -1;
397 for (i = 0 ; token_table[i].t ; ++i) {
398 if (!strncmp(token_table[i].t, *s, next-*s)) {
399 tok->tp = token_table[i].v;
400 i = 0;
401 done = (*next == '\n');
402 *s = eat_whitespace_no_nl(next);
403 while (**s != '\n' && i <= MAX_ARGS && !done) {
404 next = find_whitespace(*s);
405 if (*next == '\n')
406 done = 1;
407 *next = 0;
408 tok->val.cmd.args[i++] = *s;
409 *s = eat_whitespace_no_nl(next+1);
411 tok->val.cmd.n_args = i;
412 if (i > MAX_ARGS) {
413 tok->tp = _ERR;
414 tok->val.error = "Too many arguments"; return -1;
416 return 0;
419 tok->val.error = "Unrecognized command"; return -1;
423 #ifdef DEBUG_ROUTER_TOKENS
424 static void
425 router_dump_token(directory_token_t *tok) {
426 int i;
427 switch(tok->tp)
429 case _SIGNATURE:
430 puts("(signature)");
431 return;
432 case _PUBLIC_KEY:
433 puts("(public key)");
434 return;
435 case _ERR:
436 printf("(Error: %s\n)", tok->val.error);
437 return;
438 case _EOF:
439 puts("EOF");
440 return;
441 case K_ACCEPT: printf("Accept"); break;
442 case K_DIRECTORY_SIGNATURE: printf("Directory-Signature"); break;
443 case K_REJECT: printf("Reject"); break;
444 case K_RECOMMENDED_SOFTWARE: printf("Server-Software"); break;
445 case K_ROUTER: printf("Router"); break;
446 case K_SIGNED_DIRECTORY: printf("Signed-Directory"); break;
447 case K_SIGNING_KEY: printf("Signing-Key"); break;
448 case K_ONION_KEY: printf("Onion-key"); break;
449 case K_LINK_KEY: printf("Link-key"); break;
450 case K_ROUTER_SIGNATURE: printf("Router-signature"); break;
451 case K_PUBLISHED: printf("Published"); break;
452 case K_RUNNING_ROUTERS: printf("Running-routers"); break;
453 case K_PLATFORM: printf("Platform"); break;
454 default:
455 printf("?????? %d\n", tok->tp); return;
457 for (i = 0; i < tok->val.cmd.n_args; ++i) {
458 printf(" \"%s\"", tok->val.cmd.args[i]);
460 printf("\n");
461 return;
463 static int
464 router_get_next_token(char **s, directory_token_t *tok) {
465 int i;
466 i = _router_get_next_token(s, tok);
467 router_dump_token(tok);
468 return i;
470 #else
471 #define router_get_next_token _router_get_next_token
472 #endif
474 /* read routerinfo elements from s, and throw out the ones that
475 * don't parse and resolve. */
476 int router_set_routerlist_from_string(char *s)
478 if (router_get_list_from_string_impl(&s, &routerlist, -1, NULL)) {
479 log(LOG_WARN, "Error parsing router file");
480 return -1;
482 if (router_resolve_routerlist(routerlist)) {
483 log(LOG_WARN, "Error resolving routerlist");
484 return -1;
486 return 0;
489 static int router_get_hash_impl(char *s, char *digest, const char *start_str,
490 const char *end_str)
492 char *start, *end;
493 start = strstr(s, start_str);
494 if (!start) {
495 log_fn(LOG_WARN,"couldn't find \"%s\"",start_str);
496 return -1;
498 end = strstr(start+strlen(start_str), end_str);
499 if (!end) {
500 log_fn(LOG_WARN,"couldn't find \"%s\"",end_str);
501 return -1;
503 end = strchr(end, '\n');
504 if (!end) {
505 log_fn(LOG_WARN,"couldn't find EOL");
506 return -1;
508 ++end;
510 if (crypto_SHA_digest(start, end-start, digest)) {
511 log_fn(LOG_WARN,"couldn't compute digest");
512 return -1;
515 return 0;
518 int router_get_dir_hash(char *s, char *digest)
520 return router_get_hash_impl(s,digest,
521 "signed-directory","directory-signature");
523 int router_get_router_hash(char *s, char *digest)
525 return router_get_hash_impl(s,digest,
526 "router ","router-signature");
529 /* return 0 if myversion is in start. Else return -1. */
530 int compare_recommended_versions(char *myversion, char *start) {
531 int len_myversion = strlen(myversion);
532 char *comma;
533 char *end = start + strlen(start);
535 log_fn(LOG_DEBUG,"checking '%s' in '%s'.", myversion, start);
537 for(;;) {
538 comma = strchr(start, ',');
539 if( ((comma ? comma : end) - start == len_myversion) &&
540 !strncmp(start, myversion, len_myversion))
541 /* only do strncmp if the length matches */
542 return 0; /* success, it's there */
543 if(!comma)
544 return -1; /* nope */
545 start = comma+1;
549 int router_set_routerlist_from_directory(char *s, crypto_pk_env_t *pkey)
551 if (router_get_routerlist_from_directory_impl(s, &routerlist, pkey)) {
552 log_fn(LOG_WARN, "Couldn't parse directory.");
553 return -1;
555 if (router_resolve_routerlist(routerlist)) {
556 log_fn(LOG_WARN, "Error resolving routerlist");
557 return -1;
559 if (compare_recommended_versions(VERSION, routerlist->software_versions) < 0) {
560 log(options.IgnoreVersion ? LOG_WARN : LOG_ERR,
561 "You are running Tor version %s, which is not recommended.\n"
562 "Please upgrade to one of %s.",
563 VERSION, routerlist->software_versions);
564 if(options.IgnoreVersion) {
565 log(LOG_WARN, "IgnoreVersion is set. If it breaks, we told you so.");
566 } else {
567 fflush(0);
568 exit(0);
572 return 0;
575 int router_get_routerlist_from_directory_impl(char *s, routerlist_t **dest,
576 crypto_pk_env_t *pkey)
578 directory_token_t tok;
579 char digest[20];
580 char signed_digest[128];
581 routerlist_t *new_dir = NULL;
582 char *versions;
583 struct tm published;
584 time_t published_on;
585 const char *good_nickname_lst[1024];
586 int n_good_nicknames;
588 #define NEXT_TOK() \
589 do { \
590 if (router_get_next_token(&s, &tok)) { \
591 log_fn(LOG_WARN, "Error reading directory: %s", tok.val.error);\
592 return -1; \
593 } } while (0)
594 #define TOK_IS(type,name) \
595 do { \
596 if (tok.tp != type) { \
597 router_release_token(&tok); \
598 log_fn(LOG_WARN, "Error reading directory: expected %s", name);\
599 return -1; \
600 } } while(0)
602 if (router_get_dir_hash(s, digest)) {
603 log_fn(LOG_WARN, "Unable to compute digest of directory");
604 goto err;
606 log(LOG_DEBUG,"Received directory hashes to %02x:%02x:%02x:%02x",
607 ((int)digest[0])&0xff,((int)digest[1])&0xff,
608 ((int)digest[2])&0xff,((int)digest[3])&0xff);
610 NEXT_TOK();
611 TOK_IS(K_SIGNED_DIRECTORY, "signed-directory");
613 NEXT_TOK();
614 TOK_IS(K_PUBLISHED, "published");
615 if (tok.val.cmd.n_args != 2) {
616 log_fn(LOG_WARN, "Invalid published line");
617 goto err;
619 tok.val.cmd.args[1][-1] = ' ';
620 if (!strptime(tok.val.cmd.args[0], "%Y-%m-%d %H:%M:%S", &published)) {
621 log_fn(LOG_WARN, "Published time was unparseable"); goto err;
623 published_on = tor_timegm(&published);
625 NEXT_TOK();
626 TOK_IS(K_RECOMMENDED_SOFTWARE, "recommended-software");
627 if (tok.val.cmd.n_args != 1) {
628 log_fn(LOG_WARN, "Invalid recommended-software line");
629 goto err;
631 versions = tor_strdup(tok.val.cmd.args[0]);
633 NEXT_TOK();
634 TOK_IS(K_RUNNING_ROUTERS, "running-routers");
635 n_good_nicknames = tok.val.cmd.n_args;
636 memcpy(good_nickname_lst, tok.val.cmd.args, n_good_nicknames*sizeof(char *));
638 if (router_get_list_from_string_impl(&s, &new_dir,
639 n_good_nicknames, good_nickname_lst)) {
640 log_fn(LOG_WARN, "Error reading routers from directory");
641 goto err;
643 new_dir->software_versions = versions;
644 new_dir->published_on = published_on;
646 NEXT_TOK();
647 TOK_IS(K_DIRECTORY_SIGNATURE, "directory-signature");
648 NEXT_TOK();
649 TOK_IS(_SIGNATURE, "signature");
650 if (pkey) {
651 if (crypto_pk_public_checksig(pkey, tok.val.signature, 128, signed_digest)
652 != 20) {
653 log_fn(LOG_WARN, "Error reading directory: invalid signature.");
654 free(tok.val.signature);
655 goto err;
657 log(LOG_DEBUG,"Signed directory hash starts %02x:%02x:%02x:%02x",
658 ((int)signed_digest[0])&0xff,((int)signed_digest[1])&0xff,
659 ((int)signed_digest[2])&0xff,((int)signed_digest[3])&0xff);
660 if (memcmp(digest, signed_digest, 20)) {
661 log_fn(LOG_WARN, "Error reading directory: signature does not match.");
662 free(tok.val.signature);
663 goto err;
666 free(tok.val.signature);
668 NEXT_TOK();
669 TOK_IS(_EOF, "end of directory");
671 if (*dest)
672 routerlist_free(*dest);
673 *dest = new_dir;
675 return 0;
677 err:
678 if (new_dir)
679 routerlist_free(new_dir);
680 return -1;
681 #undef NEXT_TOK
682 #undef TOK_IS
685 int router_get_list_from_string_impl(char **s, routerlist_t **dest,
686 int n_good_nicknames,
687 const char **good_nickname_lst)
689 routerinfo_t *router;
690 routerinfo_t **rarray;
691 int rarray_len = 0;
692 int i;
694 assert(s && *s);
696 rarray = (routerinfo_t **)tor_malloc((sizeof(routerinfo_t *))*MAX_ROUTERS_IN_DIR);
698 while (1) {
699 *s = eat_whitespace(*s);
700 if (strncmp(*s, "router ", 7)!=0)
701 break;
702 router = router_get_entry_from_string(s);
703 if (!router) {
704 log_fn(LOG_WARN, "Error reading router");
705 for(i=0;i<rarray_len;i++)
706 routerinfo_free(rarray[i]);
707 free(rarray);
708 return -1;
710 if (rarray_len >= MAX_ROUTERS_IN_DIR) {
711 log_fn(LOG_WARN, "too many routers");
712 routerinfo_free(router);
713 continue;
715 if (n_good_nicknames>=0) {
716 router->is_running = 0;
717 for (i = 0; i < n_good_nicknames; ++i) {
718 if (0==strcasecmp(good_nickname_lst[i], router->nickname)) {
719 router->is_running = 1;
720 break;
723 } else {
724 router->is_running = 1; /* start out assuming all dirservers are up */
726 rarray[rarray_len++] = router;
727 log_fn(LOG_DEBUG,"just added router #%d.",rarray_len);
730 if (*dest)
731 routerlist_free(*dest);
732 *dest = (routerlist_t *)tor_malloc(sizeof(routerlist_t));
733 (*dest)->routers = rarray;
734 (*dest)->n_routers = rarray_len;
735 (*dest)->software_versions = NULL;
736 return 0;
739 static int
740 router_resolve(routerinfo_t *router)
742 struct hostent *rent;
744 rent = (struct hostent *)gethostbyname(router->address);
745 if (!rent) {
746 log_fn(LOG_WARN,"Could not get address for router %s.",router->address);
747 return -1;
749 assert(rent->h_length == 4);
750 memcpy(&router->addr, rent->h_addr,rent->h_length);
751 router->addr = ntohl(router->addr); /* get it back into host order */
753 return 0;
756 static int
757 router_resolve_routerlist(routerlist_t *rl)
759 int i, max, remove;
760 if (!rl)
761 rl = routerlist;
763 max = rl->n_routers;
764 for (i = 0; i < max; ++i) {
765 remove = 0;
766 if (router_resolve(rl->routers[i])) {
767 log_fn(LOG_WARN, "Couldn't resolve router %s; not using",
768 rl->routers[i]->address);
769 remove = 1;
770 } else if (options.Nickname &&
771 !strcmp(rl->routers[i]->nickname, options.Nickname)) {
772 remove = 1;
774 if (remove) {
775 routerinfo_free(rl->routers[i]);
776 rl->routers[i] = rl->routers[--max];
777 --rl->n_routers;
778 --i;
782 return 0;
785 /* reads a single router entry from s.
786 * updates s so it points to after the router it just read.
787 * mallocs a new router and returns it if all goes well, else returns NULL.
789 routerinfo_t *router_get_entry_from_string(char**s) {
790 routerinfo_t *router = NULL;
791 char signed_digest[128];
792 char digest[128];
793 directory_token_t _tok;
794 directory_token_t *tok = &_tok;
795 struct tm published;
796 int t;
798 #define NEXT_TOKEN() \
799 do { if (router_get_next_token(s, tok)) { \
800 log_fn(LOG_WARN, "Error reading directory: %s", tok->val.error);\
801 goto err; \
802 } } while(0)
804 #define ARGS tok->val.cmd.args
806 if (router_get_router_hash(*s, digest) < 0) {
807 log_fn(LOG_WARN, "Couldn't compute router hash.");
808 return NULL;
811 NEXT_TOKEN();
813 if (tok->tp != K_ROUTER) {
814 router_release_token(tok);
815 log_fn(LOG_WARN,"Entry does not start with \"router\"");
816 return NULL;
819 router = tor_malloc_zero(sizeof(routerinfo_t));
820 router->onion_pkey = router->identity_pkey = router->link_pkey = NULL;
822 if (tok->val.cmd.n_args != 6) {
823 log_fn(LOG_WARN,"Wrong # of arguments to \"router\"");
824 goto err;
826 router->nickname = tor_strdup(ARGS[0]);
827 if (strlen(router->nickname) > MAX_NICKNAME_LEN) {
828 log_fn(LOG_WARN,"Router nickname too long.");
829 goto err;
831 if (strspn(router->nickname, LEGAL_NICKNAME_CHARACTERS) !=
832 strlen(router->nickname)) {
833 log_fn(LOG_WARN, "Router nickname contains illegal characters.");
834 goto err;
837 /* read router.address */
838 router->address = tor_strdup(ARGS[1]);
839 router->addr = 0;
841 /* Read router->or_port */
842 router->or_port = atoi(ARGS[2]);
843 if(!router->or_port) {
844 log_fn(LOG_WARN,"or_port unreadable or 0. Failing.");
845 goto err;
848 /* Router->socks_port */
849 router->socks_port = atoi(ARGS[3]);
851 /* Router->dir_port */
852 router->dir_port = atoi(ARGS[4]);
854 /* Router->bandwidth */
855 router->bandwidth = atoi(ARGS[5]);
856 if (!router->bandwidth) {
857 log_fn(LOG_WARN,"bandwidth unreadable or 0. Failing.");
858 goto err;
861 log_fn(LOG_DEBUG,"or_port %d, socks_port %d, dir_port %d, bandwidth %d.",
862 router->or_port, router->socks_port, router->dir_port, router->bandwidth);
864 /* XXX Later, require platform before published. */
865 NEXT_TOKEN();
866 if (tok->tp == K_PLATFORM) {
867 NEXT_TOKEN();
870 if (tok->tp != K_PUBLISHED) {
871 log_fn(LOG_WARN, "Missing published time"); goto err;
873 if (tok->val.cmd.n_args != 2) {
874 log_fn(LOG_WARN, "Wrong number of arguments to published"); goto err;
876 ARGS[1][-1] = ' '; /* Re-insert space. */
877 if (!strptime(ARGS[0], "%Y-%m-%d %H:%M:%S", &published)) {
878 log_fn(LOG_WARN, "Published time was unparseable"); goto err;
880 router->published_on = tor_timegm(&published);
882 NEXT_TOKEN();
883 if (tok->tp != K_ONION_KEY) {
884 log_fn(LOG_WARN, "Missing onion-key"); goto err;
886 NEXT_TOKEN();
887 if (tok->tp != _PUBLIC_KEY) {
888 log_fn(LOG_WARN, "Missing onion key"); goto err;
889 } /* XXX Check key length */
890 router->onion_pkey = tok->val.public_key;
892 NEXT_TOKEN();
893 if (tok->tp != K_LINK_KEY) {
894 log_fn(LOG_WARN, "Missing link-key"); goto err;
896 NEXT_TOKEN();
897 if (tok->tp != _PUBLIC_KEY) {
898 log_fn(LOG_WARN, "Missing link key"); goto err;
899 } /* XXX Check key length */
900 router->link_pkey = tok->val.public_key;
902 NEXT_TOKEN();
903 if (tok->tp != K_SIGNING_KEY) {
904 log_fn(LOG_WARN, "Missing signing-key"); goto err;
906 NEXT_TOKEN();
907 if (tok->tp != _PUBLIC_KEY) {
908 log_fn(LOG_WARN, "Missing signing key"); goto err;
910 router->identity_pkey = tok->val.public_key;
912 NEXT_TOKEN();
913 while (tok->tp == K_ACCEPT || tok->tp == K_REJECT) {
914 router_add_exit_policy(router, tok);
915 NEXT_TOKEN();
918 if (tok->tp != K_ROUTER_SIGNATURE) {
919 log_fn(LOG_WARN,"Missing router signature");
920 goto err;
922 NEXT_TOKEN();
923 if (tok->tp != _SIGNATURE) {
924 log_fn(LOG_WARN,"Missing router signature");
925 goto err;
927 assert (router->identity_pkey);
929 if ((t=crypto_pk_public_checksig(router->identity_pkey, tok->val.signature,
930 128, signed_digest)) != 20) {
931 log_fn(LOG_WARN, "Invalid signature %d",t);
932 goto err;
934 if (memcmp(digest, signed_digest, 20)) {
935 log_fn(LOG_WARN, "Mismatched signature");
936 goto err;
939 router_release_token(tok); /* free the signature */
940 return router;
942 err:
943 router_release_token(tok);
944 routerinfo_free(router);
945 return NULL;
946 #undef ARGS
947 #undef NEXT_TOKEN
950 void router_add_exit_policy_from_config(routerinfo_t *router) {
951 char *s = options.ExitPolicy, *e;
952 int last=0;
953 char line[1024];
955 if(!s) {
956 log_fn(LOG_INFO,"No exit policy configured. Ok.");
957 return; /* nothing to see here */
959 if(!*s) {
960 log_fn(LOG_INFO,"Exit policy is empty. Ok.");
961 return; /* nothing to see here */
964 for(;;) {
965 e = strchr(s,',');
966 if(!e) {
967 last = 1;
968 strncpy(line,s,1023);
969 } else {
970 memcpy(line,s, ((e-s)<1023)?(e-s):1023);
971 line[e-s] = 0;
973 line[1023]=0;
974 log_fn(LOG_DEBUG,"Adding new entry '%s'",line);
975 if(router_add_exit_policy_from_string(router,line) < 0)
976 log_fn(LOG_WARN,"Malformed exit policy %s; skipping.", line);
977 if(last)
978 return;
979 s = e+1;
983 static int
984 router_add_exit_policy_from_string(routerinfo_t *router,
985 char *s)
987 directory_token_t tok;
988 char *tmp, *cp;
989 int r;
990 int len, idx;
992 len = strlen(s);
993 tmp = cp = tor_malloc(len+2);
994 for (idx = 0; idx < len; ++idx) {
995 tmp[idx] = tolower(s[idx]);
997 tmp[len]='\n';
998 tmp[len+1]='\0';
999 if (router_get_next_token(&cp, &tok)) {
1000 log_fn(LOG_WARN, "Error reading exit policy: %s", tok.val.error);
1001 free(tmp);
1002 return -1;
1004 if (tok.tp != K_ACCEPT && tok.tp != K_REJECT) {
1005 log_fn(LOG_WARN, "Expected 'accept' or 'reject'.");
1006 free(tmp);
1007 return -1;
1009 r = router_add_exit_policy(router, &tok);
1010 free(tmp);
1011 return r;
1014 static int router_add_exit_policy(routerinfo_t *router,
1015 directory_token_t *tok) {
1016 struct exit_policy_t *tmpe, *newe;
1017 struct in_addr in;
1018 char *arg, *address, *mask, *port, *endptr;
1019 int bits;
1021 if (tok->val.cmd.n_args != 1)
1022 return -1;
1023 arg = tok->val.cmd.args[0];
1025 newe = tor_malloc_zero(sizeof(struct exit_policy_t));
1027 newe->string = tor_malloc(8+strlen(arg));
1028 if (tok->tp == K_REJECT) {
1029 strcpy(newe->string, "reject ");
1030 newe->policy_type = EXIT_POLICY_REJECT;
1031 } else {
1032 assert(tok->tp == K_ACCEPT);
1033 strcpy(newe->string, "accept ");
1034 newe->policy_type = EXIT_POLICY_ACCEPT;
1036 strcat(newe->string, arg);
1038 address = arg;
1039 mask = strchr(arg,'/');
1040 port = strchr(mask?mask:arg,':');
1041 if(!port)
1042 goto policy_read_failed;
1043 if (mask)
1044 *mask++ = 0;
1045 *port++ = 0;
1047 if (strcmp(address, "*") == 0) {
1048 newe->addr = 0;
1049 } else if (inet_aton(address, &in) != 0) {
1050 newe->addr = ntohl(in.s_addr);
1051 } else {
1052 log_fn(LOG_WARN, "Malformed IP %s in exit policy; rejecting.",
1053 address);
1054 goto policy_read_failed;
1056 if (!mask) {
1057 if (strcmp(address, "*") == 0)
1058 newe->msk = 0;
1059 else
1060 newe->msk = 0xFFFFFFFFu;
1061 } else {
1062 endptr = NULL;
1063 bits = (int) strtol(mask, &endptr, 10);
1064 if (!*endptr) {
1065 /* strtol handled the whole mask. */
1066 newe->msk = ~((1<<(32-bits))-1);
1067 } else if (inet_aton(mask, &in) != 0) {
1068 newe->msk = ntohl(in.s_addr);
1069 } else {
1070 log_fn(LOG_WARN, "Malformed mask %s on exit policy; rejecting.",
1071 mask);
1072 goto policy_read_failed;
1075 if (strcmp(port, "*") == 0) {
1076 newe->prt = 0;
1077 } else {
1078 endptr = NULL;
1079 newe->prt = strtol(port, &endptr, 10);
1080 if (*endptr) {
1081 log_fn(LOG_WARN, "Malformed port %s on exit policy; rejecting.",
1082 port);
1083 goto policy_read_failed;
1087 in.s_addr = htonl(newe->addr);
1088 address = tor_strdup(inet_ntoa(in));
1089 in.s_addr = htonl(newe->msk);
1090 log_fn(LOG_DEBUG,"%s %s/%s:%d",
1091 newe->policy_type == EXIT_POLICY_REJECT ? "reject" : "accept",
1092 address, inet_ntoa(in), newe->prt);
1093 tor_free(address);
1095 /* now link newe onto the end of exit_policy */
1097 if(!router->exit_policy) {
1098 router->exit_policy = newe;
1099 return 0;
1102 for(tmpe=router->exit_policy; tmpe->next; tmpe=tmpe->next) ;
1103 tmpe->next = newe;
1105 return 0;
1107 policy_read_failed:
1108 assert(newe->string);
1109 log_fn(LOG_WARN,"Couldn't parse line '%s'. Dropping", newe->string);
1110 tor_free(newe->string);
1111 free(newe);
1112 return -1;
1115 /* Addr is 0 for "IP unknown".
1117 * Returns -1 for 'rejected', 0 for accepted, 1 for 'maybe' (since IP is
1118 * unknown.
1120 int router_supports_exit_address(uint32_t addr, uint16_t port,
1121 routerinfo_t *router)
1123 return router_compare_addr_to_exit_policy(addr, port, router->exit_policy);
1126 /* Addr is 0 for "IP unknown".
1128 * Returns -1 for 'rejected', 0 for accepted, 1 for 'maybe' (since IP is
1129 * unknown.
1131 int router_compare_addr_to_exit_policy(uint32_t addr, uint16_t port,
1132 struct exit_policy_t *policy)
1134 int maybe_reject = 0;
1135 int match = 0;
1136 struct in_addr in;
1137 struct exit_policy_t *tmpe;
1139 for(tmpe=policy; tmpe; tmpe=tmpe->next) {
1140 log_fn(LOG_DEBUG,"Considering exit policy %s", tmpe->string);
1141 if (!addr) {
1142 /* Address is unknown. */
1143 if (tmpe->msk == 0 && (!tmpe || port == tmpe->prt)) {
1144 /* The exit policy is accept/reject *:port */
1145 match = 1;
1146 } else if ((!tmpe->prt || port == tmpe->prt) &&
1147 tmpe->policy_type == EXIT_POLICY_REJECT) {
1148 /* The exit policy is reject ???:port */
1149 maybe_reject = 1;
1151 } else {
1152 /* Address is known */
1153 if ( (addr & tmpe->msk) == (tmpe->addr & tmpe->msk) &&
1154 (!tmpe->prt || port == tmpe->prt) ) {
1155 /* Exact match for the policy */
1156 match = 1;
1159 if (match) {
1160 in.s_addr = htonl(addr);
1161 log_fn(LOG_INFO,"Address %s:%d matches exit policy '%s'",
1162 inet_ntoa(in), port, tmpe->string);
1163 if(tmpe->policy_type == EXIT_POLICY_ACCEPT)
1164 return 0;
1165 else
1166 return -1;
1169 if (maybe_reject)
1170 return 1;
1171 else
1172 return 0; /* accept all by default. */
1175 /* Return 0 if my exit policy says to allow connection to conn.
1176 * Else return -1.
1178 int router_compare_to_my_exit_policy(connection_t *conn) {
1179 assert(desc_routerinfo);
1180 assert(conn->addr); /* make sure it's resolved to something. this
1181 way we can't get a 'maybe' below. */
1183 if (router_compare_addr_to_exit_policy(conn->addr, conn->port,
1184 desc_routerinfo->exit_policy) == 0)
1185 return 0;
1186 else
1187 return -1;
1190 /* return 1 if all running routers will reject addr:port, return 0 if
1191 any might accept it. */
1192 int router_exit_policy_all_routers_reject(uint32_t addr, uint16_t port) {
1193 int i;
1194 routerinfo_t *router;
1196 for (i=0;i<routerlist->n_routers;i++) {
1197 router = routerlist->routers[i];
1198 if (router->is_running && router_compare_addr_to_exit_policy(addr,
1199 port, router->exit_policy) >= 0)
1200 return 0; /* this one could be ok. good enough. */
1202 return 1; /* all will reject. */
1205 int router_exit_policy_rejects_all(routerinfo_t *router) {
1206 if (router_compare_addr_to_exit_policy(0, 0, router->exit_policy) < 0)
1207 return 1; /* yes, rejects all */
1208 else
1209 return 0; /* no, might accept some */
1212 const char *router_get_my_descriptor(void) {
1213 if (!desc_routerinfo) {
1214 if (router_rebuild_descriptor())
1215 return NULL;
1217 log_fn(LOG_DEBUG,"my desc is '%s'",descriptor);
1218 return descriptor;
1221 int router_rebuild_descriptor(void) {
1222 routerinfo_t *ri;
1223 char localhostname[256];
1224 char *address = options.Address;
1226 if(!address) { /* if not specified in config, we find a default */
1227 if(gethostname(localhostname,sizeof(localhostname)) < 0) {
1228 log_fn(LOG_WARN,"Error obtaining local hostname");
1229 return -1;
1231 address = localhostname;
1232 if(!strchr(address,'.')) {
1233 log_fn(LOG_WARN,"fqdn '%s' has only one element. Misconfigured machine?",address);
1234 log_fn(LOG_WARN,"Try setting the Address line in your config file.");
1235 return -1;
1238 ri = tor_malloc(sizeof(routerinfo_t));
1239 ri->address = tor_strdup(address);
1240 ri->nickname = tor_strdup(options.Nickname);
1241 /* No need to set addr. */
1242 ri->or_port = options.ORPort;
1243 ri->socks_port = options.SocksPort;
1244 ri->dir_port = options.DirPort;
1245 ri->published_on = time(NULL);
1246 ri->onion_pkey = crypto_pk_dup_key(get_onion_key());
1247 ri->link_pkey = crypto_pk_dup_key(get_link_key());
1248 ri->identity_pkey = crypto_pk_dup_key(get_identity_key());
1249 ri->bandwidth = options.TotalBandwidth;
1250 ri->exit_policy = NULL; /* zero it out first */
1251 router_add_exit_policy_from_config(ri);
1252 if (desc_routerinfo)
1253 routerinfo_free(desc_routerinfo);
1254 desc_routerinfo = ri;
1255 if (router_dump_router_to_string(descriptor, 8192, ri, get_identity_key())<0) {
1256 log_fn(LOG_WARN, "Couldn't dump router to string.");
1257 return -1;
1259 return 0;
1262 static void get_platform_str(char *platform, int len)
1264 snprintf(platform, len-1, "Tor %s on %s", VERSION, get_uname());
1265 platform[len-1] = '\0';
1266 return;
1269 /* XXX need to audit this thing and count fenceposts. maybe
1270 * refactor so we don't have to keep asking if we're
1271 * near the end of maxlen?
1273 #define DEBUG_ROUTER_DUMP_ROUTER_TO_STRING
1274 int router_dump_router_to_string(char *s, int maxlen, routerinfo_t *router,
1275 crypto_pk_env_t *ident_key) {
1276 char *onion_pkey;
1277 char *link_pkey;
1278 char *identity_pkey;
1279 struct in_addr in;
1280 char platform[256];
1281 char digest[20];
1282 char signature[128];
1283 char published[32];
1284 int onion_pkeylen, link_pkeylen, identity_pkeylen;
1285 int written;
1286 int result=0;
1287 struct exit_policy_t *tmpe;
1288 #ifdef DEBUG_ROUTER_DUMP_ROUTER_TO_STRING
1289 char *s_tmp, *s_dup;
1290 routerinfo_t *ri_tmp;
1291 #endif
1293 get_platform_str(platform, sizeof(platform));
1295 if (crypto_pk_cmp_keys(ident_key, router->identity_pkey)) {
1296 log_fn(LOG_WARN,"Tried to sign a router with a private key that didn't match router's public key!");
1297 return -1;
1300 if(crypto_pk_write_public_key_to_string(router->onion_pkey,
1301 &onion_pkey,&onion_pkeylen)<0) {
1302 log_fn(LOG_WARN,"write onion_pkey to string failed!");
1303 return -1;
1306 if(crypto_pk_write_public_key_to_string(router->identity_pkey,
1307 &identity_pkey,&identity_pkeylen)<0) {
1308 log_fn(LOG_WARN,"write identity_pkey to string failed!");
1309 return -1;
1312 if(crypto_pk_write_public_key_to_string(router->link_pkey,
1313 &link_pkey,&link_pkeylen)<0) {
1314 log_fn(LOG_WARN,"write link_pkey to string failed!");
1315 return -1;
1317 strftime(published, 32, "%Y-%m-%d %H:%M:%S", gmtime(&router->published_on));
1319 result = snprintf(s, maxlen,
1320 "router %s %s %d %d %d %d\n"
1321 "platform %s\n"
1322 "published %s\n"
1323 "onion-key\n%s"
1324 "link-key\n%s"
1325 "signing-key\n%s",
1326 router->nickname,
1327 router->address,
1328 router->or_port,
1329 router->socks_port,
1330 router->dir_port,
1331 router->bandwidth,
1332 platform,
1333 published,
1334 onion_pkey, link_pkey, identity_pkey);
1336 free(onion_pkey);
1337 free(link_pkey);
1338 free(identity_pkey);
1340 if(result < 0 || result >= maxlen) {
1341 /* apparently different glibcs do different things on snprintf error.. so check both */
1342 return -1;
1344 written = result;
1346 for(tmpe=router->exit_policy; tmpe; tmpe=tmpe->next) {
1347 in.s_addr = htonl(tmpe->addr);
1348 result = snprintf(s+written, maxlen-written, "%s %s",
1349 tmpe->policy_type == EXIT_POLICY_ACCEPT ? "accept" : "reject",
1350 tmpe->msk == 0 ? "*" : inet_ntoa(in));
1351 if(result < 0 || result+written > maxlen) {
1352 /* apparently different glibcs do different things on snprintf error.. so check both */
1353 return -1;
1355 written += result;
1356 if (tmpe->msk != 0xFFFFFFFFu && tmpe->msk != 0) {
1357 in.s_addr = htonl(tmpe->msk);
1358 result = snprintf(s+written, maxlen-written, "/%s", inet_ntoa(in));
1359 if (result<0 || result+written > maxlen)
1360 return -1;
1361 written += result;
1363 if (tmpe->prt) {
1364 result = snprintf(s+written, maxlen-written, ":%d\n", tmpe->prt);
1365 if (result<0 || result+written > maxlen)
1366 return -1;
1367 written += result;
1368 } else {
1369 if (written > maxlen-4)
1370 return -1;
1371 strcat(s+written, ":*\n");
1372 written += 3;
1374 } /* end for */
1375 if (written > maxlen-256) /* Not enough room for signature. */
1376 return -1;
1378 strcat(s+written, "router-signature\n");
1379 written += strlen(s+written);
1380 s[written] = '\0';
1381 if (router_get_router_hash(s, digest) < 0)
1382 return -1;
1384 if (crypto_pk_private_sign(ident_key, digest, 20, signature) < 0) {
1385 log_fn(LOG_WARN, "Error signing digest");
1386 return -1;
1388 strcat(s+written, "-----BEGIN SIGNATURE-----\n");
1389 written += strlen(s+written);
1390 if (base64_encode(s+written, maxlen-written, signature, 128) < 0) {
1391 log_fn(LOG_WARN, "Couldn't base64-encode signature");
1392 return -1;
1394 written += strlen(s+written);
1395 strcat(s+written, "-----END SIGNATURE-----\n");
1396 written += strlen(s+written);
1398 if (written > maxlen-2)
1399 return -1;
1400 /* include a last '\n' */
1401 s[written] = '\n';
1402 s[written+1] = 0;
1404 #ifdef DEBUG_ROUTER_DUMP_ROUTER_TO_STRING
1405 s_tmp = s_dup = tor_strdup(s);
1406 ri_tmp = router_get_entry_from_string(&s_tmp);
1407 if (!ri_tmp) {
1408 log_fn(LOG_ERR, "We just generated a router descriptor we can't parse: <<%s>>",
1410 return -1;
1412 free(s_dup);
1413 routerinfo_free(ri_tmp);
1414 #endif
1416 return written+1;
1420 Local Variables:
1421 mode:c
1422 indent-tabs-mode:nil
1423 c-basic-offset:2
1424 End: