start tracking a rare bug: package_raw_inbuf gets called with package_window 0
[tor.git] / src / or / routers.c
blobfb2598561d096077e57c3ced7805a311e3f1233d
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 directory_t *directory = 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 void routerlist_free(routerinfo_t *list);
32 static int router_add_exit_policy_from_string(routerinfo_t *router, char *s);
33 static int router_add_exit_policy(routerinfo_t *router,
34 directory_token_t *tok);
35 static int router_resolve_directory(directory_t *dir);
37 /****************************************************************************/
39 void router_retry_connections(void) {
40 int i;
41 routerinfo_t *router;
43 for (i=0;i<directory->n_routers;i++) {
44 router = directory->routers[i];
45 if(!connection_exact_get_by_addr_port(router->addr,router->or_port)) { /* 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 the first running router with a positive dir_port */
54 int i;
55 routerinfo_t *router, *dirserver=NULL;
57 if(!directory)
58 return NULL;
60 for(i=0;i<directory->n_routers;i++) {
61 router = directory->routers[i];
62 if(router->dir_port > 0 && router->is_running)
63 return router;
66 log_fn(LOG_INFO,"No dirservers are reachable. Trying them all again.");
67 /* no running dir servers found? go through and mark them all as up,
68 * and we'll cycle through the list again. */
69 for(i=0;i<directory->n_routers;i++) {
70 router = directory->routers[i];
71 if(router->dir_port > 0) {
72 router->is_running = 1;
73 dirserver = router;
77 return dirserver;
80 void router_upload_desc_to_dirservers(void) {
81 int i;
82 routerinfo_t *router;
84 if(!directory)
85 return;
87 if (!router_get_my_descriptor()) {
88 log_fn(LOG_WARN, "No descriptor; skipping upload");
89 return;
92 for(i=0;i<directory->n_routers;i++) {
93 router = directory->routers[i];
94 if(router->dir_port > 0)
95 directory_initiate_command(router, DIR_CONN_STATE_CONNECTING_UPLOAD);
99 routerinfo_t *router_get_by_addr_port(uint32_t addr, uint16_t port) {
100 int i;
101 routerinfo_t *router;
103 assert(directory);
105 for(i=0;i<directory->n_routers;i++) {
106 router = directory->routers[i];
107 if ((router->addr == addr) && (router->or_port == port))
108 return router;
110 return NULL;
113 routerinfo_t *router_get_by_link_pk(crypto_pk_env_t *pk)
115 int i;
116 routerinfo_t *router;
118 assert(directory);
120 for(i=0;i<directory->n_routers;i++) {
121 router = directory->routers[i];
122 if (0 == crypto_pk_cmp_keys(router->link_pkey, pk))
123 return router;
125 return NULL;
128 routerinfo_t *router_get_by_nickname(char *nickname)
130 int i;
131 routerinfo_t *router;
133 assert(directory);
135 for(i=0;i<directory->n_routers;i++) {
136 router = directory->routers[i];
137 if (0 == strcmp(router->nickname, nickname))
138 return router;
140 return NULL;
143 void router_get_directory(directory_t **pdirectory) {
144 *pdirectory = directory;
147 /* delete a router from memory */
148 void routerinfo_free(routerinfo_t *router)
150 struct exit_policy_t *e;
152 if (!router)
153 return;
155 tor_free(router->address);
156 tor_free(router->nickname);
157 if (router->onion_pkey)
158 crypto_free_pk_env(router->onion_pkey);
159 if (router->link_pkey)
160 crypto_free_pk_env(router->link_pkey);
161 if (router->identity_pkey)
162 crypto_free_pk_env(router->identity_pkey);
163 while (router->exit_policy) {
164 e = router->exit_policy;
165 router->exit_policy = e->next;
166 tor_free(e->string);
167 free(e);
169 free(router);
172 void directory_free(directory_t *dir)
174 int i;
175 for (i = 0; i < dir->n_routers; ++i)
176 routerinfo_free(dir->routers[i]);
177 tor_free(dir->routers);
178 tor_free(dir->software_versions);
179 free(dir);
182 void router_mark_as_down(char *nickname) {
183 routerinfo_t *router = router_get_by_nickname(nickname);
184 if(!router) /* we don't seem to know about him in the first place */
185 return;
186 log_fn(LOG_DEBUG,"Marking %s as down.",router->nickname);
187 router->is_running = 0;
190 /* load the router list */
191 int router_get_list_from_file(char *routerfile)
193 char *string;
195 string = read_file_to_str(routerfile);
196 if(!string) {
197 log_fn(LOG_WARN,"Failed to load routerfile %s.",routerfile);
198 return -1;
201 if(router_get_list_from_string(string) < 0) {
202 log_fn(LOG_WARN,"The routerfile itself was corrupt.");
203 free(string);
204 return -1;
207 free(string);
208 return 0;
212 typedef enum {
213 K_ACCEPT,
214 K_DIRECTORY_SIGNATURE,
215 K_RECOMMENDED_SOFTWARE,
216 K_REJECT,
217 K_ROUTER,
218 K_SIGNED_DIRECTORY,
219 K_SIGNING_KEY,
220 K_ONION_KEY,
221 K_LINK_KEY,
222 K_ROUTER_SIGNATURE,
223 K_PUBLISHED,
224 K_RUNNING_ROUTERS,
225 K_PLATFORM,
226 _SIGNATURE,
227 _PUBLIC_KEY,
228 _ERR,
229 _EOF
230 } directory_keyword;
232 struct token_table_ent { char *t; int v; };
234 static struct token_table_ent token_table[] = {
235 { "accept", K_ACCEPT },
236 { "directory-signature", K_DIRECTORY_SIGNATURE },
237 { "reject", K_REJECT },
238 { "router", K_ROUTER },
239 { "recommended-software", K_RECOMMENDED_SOFTWARE },
240 { "signed-directory", K_SIGNED_DIRECTORY },
241 { "signing-key", K_SIGNING_KEY },
242 { "onion-key", K_ONION_KEY },
243 { "link-key", K_LINK_KEY },
244 { "router-signature", K_ROUTER_SIGNATURE },
245 { "published", K_PUBLISHED },
246 { "running-routers", K_RUNNING_ROUTERS },
247 { "platform", K_PLATFORM },
248 { NULL, -1 }
251 #define MAX_ARGS 1024
252 struct directory_token {
253 directory_keyword tp;
254 union {
255 struct {
256 char *args[MAX_ARGS+1];
257 int n_args;
258 } cmd;
259 char *signature;
260 char *error;
261 crypto_pk_env_t *public_key;
262 } val;
265 /* Free any malloced resources allocated for a token. Don't call this if
266 you inherit the reference to those resources.
268 static void
269 router_release_token(directory_token_t *tok)
271 switch (tok->tp)
273 case _SIGNATURE:
274 free(tok->val.signature);
275 break;
276 case _PUBLIC_KEY:
277 crypto_free_pk_env(tok->val.public_key);
278 break;
279 default:
280 break;
284 static int
285 _router_get_next_token(char **s, directory_token_t *tok) {
286 char *next;
287 crypto_pk_env_t *pkey = NULL;
288 char *signature = NULL;
289 int i, done;
291 tok->tp = _ERR;
292 tok->val.error = "";
294 *s = eat_whitespace(*s);
295 if (!**s) {
296 tok->tp = _EOF;
297 return 0;
298 } else if (**s == '-') {
299 next = strchr(*s, '\n');
300 if (! next) { tok->val.error = "No newline at EOF"; return -1; }
301 ++next;
302 if (! strncmp(*s, OR_PUBLICKEY_BEGIN_TAG, next-*s)) {
303 next = strstr(*s, OR_PUBLICKEY_END_TAG);
304 if (!next) { tok->val.error = "No public key end tag found"; return -1; }
305 next = strchr(next, '\n'); /* Part of OR_PUBLICKEY_END_TAG; can't fail.*/
306 ++next;
307 if (!(pkey = crypto_new_pk_env(CRYPTO_PK_RSA)))
308 return -1;
309 if (crypto_pk_read_public_key_from_string(pkey, *s, next-*s)) {
310 crypto_free_pk_env(pkey);
311 tok->val.error = "Couldn't parse public key.";
312 return -1;
314 tok->tp = _PUBLIC_KEY;
315 tok->val.public_key = pkey;
316 *s = next;
317 return 0;
318 } else if (! strncmp(*s, OR_SIGNATURE_BEGIN_TAG, next-*s)) {
319 /* Advance past newline; can't fail. */
320 *s = strchr(*s, '\n');
321 ++*s;
322 /* Find end of base64'd data */
323 next = strstr(*s, OR_SIGNATURE_END_TAG);
324 if (!next) { tok->val.error = "No signature end tag found"; return -1; }
326 signature = tor_malloc(256);
327 i = base64_decode(signature, 256, *s, next-*s);
328 if (i<0) {
329 free(signature);
330 tok->val.error = "Error decoding signature."; return -1;
331 } else if (i != 128) {
332 free(signature);
333 tok->val.error = "Bad length on decoded signature."; return -1;
335 tok->tp = _SIGNATURE;
336 tok->val.signature = signature;
338 next = strchr(next, '\n'); /* Part of OR_SIGNATURE_END_TAG; can't fail.*/
339 *s = next+1;
340 return 0;
341 } else {
342 tok->val.error = "Unrecognized begin line"; return -1;
344 } else {
345 next = find_whitespace(*s);
346 if (!next) {
347 tok->val.error = "Unexpected EOF"; return -1;
349 for (i = 0 ; token_table[i].t ; ++i) {
350 if (!strncmp(token_table[i].t, *s, next-*s)) {
351 tok->tp = token_table[i].v;
352 i = 0;
353 done = (*next == '\n');
354 *s = eat_whitespace_no_nl(next);
355 while (**s != '\n' && i <= MAX_ARGS && !done) {
356 next = find_whitespace(*s);
357 if (*next == '\n')
358 done = 1;
359 *next = 0;
360 tok->val.cmd.args[i++] = *s;
361 *s = eat_whitespace_no_nl(next+1);
363 tok->val.cmd.n_args = i;
364 if (i > MAX_ARGS) {
365 tok->tp = _ERR;
366 tok->val.error = "Too many arguments"; return -1;
368 return 0;
371 tok->val.error = "Unrecognized command"; return -1;
375 #ifdef DEBUG_ROUTER_TOKENS
376 static void
377 router_dump_token(directory_token_t *tok) {
378 int i;
379 switch(tok->tp)
381 case _SIGNATURE:
382 puts("(signature)");
383 return;
384 case _PUBLIC_KEY:
385 puts("(public key)");
386 return;
387 case _ERR:
388 printf("(Error: %s\n)", tok->val.error);
389 return;
390 case _EOF:
391 puts("EOF");
392 return;
393 case K_ACCEPT: printf("Accept"); break;
394 case K_DIRECTORY_SIGNATURE: printf("Directory-Signature"); break;
395 case K_REJECT: printf("Reject"); break;
396 case K_RECOMMENDED_SOFTWARE: printf("Server-Software"); break;
397 case K_ROUTER: printf("Router"); break;
398 case K_SIGNED_DIRECTORY: printf("Signed-Directory"); break;
399 case K_SIGNING_KEY: printf("Signing-Key"); break;
400 case K_ONION_KEY: printf("Onion-key"); break;
401 case K_LINK_KEY: printf("Link-key"); break;
402 case K_ROUTER_SIGNATURE: printf("Router-signature"); break;
403 case K_PUBLISHED: printf("Published"); break;
404 case K_RUNNING_ROUTERS: printf("Running-routers"); break;
405 case K_PLATFORM: printf("Platform"); break;
406 default:
407 printf("?????? %d\n", tok->tp); return;
409 for (i = 0; i < tok->val.cmd.n_args; ++i) {
410 printf(" \"%s\"", tok->val.cmd.args[i]);
412 printf("\n");
413 return;
415 static int
416 router_get_next_token(char **s, directory_token_t *tok) {
417 int i;
418 i = _router_get_next_token(s, tok);
419 router_dump_token(tok);
420 return i;
422 #else
423 #define router_get_next_token _router_get_next_token
424 #endif
426 int router_get_list_from_string(char *s)
428 if (router_get_list_from_string_impl(&s, &directory, -1, NULL)) {
429 log(LOG_WARN, "Error parsing router file");
430 return -1;
432 if (router_resolve_directory(directory)) {
433 log(LOG_WARN, "Error resolving directory");
434 return -1;
436 return 0;
439 static int router_get_hash_impl(char *s, char *digest, const char *start_str,
440 const char *end_str)
442 char *start, *end;
443 start = strstr(s, start_str);
444 if (!start) {
445 log_fn(LOG_WARN,"couldn't find \"%s\"",start_str);
446 return -1;
448 end = strstr(start+strlen(start_str), end_str);
449 if (!end) {
450 log_fn(LOG_WARN,"couldn't find \"%s\"",end_str);
451 return -1;
453 end = strchr(end, '\n');
454 if (!end) {
455 log_fn(LOG_WARN,"couldn't find EOL");
456 return -1;
458 ++end;
460 if (crypto_SHA_digest(start, end-start, digest)) {
461 log_fn(LOG_WARN,"couldn't compute digest");
462 return -1;
465 return 0;
468 int router_get_dir_hash(char *s, char *digest)
470 return router_get_hash_impl(s,digest,
471 "signed-directory","directory-signature");
473 int router_get_router_hash(char *s, char *digest)
475 return router_get_hash_impl(s,digest,
476 "router ","router-signature");
479 /* return 0 if myversion is in start. Else return -1. */
480 int compare_recommended_versions(char *myversion, char *start) {
481 int len_myversion = strlen(myversion);
482 char *comma;
483 char *end = start + strlen(start);
485 log_fn(LOG_DEBUG,"checking '%s' in '%s'.", myversion, start);
487 for(;;) {
488 comma = strchr(start, ',');
489 if( ((comma ? comma : end) - start == len_myversion) &&
490 !strncmp(start, myversion, len_myversion)) /* only do strncmp if the length matches */
491 return 0; /* success, it's there */
492 if(!comma)
493 return -1; /* nope */
494 start = comma+1;
498 int router_get_dir_from_string(char *s, crypto_pk_env_t *pkey)
500 if (router_get_dir_from_string_impl(s, &directory, pkey)) {
501 log_fn(LOG_WARN, "Couldn't parse directory.");
502 return -1;
504 if (router_resolve_directory(directory)) {
505 log_fn(LOG_WARN, "Error resolving directory");
506 return -1;
508 if (compare_recommended_versions(VERSION, directory->software_versions) < 0) {
509 log(options.IgnoreVersion ? LOG_WARN : LOG_ERR,
510 "You are running Tor version %s, which is not recommended.\n"
511 "Please upgrade to one of %s.",
512 VERSION, directory->software_versions);
513 if(options.IgnoreVersion) {
514 log(LOG_WARN, "IgnoreVersion is set. If it breaks, we told you so.");
515 } else {
516 fflush(0);
517 exit(0);
521 return 0;
524 int router_get_dir_from_string_impl(char *s, directory_t **dest,
525 crypto_pk_env_t *pkey)
527 directory_token_t tok;
528 char digest[20];
529 char signed_digest[128];
530 directory_t *new_dir = NULL;
531 char *versions;
532 struct tm published;
533 time_t published_on;
534 const char *good_nickname_lst[1024];
535 int n_good_nicknames;
537 #define NEXT_TOK() \
538 do { \
539 if (router_get_next_token(&s, &tok)) { \
540 log_fn(LOG_WARN, "Error reading directory: %s", tok.val.error);\
541 return -1; \
542 } } while (0)
543 #define TOK_IS(type,name) \
544 do { \
545 if (tok.tp != type) { \
546 router_release_token(&tok); \
547 log_fn(LOG_WARN, "Error reading directory: expected %s", name);\
548 return -1; \
549 } } while(0)
551 if (router_get_dir_hash(s, digest)) {
552 log_fn(LOG_WARN, "Unable to compute digest of directory");
553 goto err;
555 log(LOG_DEBUG,"Received directory hashes to %02x:%02x:%02x:%02x",
556 ((int)digest[0])&0xff,((int)digest[1])&0xff,
557 ((int)digest[2])&0xff,((int)digest[3])&0xff);
559 NEXT_TOK();
560 TOK_IS(K_SIGNED_DIRECTORY, "signed-directory");
562 NEXT_TOK();
563 TOK_IS(K_PUBLISHED, "published");
564 if (tok.val.cmd.n_args != 2) {
565 log_fn(LOG_WARN, "Invalid published line");
566 goto err;
568 tok.val.cmd.args[1][-1] = ' ';
569 if (!strptime(tok.val.cmd.args[0], "%Y-%m-%d %H:%M:%S", &published)) {
570 log_fn(LOG_WARN, "Published time was unparseable"); goto err;
572 published_on = tor_timegm(&published);
574 NEXT_TOK();
575 TOK_IS(K_RECOMMENDED_SOFTWARE, "recommended-software");
576 if (tok.val.cmd.n_args != 1) {
577 log_fn(LOG_WARN, "Invalid recommended-software line");
578 goto err;
580 versions = tor_strdup(tok.val.cmd.args[0]);
582 NEXT_TOK();
583 TOK_IS(K_RUNNING_ROUTERS, "running-routers");
584 n_good_nicknames = tok.val.cmd.n_args;
585 memcpy(good_nickname_lst, tok.val.cmd.args, n_good_nicknames*sizeof(char *));
587 if (router_get_list_from_string_impl(&s, &new_dir,
588 n_good_nicknames, good_nickname_lst)) {
589 log_fn(LOG_WARN, "Error reading routers from directory");
590 goto err;
592 new_dir->software_versions = versions;
593 new_dir->published_on = published_on;
595 NEXT_TOK();
596 TOK_IS(K_DIRECTORY_SIGNATURE, "directory-signature");
597 NEXT_TOK();
598 TOK_IS(_SIGNATURE, "signature");
599 if (pkey) {
600 if (crypto_pk_public_checksig(pkey, tok.val.signature, 128, signed_digest)
601 != 20) {
602 log_fn(LOG_WARN, "Error reading directory: invalid signature.");
603 free(tok.val.signature);
604 goto err;
606 log(LOG_DEBUG,"Signed directory hash starts %02x:%02x:%02x:%02x",
607 ((int)signed_digest[0])&0xff,((int)signed_digest[1])&0xff,
608 ((int)signed_digest[2])&0xff,((int)signed_digest[3])&0xff);
609 if (memcmp(digest, signed_digest, 20)) {
610 log_fn(LOG_WARN, "Error reading directory: signature does not match.");
611 free(tok.val.signature);
612 goto err;
615 free(tok.val.signature);
617 NEXT_TOK();
618 TOK_IS(_EOF, "end of directory");
620 if (*dest)
621 directory_free(*dest);
622 *dest = new_dir;
624 return 0;
626 err:
627 if (new_dir)
628 directory_free(new_dir);
629 return -1;
630 #undef NEXT_TOK
631 #undef TOK_IS
634 int router_get_list_from_string_impl(char **s, directory_t **dest,
635 int n_good_nicknames,
636 const char **good_nickname_lst)
638 routerinfo_t *router;
639 routerinfo_t **rarray;
640 int rarray_len = 0;
641 int i;
643 assert(s && *s);
645 rarray = (routerinfo_t **)tor_malloc((sizeof(routerinfo_t *))*MAX_ROUTERS_IN_DIR);
647 while (1) {
648 *s = eat_whitespace(*s);
649 if (strncmp(*s, "router ", 7)!=0)
650 break;
651 router = router_get_entry_from_string(s);
652 if (!router) {
653 log_fn(LOG_WARN, "Error reading router");
654 for(i=0;i<rarray_len;i++)
655 routerinfo_free(rarray[i]);
656 free(rarray);
657 return -1;
659 if (rarray_len >= MAX_ROUTERS_IN_DIR) {
660 log_fn(LOG_WARN, "too many routers");
661 routerinfo_free(router);
662 continue;
664 if (n_good_nicknames>=0) {
665 router->is_running = 0;
666 for (i = 0; i < n_good_nicknames; ++i) {
667 if (0==strcasecmp(good_nickname_lst[i], router->nickname)) {
668 router->is_running = 1;
669 break;
672 } else {
673 router->is_running = 1; /* start out assuming all dirservers are up */
675 rarray[rarray_len++] = router;
676 log_fn(LOG_DEBUG,"just added router #%d.",rarray_len);
679 if (*dest)
680 directory_free(*dest);
681 *dest = (directory_t *)tor_malloc(sizeof(directory_t));
682 (*dest)->routers = rarray;
683 (*dest)->n_routers = rarray_len;
684 (*dest)->software_versions = NULL;
685 return 0;
688 static int
689 router_resolve(routerinfo_t *router)
691 struct hostent *rent;
693 rent = (struct hostent *)gethostbyname(router->address);
694 if (!rent) {
695 log_fn(LOG_WARN,"Could not get address for router %s.",router->address);
696 return -1;
698 assert(rent->h_length == 4);
699 memcpy(&router->addr, rent->h_addr,rent->h_length);
700 router->addr = ntohl(router->addr); /* get it back into host order */
702 return 0;
705 static int
706 router_resolve_directory(directory_t *dir)
708 int i, max, remove;
709 if (!dir)
710 dir = directory;
712 max = dir->n_routers;
713 for (i = 0; i < max; ++i) {
714 remove = 0;
715 if (router_resolve(dir->routers[i])) {
716 log_fn(LOG_WARN, "Couldn't resolve router %s; not using",
717 dir->routers[i]->address);
718 remove = 1;
719 } else if (options.Nickname &&
720 !strcmp(dir->routers[i]->nickname, options.Nickname)) {
721 remove = 1;
723 if (remove) {
724 routerinfo_free(dir->routers[i]);
725 dir->routers[i] = dir->routers[--max];
726 --dir->n_routers;
727 --i;
731 return 0;
734 /* reads a single router entry from s.
735 * updates s so it points to after the router it just read.
736 * mallocs a new router, returns it if all goes well, else returns NULL.
738 routerinfo_t *router_get_entry_from_string(char**s) {
739 routerinfo_t *router = NULL;
740 char signed_digest[128];
741 char digest[128];
742 directory_token_t _tok;
743 directory_token_t *tok = &_tok;
744 struct tm published;
745 int t;
747 #define NEXT_TOKEN() \
748 do { if (router_get_next_token(s, tok)) { \
749 log_fn(LOG_WARN, "Error reading directory: %s", tok->val.error);\
750 goto err; \
751 } } while(0)
753 #define ARGS tok->val.cmd.args
755 if (router_get_router_hash(*s, digest) < 0) {
756 log_fn(LOG_WARN, "Couldn't compute router hash.");
757 return NULL;
760 NEXT_TOKEN();
762 if (tok->tp != K_ROUTER) {
763 router_release_token(tok);
764 log_fn(LOG_WARN,"Entry does not start with \"router\"");
765 return NULL;
768 router = tor_malloc_zero(sizeof(routerinfo_t));
769 router->onion_pkey = router->identity_pkey = router->link_pkey = NULL;
771 if (tok->val.cmd.n_args != 6) {
772 log_fn(LOG_WARN,"Wrong # of arguments to \"router\"");
773 goto err;
775 router->nickname = tor_strdup(ARGS[0]);
776 if (strlen(router->nickname) > MAX_NICKNAME_LEN) {
777 log_fn(LOG_WARN,"Router nickname too long.");
778 goto err;
780 if (strspn(router->nickname, LEGAL_NICKNAME_CHARACTERS) !=
781 strlen(router->nickname)) {
782 log_fn(LOG_WARN, "Router nickname contains illegal characters.");
783 goto err;
786 /* read router.address */
787 router->address = tor_strdup(ARGS[1]);
788 router->addr = 0;
790 /* Read router->or_port */
791 router->or_port = atoi(ARGS[2]);
792 if(!router->or_port) {
793 log_fn(LOG_WARN,"or_port unreadable or 0. Failing.");
794 goto err;
797 /* Router->socks_port */
798 router->socks_port = atoi(ARGS[3]);
800 /* Router->dir_port */
801 router->dir_port = atoi(ARGS[4]);
803 /* Router->bandwidth */
804 router->bandwidth = atoi(ARGS[5]);
805 if (!router->bandwidth) {
806 log_fn(LOG_WARN,"bandwidth unreadable or 0. Failing.");
807 goto err;
810 log_fn(LOG_DEBUG,"or_port %d, socks_port %d, dir_port %d, bandwidth %d.",
811 router->or_port, router->socks_port, router->dir_port, router->bandwidth);
813 /* XXX Later, require platform before published. */
814 NEXT_TOKEN();
815 if (tok->tp == K_PLATFORM) {
816 NEXT_TOKEN();
819 if (tok->tp != K_PUBLISHED) {
820 log_fn(LOG_WARN, "Missing published time"); goto err;
822 if (tok->val.cmd.n_args != 2) {
823 log_fn(LOG_WARN, "Wrong number of arguments to published"); goto err;
825 ARGS[1][-1] = ' '; /* Re-insert space. */
826 if (!strptime(ARGS[0], "%Y-%m-%d %H:%M:%S", &published)) {
827 log_fn(LOG_WARN, "Published time was unparseable"); goto err;
829 router->published_on = tor_timegm(&published);
831 NEXT_TOKEN();
832 if (tok->tp != K_ONION_KEY) {
833 log_fn(LOG_WARN, "Missing onion-key"); goto err;
835 NEXT_TOKEN();
836 if (tok->tp != _PUBLIC_KEY) {
837 log_fn(LOG_WARN, "Missing onion key"); goto err;
838 } /* XXX Check key length */
839 router->onion_pkey = tok->val.public_key;
841 NEXT_TOKEN();
842 if (tok->tp != K_LINK_KEY) {
843 log_fn(LOG_WARN, "Missing link-key"); goto err;
845 NEXT_TOKEN();
846 if (tok->tp != _PUBLIC_KEY) {
847 log_fn(LOG_WARN, "Missing link key"); goto err;
848 } /* XXX Check key length */
849 router->link_pkey = tok->val.public_key;
851 NEXT_TOKEN();
852 if (tok->tp != K_SIGNING_KEY) {
853 log_fn(LOG_WARN, "Missing signing-key"); goto err;
855 NEXT_TOKEN();
856 if (tok->tp != _PUBLIC_KEY) {
857 log_fn(LOG_WARN, "Missing signing key"); goto err;
859 router->identity_pkey = tok->val.public_key;
861 NEXT_TOKEN();
862 while (tok->tp == K_ACCEPT || tok->tp == K_REJECT) {
863 router_add_exit_policy(router, tok);
864 NEXT_TOKEN();
867 if (tok->tp != K_ROUTER_SIGNATURE) {
868 log_fn(LOG_WARN,"Missing router signature");
869 goto err;
871 NEXT_TOKEN();
872 if (tok->tp != _SIGNATURE) {
873 log_fn(LOG_WARN,"Missing router signature");
874 goto err;
876 assert (router->identity_pkey);
878 if ((t=crypto_pk_public_checksig(router->identity_pkey, tok->val.signature,
879 128, signed_digest)) != 20) {
880 log_fn(LOG_WARN, "Invalid signature %d",t);
881 goto err;
883 if (memcmp(digest, signed_digest, 20)) {
884 log_fn(LOG_WARN, "Mismatched signature");
885 goto err;
888 router_release_token(tok); /* free the signature */
889 return router;
891 err:
892 router_release_token(tok);
893 routerinfo_free(router);
894 return NULL;
895 #undef ARGS
896 #undef NEXT_TOKEN
899 void router_add_exit_policy_from_config(routerinfo_t *router) {
900 char *s = options.ExitPolicy, *e;
901 int last=0;
902 char line[1024];
904 if(!s) {
905 log_fn(LOG_INFO,"No exit policy configured. Ok.");
906 return; /* nothing to see here */
908 if(!*s) {
909 log_fn(LOG_INFO,"Exit policy is empty. Ok.");
910 return; /* nothing to see here */
913 for(;;) {
914 e = strchr(s,',');
915 if(!e) {
916 last = 1;
917 strncpy(line,s,1023);
918 } else {
919 memcpy(line,s, ((e-s)<1023)?(e-s):1023);
920 line[e-s] = 0;
922 line[1023]=0;
923 log_fn(LOG_DEBUG,"Adding new entry '%s'",line);
924 if(router_add_exit_policy_from_string(router,line) < 0)
925 log_fn(LOG_WARN,"Malformed exit policy %s; skipping.", line);
926 if(last)
927 return;
928 s = e+1;
932 static int
933 router_add_exit_policy_from_string(routerinfo_t *router,
934 char *s)
936 directory_token_t tok;
937 char *tmp, *cp;
938 int r;
939 int len, idx;
941 len = strlen(s);
942 tmp = cp = tor_malloc(len+2);
943 for (idx = 0; idx < len; ++idx) {
944 tmp[idx] = tolower(s[idx]);
946 tmp[len]='\n';
947 tmp[len+1]='\0';
948 if (router_get_next_token(&cp, &tok)) {
949 log_fn(LOG_WARN, "Error reading exit policy: %s", tok.val.error);
950 free(tmp);
951 return -1;
953 if (tok.tp != K_ACCEPT && tok.tp != K_REJECT) {
954 log_fn(LOG_WARN, "Expected 'accept' or 'reject'.");
955 free(tmp);
956 return -1;
958 r = router_add_exit_policy(router, &tok);
959 free(tmp);
960 return r;
963 static int router_add_exit_policy(routerinfo_t *router,
964 directory_token_t *tok) {
965 struct exit_policy_t *tmpe, *newe;
966 struct in_addr in;
967 char *arg, *address, *mask, *port, *endptr;
968 int bits;
970 if (tok->val.cmd.n_args != 1)
971 return -1;
972 arg = tok->val.cmd.args[0];
974 newe = tor_malloc_zero(sizeof(struct exit_policy_t));
976 newe->string = tor_malloc(8+strlen(arg));
977 if (tok->tp == K_REJECT) {
978 strcpy(newe->string, "reject ");
979 newe->policy_type = EXIT_POLICY_REJECT;
980 } else {
981 assert(tok->tp == K_ACCEPT);
982 strcpy(newe->string, "accept ");
983 newe->policy_type = EXIT_POLICY_ACCEPT;
985 strcat(newe->string, arg);
987 address = arg;
988 mask = strchr(arg,'/');
989 port = strchr(mask?mask:arg,':');
990 if(!port)
991 goto policy_read_failed;
992 if (mask)
993 *mask++ = 0;
994 *port++ = 0;
996 if (strcmp(address, "*") == 0) {
997 newe->addr = 0;
998 } else if (inet_aton(address, &in) != 0) {
999 newe->addr = ntohl(in.s_addr);
1000 } else {
1001 log_fn(LOG_WARN, "Malformed IP %s in exit policy; rejecting.",
1002 address);
1003 goto policy_read_failed;
1005 if (!mask) {
1006 if (strcmp(address, "*") == 0)
1007 newe->msk = 0;
1008 else
1009 newe->msk = 0xFFFFFFFFu;
1010 } else {
1011 endptr = NULL;
1012 bits = (int) strtol(mask, &endptr, 10);
1013 if (!*endptr) {
1014 /* strtol handled the whole mask. */
1015 newe->msk = ~((1<<(32-bits))-1);
1016 } else if (inet_aton(mask, &in) != 0) {
1017 newe->msk = ntohl(in.s_addr);
1018 } else {
1019 log_fn(LOG_WARN, "Malformed mask %s on exit policy; rejecting.",
1020 mask);
1021 goto policy_read_failed;
1024 if (strcmp(port, "*") == 0) {
1025 newe->prt = 0;
1026 } else {
1027 endptr = NULL;
1028 newe->prt = strtol(port, &endptr, 10);
1029 if (*endptr) {
1030 log_fn(LOG_WARN, "Malformed port %s on exit policy; rejecting.",
1031 port);
1032 goto policy_read_failed;
1036 in.s_addr = htonl(newe->addr);
1037 address = tor_strdup(inet_ntoa(in));
1038 in.s_addr = htonl(newe->msk);
1039 log_fn(LOG_DEBUG,"%s %s/%s:%d",
1040 newe->policy_type == EXIT_POLICY_REJECT ? "reject" : "accept",
1041 address, inet_ntoa(in), newe->prt);
1042 tor_free(address);
1044 /* now link newe onto the end of exit_policy */
1046 if(!router->exit_policy) {
1047 router->exit_policy = newe;
1048 return 0;
1051 for(tmpe=router->exit_policy; tmpe->next; tmpe=tmpe->next) ;
1052 tmpe->next = newe;
1054 return 0;
1056 policy_read_failed:
1057 assert(newe->string);
1058 log_fn(LOG_WARN,"Couldn't parse line '%s'. Dropping", newe->string);
1059 tor_free(newe->string);
1060 free(newe);
1061 return -1;
1064 /* Addr is 0 for "IP unknown".
1066 * Returns -1 for 'rejected', 0 for accepted, 1 for 'maybe' (since IP is
1067 * unknown.
1069 int router_supports_exit_address(uint32_t addr, uint16_t port,
1070 routerinfo_t *router)
1072 return router_compare_addr_to_exit_policy(addr, port, router->exit_policy);
1075 /* Addr is 0 for "IP unknown".
1077 * Returns -1 for 'rejected', 0 for accepted, 1 for 'maybe' (since IP is
1078 * unknown.
1080 int router_compare_addr_to_exit_policy(uint32_t addr, uint16_t port,
1081 struct exit_policy_t *policy)
1083 int maybe_reject = 0;
1084 int match = 0;
1085 struct in_addr in;
1086 struct exit_policy_t *tmpe;
1088 for(tmpe=policy; tmpe; tmpe=tmpe->next) {
1089 log_fn(LOG_DEBUG,"Considering exit policy %s", tmpe->string);
1090 if (!addr) {
1091 /* Address is unknown. */
1092 if (tmpe->msk == 0 && port == tmpe->prt) {
1093 /* The exit policy is accept/reject *:port */
1094 match = 1;
1095 } else if ((!tmpe->prt || port == tmpe->prt) &&
1096 tmpe->policy_type == EXIT_POLICY_REJECT) {
1097 /* The exit policy is reject ???:port */
1098 maybe_reject = 1;
1100 } else {
1101 /* Address is known */
1102 if ( (addr & tmpe->msk) == (tmpe->addr & tmpe->msk) &&
1103 (!tmpe->prt || port == tmpe->prt) ) {
1104 /* Exact match for the policy */
1105 match = 1;
1108 if (match) {
1109 in.s_addr = htonl(addr);
1110 log_fn(LOG_INFO,"Address %s:%d matches exit policy '%s'",
1111 inet_ntoa(in), port, tmpe->string);
1112 if(tmpe->policy_type == EXIT_POLICY_ACCEPT)
1113 return 0;
1114 else
1115 return -1;
1118 if (maybe_reject)
1119 return 1;
1120 else
1121 return 0; /* accept all by default. */
1124 /* Return 0 if my exit policy says to allow connection to conn.
1125 * Else return -1.
1127 int router_compare_to_exit_policy(connection_t *conn) {
1128 assert(desc_routerinfo);
1130 if (router_compare_addr_to_exit_policy(conn->addr, conn->port,
1131 desc_routerinfo->exit_policy))
1132 return -1;
1133 else
1134 return 0;
1137 const char *router_get_my_descriptor(void) {
1138 if (!desc_routerinfo) {
1139 if (router_rebuild_descriptor())
1140 return NULL;
1142 log_fn(LOG_DEBUG,"my desc is '%s'",descriptor);
1143 return descriptor;
1145 const routerinfo_t *router_get_desc_routerinfo(void) {
1146 if (!desc_routerinfo) {
1147 if (router_rebuild_descriptor())
1148 return NULL;
1150 return desc_routerinfo;
1153 int router_rebuild_descriptor(void) {
1154 routerinfo_t *ri;
1155 char localhostname[256];
1156 char *address = options.Address;
1158 if(!address) { /* if not specified in config, we find a default */
1159 if(gethostname(localhostname,sizeof(localhostname)) < 0) {
1160 log_fn(LOG_WARN,"Error obtaining local hostname");
1161 return -1;
1163 address = localhostname;
1164 if(!strchr(address,'.')) {
1165 log_fn(LOG_WARN,"fqdn '%s' has only one element. Misconfigured machine?",address);
1166 log_fn(LOG_WARN,"Try setting the Address line in your config file.");
1167 return -1;
1170 ri = tor_malloc(sizeof(routerinfo_t));
1171 ri->address = tor_strdup(address);
1172 ri->nickname = tor_strdup(options.Nickname);
1173 /* No need to set addr. */
1174 ri->or_port = options.ORPort;
1175 ri->socks_port = options.SocksPort;
1176 ri->dir_port = options.DirPort;
1177 ri->published_on = time(NULL);
1178 ri->onion_pkey = crypto_pk_dup_key(get_onion_key());
1179 ri->link_pkey = crypto_pk_dup_key(get_link_key());
1180 ri->identity_pkey = crypto_pk_dup_key(get_identity_key());
1181 ri->bandwidth = options.TotalBandwidth;
1182 ri->exit_policy = NULL; /* zero it out first */
1183 router_add_exit_policy_from_config(ri);
1184 if (desc_routerinfo)
1185 routerinfo_free(desc_routerinfo);
1186 desc_routerinfo = ri;
1187 if (router_dump_router_to_string(descriptor, 8192, ri, get_identity_key())<0) {
1188 log_fn(LOG_WARN, "Couldn't dump router to string.");
1189 return -1;
1191 return 0;
1194 static void get_platform_str(char *platform, int len)
1196 snprintf(platform, len-1, "Tor %s on %s", VERSION, get_uname());
1197 platform[len-1] = '\0';
1198 return;
1201 /* XXX need to audit this thing and count fenceposts. maybe
1202 * refactor so we don't have to keep asking if we're
1203 * near the end of maxlen?
1205 #define DEBUG_ROUTER_DUMP_ROUTER_TO_STRING
1206 int router_dump_router_to_string(char *s, int maxlen, routerinfo_t *router,
1207 crypto_pk_env_t *ident_key) {
1208 char *onion_pkey;
1209 char *link_pkey;
1210 char *identity_pkey;
1211 struct in_addr in;
1212 char platform[256];
1213 char digest[20];
1214 char signature[128];
1215 char published[32];
1216 int onion_pkeylen, link_pkeylen, identity_pkeylen;
1217 int written;
1218 int result=0;
1219 struct exit_policy_t *tmpe;
1220 #ifdef DEBUG_ROUTER_DUMP_ROUTER_TO_STRING
1221 char *s_tmp, *s_dup;
1222 routerinfo_t *ri_tmp;
1223 #endif
1225 get_platform_str(platform, sizeof(platform));
1227 if (crypto_pk_cmp_keys(ident_key, router->identity_pkey)) {
1228 log_fn(LOG_WARN,"Tried to sign a router with a private key that didn't match router's public key!");
1229 return -1;
1232 if(crypto_pk_write_public_key_to_string(router->onion_pkey,
1233 &onion_pkey,&onion_pkeylen)<0) {
1234 log_fn(LOG_WARN,"write onion_pkey to string failed!");
1235 return -1;
1238 if(crypto_pk_write_public_key_to_string(router->identity_pkey,
1239 &identity_pkey,&identity_pkeylen)<0) {
1240 log_fn(LOG_WARN,"write identity_pkey to string failed!");
1241 return -1;
1244 if(crypto_pk_write_public_key_to_string(router->link_pkey,
1245 &link_pkey,&link_pkeylen)<0) {
1246 log_fn(LOG_WARN,"write link_pkey to string failed!");
1247 return -1;
1249 strftime(published, 32, "%Y-%m-%d %H:%M:%S", gmtime(&router->published_on));
1251 result = snprintf(s, maxlen,
1252 "router %s %s %d %d %d %d\n"
1253 "platform %s\n"
1254 "published %s\n"
1255 "onion-key\n%s"
1256 "link-key\n%s"
1257 "signing-key\n%s",
1258 router->nickname,
1259 router->address,
1260 router->or_port,
1261 router->socks_port,
1262 router->dir_port,
1263 router->bandwidth,
1264 platform,
1265 published,
1266 onion_pkey, link_pkey, identity_pkey);
1268 free(onion_pkey);
1269 free(link_pkey);
1270 free(identity_pkey);
1272 if(result < 0 || result >= maxlen) {
1273 /* apparently different glibcs do different things on snprintf error.. so check both */
1274 return -1;
1276 written = result;
1278 for(tmpe=router->exit_policy; tmpe; tmpe=tmpe->next) {
1279 in.s_addr = htonl(tmpe->addr);
1280 result = snprintf(s+written, maxlen-written, "%s %s",
1281 tmpe->policy_type == EXIT_POLICY_ACCEPT ? "accept" : "reject",
1282 tmpe->msk == 0 ? "*" : inet_ntoa(in));
1283 if(result < 0 || result+written > maxlen) {
1284 /* apparently different glibcs do different things on snprintf error.. so check both */
1285 return -1;
1287 written += result;
1288 if (tmpe->msk != 0xFFFFFFFFu && tmpe->msk != 0) {
1289 in.s_addr = htonl(tmpe->msk);
1290 result = snprintf(s+written, maxlen-written, "/%s", inet_ntoa(in));
1291 if (result<0 || result+written > maxlen)
1292 return -1;
1293 written += result;
1295 if (tmpe->prt) {
1296 result = snprintf(s+written, maxlen-written, ":%d\n", tmpe->prt);
1297 if (result<0 || result+written > maxlen)
1298 return -1;
1299 written += result;
1300 } else {
1301 if (written > maxlen-4)
1302 return -1;
1303 strcat(s+written, ":*\n");
1304 written += 3;
1306 } /* end for */
1307 if (written > maxlen-256) /* Not enough room for signature. */
1308 return -1;
1310 strcat(s+written, "router-signature\n");
1311 written += strlen(s+written);
1312 s[written] = '\0';
1313 if (router_get_router_hash(s, digest) < 0)
1314 return -1;
1316 if (crypto_pk_private_sign(ident_key, digest, 20, signature) < 0) {
1317 log_fn(LOG_WARN, "Error signing digest");
1318 return -1;
1320 strcat(s+written, "-----BEGIN SIGNATURE-----\n");
1321 written += strlen(s+written);
1322 if (base64_encode(s+written, maxlen-written, signature, 128) < 0) {
1323 log_fn(LOG_WARN, "Couldn't base64-encode signature");
1324 return -1;
1326 written += strlen(s+written);
1327 strcat(s+written, "-----END SIGNATURE-----\n");
1328 written += strlen(s+written);
1330 if (written > maxlen-2)
1331 return -1;
1332 /* include a last '\n' */
1333 s[written] = '\n';
1334 s[written+1] = 0;
1336 #ifdef DEBUG_ROUTER_DUMP_ROUTER_TO_STRING
1337 s_tmp = s_dup = tor_strdup(s);
1338 ri_tmp = router_get_entry_from_string(&s_tmp);
1339 if (!ri_tmp) {
1340 log_fn(LOG_ERR, "We just generated a router descriptor we can't parse: <<%s>>",
1342 return -1;
1344 free(s_dup);
1345 routerinfo_free(ri_tmp);
1346 #endif
1348 return written+1;
1352 Local Variables:
1353 mode:c
1354 indent-tabs-mode:nil
1355 c-basic-offset:2
1356 End: