dirserv.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755
  1. /* Copyright 2001,2002,2003 Roger Dingledine, Matej Pfajfar. */
  2. /* See LICENSE for licensing information */
  3. /* $Id$ */
  4. #include "or.h"
  5. /**
  6. * \file dirserv.c
  7. * \brief Directory server core implementation.
  8. **/
  9. /** How far in the future do we allow a router to get? (seconds) */
  10. #define ROUTER_ALLOW_SKEW (30*60)
  11. extern or_options_t options; /**< command-line and config-file options */
  12. /** Do we need to regenerate the directory when someone asks for it? */
  13. static int the_directory_is_dirty = 1;
  14. static int runningrouters_is_dirty = 1;
  15. static int list_running_servers(char **nicknames_out);
  16. static void directory_remove_unrecognized(void);
  17. /************** Fingerprint handling code ************/
  18. typedef struct fingerprint_entry_t {
  19. char *nickname;
  20. char *fingerprint;
  21. } fingerprint_entry_t;
  22. /** List of nickname-\>identity fingerprint mappings for all the routers
  23. * that we recognize. Used to prevent Sybil attacks. */
  24. static smartlist_t *fingerprint_list = NULL;
  25. /** Add the fingerprint <b>fp</b> for the nickname <b>nickname</b> to
  26. * the global list of recognized identity key fingerprints.
  27. */
  28. void /* Should be static; exposed for testing */
  29. add_fingerprint_to_dir(const char *nickname, const char *fp)
  30. {
  31. int i;
  32. fingerprint_entry_t *ent;
  33. if (!fingerprint_list)
  34. fingerprint_list = smartlist_create();
  35. for (i = 0; i < smartlist_len(fingerprint_list); ++i) {
  36. ent = smartlist_get(fingerprint_list, i);
  37. if (!strcasecmp(ent->nickname,nickname)) {
  38. tor_free(ent->fingerprint);
  39. ent->fingerprint = tor_strdup(fp);
  40. return;
  41. }
  42. }
  43. ent = tor_malloc(sizeof(fingerprint_entry_t));
  44. ent->nickname = tor_strdup(nickname);
  45. ent->fingerprint = tor_strdup(fp);
  46. smartlist_add(fingerprint_list, ent);
  47. }
  48. /** Add the nickname and fingerprint for this OR to the recognized list.
  49. */
  50. int
  51. dirserv_add_own_fingerprint(const char *nickname, crypto_pk_env_t *pk)
  52. {
  53. char fp[FINGERPRINT_LEN+1];
  54. if (crypto_pk_get_fingerprint(pk, fp)<0) {
  55. log_fn(LOG_ERR, "Error computing fingerprint");
  56. return -1;
  57. }
  58. add_fingerprint_to_dir(nickname, fp);
  59. return 0;
  60. }
  61. /** Parse the nickname-\>fingerprint mappings stored in the file named
  62. * <b>fname</b>. The file format is line-based, with each non-blank
  63. * holding one nickname, some space, and a fingerprint for that
  64. * nickname. On success, replace the current fingerprint list with
  65. * the contents of <b>fname</b> and return 0. On failure, leave the
  66. * current fingerprint list untouched, and return -1. */
  67. int
  68. dirserv_parse_fingerprint_file(const char *fname)
  69. {
  70. FILE *file;
  71. char line[FINGERPRINT_LEN+MAX_NICKNAME_LEN+20+1];
  72. char *nickname, *fingerprint;
  73. smartlist_t *fingerprint_list_new;
  74. int i, result;
  75. fingerprint_entry_t *ent;
  76. if(!(file = fopen(fname, "r"))) {
  77. log_fn(LOG_WARN, "Cannot open fingerprint file %s", fname);
  78. return -1;
  79. }
  80. fingerprint_list_new = smartlist_create();
  81. while( (result=parse_line_from_file(line, sizeof(line),file,&nickname,&fingerprint)) > 0) {
  82. if (strlen(nickname) > MAX_NICKNAME_LEN) {
  83. log(LOG_WARN, "Nickname %s too long in fingerprint file. Skipping.", nickname);
  84. continue;
  85. }
  86. if(strlen(fingerprint) != FINGERPRINT_LEN ||
  87. !crypto_pk_check_fingerprint_syntax(fingerprint)) {
  88. log_fn(LOG_WARN, "Invalid fingerprint (nickname %s, fingerprint %s). Skipping.",
  89. nickname, fingerprint);
  90. continue;
  91. }
  92. for (i = 0; i < smartlist_len(fingerprint_list_new); ++i) {
  93. ent = smartlist_get(fingerprint_list_new, i);
  94. if (0==strcasecmp(ent->nickname, nickname)) {
  95. log(LOG_WARN, "Duplicate nickname %s. Skipping.",nickname);
  96. break; /* out of the for. the 'if' below means skip to the next line. */
  97. }
  98. }
  99. if(i == smartlist_len(fingerprint_list_new)) { /* not a duplicate */
  100. ent = tor_malloc(sizeof(fingerprint_entry_t));
  101. ent->nickname = tor_strdup(nickname);
  102. ent->fingerprint = tor_strdup(fingerprint);
  103. smartlist_add(fingerprint_list_new, ent);
  104. }
  105. }
  106. fclose(file);
  107. if(result == 0) { /* eof; replace the global fingerprints list. */
  108. dirserv_free_fingerprint_list();
  109. fingerprint_list = fingerprint_list_new;
  110. /* Delete any routers whose fingerprints we no longer recognize */
  111. directory_remove_unrecognized();
  112. return 0;
  113. }
  114. /* error */
  115. log_fn(LOG_WARN, "Error reading from fingerprint file");
  116. for (i = 0; i < smartlist_len(fingerprint_list_new); ++i) {
  117. ent = smartlist_get(fingerprint_list_new, i);
  118. tor_free(ent->nickname);
  119. tor_free(ent->fingerprint);
  120. tor_free(ent);
  121. }
  122. smartlist_free(fingerprint_list_new);
  123. return -1;
  124. }
  125. /** Check whether <b>router</b> has a nickname/identity key combination that
  126. * we recognize from the fingerprint list. Return 1 if router's
  127. * identity and nickname match, -1 if we recognize the nickname but
  128. * the identity key is wrong, and 0 if the nickname is not known. */
  129. int
  130. dirserv_router_fingerprint_is_known(const routerinfo_t *router)
  131. {
  132. int i, found=0;
  133. fingerprint_entry_t *ent =NULL;
  134. char fp[FINGERPRINT_LEN+1];
  135. if (!fingerprint_list)
  136. fingerprint_list = smartlist_create();
  137. log_fn(LOG_DEBUG, "%d fingerprints known.", smartlist_len(fingerprint_list));
  138. for (i=0;i<smartlist_len(fingerprint_list);++i) {
  139. ent = smartlist_get(fingerprint_list, i);
  140. log_fn(LOG_DEBUG,"%s vs %s", router->nickname, ent->nickname);
  141. if (!strcasecmp(router->nickname,ent->nickname)) {
  142. found = 1;
  143. break;
  144. }
  145. }
  146. if (!found) { /* No such server known */
  147. log_fn(LOG_INFO,"no fingerprint found for %s",router->nickname);
  148. return 0;
  149. }
  150. if (crypto_pk_get_fingerprint(router->identity_pkey, fp)) {
  151. log_fn(LOG_WARN,"error computing fingerprint");
  152. return -1;
  153. }
  154. if (0==strcasecmp(ent->fingerprint, fp)) {
  155. log_fn(LOG_DEBUG,"good fingerprint for %s",router->nickname);
  156. return 1; /* Right fingerprint. */
  157. } else {
  158. log_fn(LOG_WARN,"mismatched fingerprint for %s",router->nickname);
  159. return -1; /* Wrong fingerprint. */
  160. }
  161. }
  162. /** Return true iff any router named <b>nickname</b> is in the fingerprint
  163. * list. */
  164. static int
  165. router_nickname_is_approved(const char *nickname, const char *digest)
  166. {
  167. int i,j;
  168. fingerprint_entry_t *ent;
  169. char fp[FINGERPRINT_LEN+1];
  170. if (!fingerprint_list)
  171. return 0;
  172. for (i=j=0;i<DIGEST_LEN;++i,++j) {
  173. fp[i]=digest[j];
  174. if ((j%4)==3 && j != 19)
  175. fp[++i]=' ';
  176. }
  177. fp[i]='\0';
  178. for (i=0;i<smartlist_len(fingerprint_list);++i) {
  179. ent = smartlist_get(fingerprint_list, i);
  180. if (!strcasecmp(nickname,ent->nickname) &&
  181. !strcasecmp(fp,ent->fingerprint)) {
  182. return 1;
  183. }
  184. }
  185. return 0;
  186. }
  187. /** Clear the current fingerprint list. */
  188. void
  189. dirserv_free_fingerprint_list()
  190. {
  191. int i;
  192. fingerprint_entry_t *ent;
  193. if (!fingerprint_list)
  194. return;
  195. for (i = 0; i < smartlist_len(fingerprint_list); ++i) {
  196. ent = smartlist_get(fingerprint_list, i);
  197. tor_free(ent->nickname);
  198. tor_free(ent->fingerprint);
  199. tor_free(ent);
  200. }
  201. smartlist_free(fingerprint_list);
  202. fingerprint_list = NULL;
  203. }
  204. /*
  205. * Descriptor list
  206. */
  207. /** A directory server's view of a server descriptor. Contains both
  208. * parsed and unparsed versions. */
  209. typedef struct descriptor_entry_t {
  210. char *nickname;
  211. time_t published;
  212. size_t desc_len;
  213. char *descriptor;
  214. int verified;
  215. routerinfo_t *router;
  216. } descriptor_entry_t;
  217. /** List of all server descriptors that this dirserv is holding. */
  218. static smartlist_t *descriptor_list = NULL;
  219. /** Release the storage held by <b>desc</b> */
  220. static void free_descriptor_entry(descriptor_entry_t *desc)
  221. {
  222. tor_free(desc->descriptor);
  223. tor_free(desc->nickname);
  224. routerinfo_free(desc->router);
  225. free(desc);
  226. }
  227. /** Release all storage that the dirserv is holding for server
  228. * descriptors. */
  229. void
  230. dirserv_free_descriptors()
  231. {
  232. if (!descriptor_list)
  233. return;
  234. SMARTLIST_FOREACH(descriptor_list, descriptor_entry_t *, d,
  235. free_descriptor_entry(d));
  236. smartlist_clear(descriptor_list);
  237. }
  238. /** Parse the server descriptor at *desc and maybe insert it into the
  239. * list of service descriptors, and (if the descriptor is well-formed)
  240. * advance *desc immediately past the descriptor's end.
  241. *
  242. * Return 1 if descriptor is well-formed and accepted;
  243. * 0 if well-formed and server is unapproved;
  244. * -1 if not well-formed or other error.
  245. */
  246. int
  247. dirserv_add_descriptor(const char **desc)
  248. {
  249. descriptor_entry_t *ent = NULL;
  250. routerinfo_t *ri = NULL;
  251. int i, r, found=-1;
  252. char *start, *end;
  253. char *desc_tmp = NULL;
  254. const char *cp;
  255. size_t desc_len;
  256. time_t now;
  257. if (!descriptor_list)
  258. descriptor_list = smartlist_create();
  259. start = strstr(*desc, "router ");
  260. if (!start) {
  261. log_fn(LOG_WARN, "no 'router' line found. This is not a descriptor.");
  262. return -1;
  263. }
  264. if ((end = strstr(start+6, "\nrouter "))) {
  265. ++end; /* Include NL. */
  266. } else if ((end = strstr(start+6, "\ndirectory-signature"))) {
  267. ++end;
  268. } else {
  269. end = start+strlen(start);
  270. }
  271. desc_len = end-start;
  272. cp = desc_tmp = tor_strndup(start, desc_len);
  273. /* Check: is the descriptor syntactically valid? */
  274. ri = router_parse_entry_from_string(cp, NULL);
  275. tor_free(desc_tmp);
  276. if (!ri) {
  277. log(LOG_WARN, "Couldn't parse descriptor");
  278. return -1;
  279. }
  280. /* Okay. Now check whether the fingerprint is recognized. */
  281. r = dirserv_router_fingerprint_is_known(ri);
  282. if(r<1) {
  283. if(r==0) {
  284. char fp[FINGERPRINT_LEN+1];
  285. log_fn(LOG_WARN, "Unknown nickname %s (%s:%d). Not adding.",
  286. ri->nickname, ri->address, ri->or_port);
  287. if (crypto_pk_get_fingerprint(ri->identity_pkey, fp) < 0) {
  288. log_fn(LOG_WARN, "Error computing fingerprint for %s", ri->nickname);
  289. } else {
  290. log_fn(LOG_WARN, "Fingerprint line: %s %s", ri->nickname, fp);
  291. }
  292. } else {
  293. log_fn(LOG_WARN, "Known nickname %s, wrong fingerprint. Not adding.", ri->nickname);
  294. }
  295. routerinfo_free(ri);
  296. *desc = end;
  297. return 0;
  298. }
  299. /* Is there too much clock skew? */
  300. now = time(NULL);
  301. if (ri->published_on > now+ROUTER_ALLOW_SKEW) {
  302. log_fn(LOG_WARN, "Publication time for nickname %s is too far in the future; possible clock skew. Not adding.", ri->nickname);
  303. routerinfo_free(ri);
  304. *desc = end;
  305. return 0;
  306. }
  307. if (ri->published_on < now-ROUTER_MAX_AGE) {
  308. log_fn(LOG_WARN, "Publication time for router with nickname %s is too far in the past. Not adding.", ri->nickname);
  309. routerinfo_free(ri);
  310. *desc = end;
  311. return 0;
  312. }
  313. /* Do we already have an entry for this router? */
  314. for (i = 0; i < smartlist_len(descriptor_list); ++i) {
  315. ent = smartlist_get(descriptor_list, i);
  316. if (!strcasecmp(ri->nickname, ent->nickname)) {
  317. found = i;
  318. break;
  319. }
  320. }
  321. if (found >= 0) {
  322. /* if so, decide whether to update it. */
  323. if (ent->published > ri->published_on) {
  324. /* We already have a newer descriptor */
  325. log_fn(LOG_INFO,"We already have a newer desc for nickname %s. Not adding.",ri->nickname);
  326. /* This isn't really an error; return success. */
  327. routerinfo_free(ri);
  328. *desc = end;
  329. return 1;
  330. }
  331. /* We don't have a newer one; we'll update this one. */
  332. log_fn(LOG_INFO,"Dirserv updating desc for nickname %s",ri->nickname);
  333. free_descriptor_entry(ent);
  334. smartlist_del_keeporder(descriptor_list, found);
  335. } else {
  336. /* Add at the end. */
  337. log_fn(LOG_INFO,"Dirserv adding desc for nickname %s",ri->nickname);
  338. }
  339. ent = tor_malloc(sizeof(descriptor_entry_t));
  340. ent->nickname = tor_strdup(ri->nickname);
  341. ent->published = ri->published_on;
  342. ent->desc_len = desc_len;
  343. ent->descriptor = tor_malloc(desc_len+1);
  344. strncpy(ent->descriptor, start, desc_len);
  345. ent->descriptor[desc_len] = '\0';
  346. ent->router = ri;
  347. ent->verified = 1; /* XXXX008 support other possibilities. */
  348. smartlist_add(descriptor_list, ent);
  349. *desc = end;
  350. directory_set_dirty();
  351. return 1;
  352. }
  353. /** Remove all descriptors whose nicknames or fingerprints we don't
  354. * recognize. (Descriptors that used to be good can become
  355. * unrecognized when we reload the fingerprint list.)
  356. */
  357. static void
  358. directory_remove_unrecognized(void)
  359. {
  360. int i;
  361. descriptor_entry_t *ent;
  362. if (!descriptor_list)
  363. descriptor_list = smartlist_create();
  364. for (i = 0; i < smartlist_len(descriptor_list); ++i) {
  365. ent = smartlist_get(descriptor_list, i);
  366. if (dirserv_router_fingerprint_is_known(ent->router)<=0) {
  367. log(LOG_INFO, "Router %s is no longer recognized",
  368. ent->nickname);
  369. free_descriptor_entry(ent);
  370. smartlist_del(descriptor_list, i--);
  371. }
  372. }
  373. }
  374. /** Mark the directory as <b>dirty</b> -- when we're next asked for a
  375. * directory, we will rebuild it instead of reusing the most recently
  376. * generated one.
  377. */
  378. void
  379. directory_set_dirty()
  380. {
  381. the_directory_is_dirty = 1;
  382. runningrouters_is_dirty = 1;
  383. }
  384. /** Load all descriptors from a directory stored in the string
  385. * <b>dir</b>.
  386. */
  387. int
  388. dirserv_load_from_directory_string(const char *dir)
  389. {
  390. const char *cp = dir;
  391. while(1) {
  392. cp = strstr(cp, "\nrouter ");
  393. if (!cp) break;
  394. ++cp;
  395. if (dirserv_add_descriptor(&cp) < 0) {
  396. return -1;
  397. }
  398. --cp; /*Back up to newline.*/
  399. }
  400. return 0;
  401. }
  402. /** Set *<b>nicknames_out</b> to a comma-separated list of all the ORs that we
  403. * believe are currently running (because we have open connections to
  404. * them). Return 0 on success; -1 on error.
  405. */
  406. static int
  407. list_running_servers(char **nicknames_out)
  408. {
  409. connection_t **connection_array;
  410. int n_conns;
  411. connection_t *conn;
  412. char *cp;
  413. int i;
  414. int length;
  415. smartlist_t *nicknames_up, *nicknames_down;
  416. *nicknames_out = NULL;
  417. nicknames_up = smartlist_create();
  418. nicknames_down = smartlist_create();
  419. smartlist_add(nicknames_up, tor_strdup(options.Nickname));
  420. get_connection_array(&connection_array, &n_conns);
  421. for (i = 0; i<n_conns; ++i) {
  422. char *name;
  423. conn = connection_array[i];
  424. if (conn->type != CONN_TYPE_OR || !conn->nickname)
  425. continue; /* only list ORs. */
  426. if (router_nickname_is_approved(conn->nickname, conn->identity_digest)) {
  427. name = tor_strdup(conn->nickname);
  428. } else {
  429. name = tor_malloc(HEX_DIGEST_LEN+2);
  430. *name = '$';
  431. base16_encode(name+1, HEX_DIGEST_LEN, conn->identity_digest, DIGEST_LEN);
  432. }
  433. if(conn->state == OR_CONN_STATE_OPEN)
  434. smartlist_add(nicknames_up, name);
  435. else
  436. smartlist_add(nicknames_down, name);
  437. }
  438. length = smartlist_len(nicknames_up) +
  439. 2*smartlist_len(nicknames_down) + 1;
  440. /* spaces + EOS + !'s + 1. */
  441. SMARTLIST_FOREACH(nicknames_up, char *, c, length += strlen(c));
  442. SMARTLIST_FOREACH(nicknames_down, char *, c, length += strlen(c));
  443. *nicknames_out = tor_malloc_zero(length);
  444. cp = *nicknames_out;
  445. for (i = 0; i<smartlist_len(nicknames_up); ++i) {
  446. if (i)
  447. strcat(cp, " ");
  448. strcat(cp, (char*)smartlist_get(nicknames_up,i)); /* can't overflow */
  449. while (*cp)
  450. ++cp;
  451. }
  452. for (i = 0; i<smartlist_len(nicknames_down); ++i) {
  453. strcat(cp, " !");
  454. strcat(cp, (char*)smartlist_get(nicknames_down,i)); /* can't overflow */
  455. while (*cp)
  456. ++cp;
  457. }
  458. SMARTLIST_FOREACH(nicknames_up, char *, victim, tor_free(victim));
  459. SMARTLIST_FOREACH(nicknames_down, char *, victim, tor_free(victim));
  460. smartlist_free(nicknames_up);
  461. smartlist_free(nicknames_down);
  462. return 0;
  463. }
  464. /** Remove any descriptors from the directory that are more than ROUTER_MAX_AGE
  465. * seconds old.
  466. */
  467. void
  468. dirserv_remove_old_servers(void)
  469. {
  470. int i;
  471. time_t cutoff;
  472. descriptor_entry_t *ent;
  473. if (!descriptor_list)
  474. descriptor_list = smartlist_create();
  475. cutoff = time(NULL) - ROUTER_MAX_AGE;
  476. for (i = 0; i < smartlist_len(descriptor_list); ++i) {
  477. ent = smartlist_get(descriptor_list, i);
  478. if (ent->published < cutoff) {
  479. /* descriptor_list[i] is too old. Remove it. */
  480. free_descriptor_entry(ent);
  481. smartlist_del(descriptor_list, i--);
  482. directory_set_dirty();
  483. }
  484. }
  485. }
  486. /** Dump all routers currently in the directory into the string
  487. * <b>s</b>, using at most <b>maxlen</b> characters, and signing the
  488. * directory with <b>private_key</b>. Return 0 on success, -1 on
  489. * failure.
  490. */
  491. int
  492. dirserv_dump_directory_to_string(char *s, unsigned int maxlen,
  493. crypto_pk_env_t *private_key)
  494. {
  495. char *cp, *eos;
  496. char digest[20];
  497. char signature[128];
  498. char published[33];
  499. time_t published_on;
  500. int i;
  501. eos = s+maxlen;
  502. if (!descriptor_list)
  503. descriptor_list = smartlist_create();
  504. if (list_running_servers(&cp))
  505. return -1;
  506. dirserv_remove_old_servers();
  507. published_on = time(NULL);
  508. strftime(published, 32, "%Y-%m-%d %H:%M:%S", gmtime(&published_on));
  509. snprintf(s, maxlen,
  510. "signed-directory\n"
  511. "published %s\n"
  512. "recommended-software %s\n"
  513. "running-routers %s\n\n",
  514. published, options.RecommendedVersions, cp);
  515. free(cp);
  516. i = strlen(s);
  517. cp = s+i;
  518. SMARTLIST_FOREACH(descriptor_list, descriptor_entry_t *, d,
  519. if (strlcat(s, d->descriptor, maxlen) >= maxlen)
  520. goto truncated);
  521. /* These multiple strlcat calls are inefficient, but dwarfed by the RSA
  522. signature.
  523. */
  524. if (strlcat(s, "directory-signature ", maxlen) >= maxlen)
  525. goto truncated;
  526. if (strlcat(s, options.Nickname, maxlen) >= maxlen)
  527. goto truncated;
  528. if (strlcat(s, "\n", maxlen) >= maxlen)
  529. goto truncated;
  530. if (router_get_dir_hash(s,digest)) {
  531. log_fn(LOG_WARN,"couldn't compute digest");
  532. return -1;
  533. }
  534. if (crypto_pk_private_sign(private_key, digest, 20, signature) < 0) {
  535. log_fn(LOG_WARN,"couldn't sign digest");
  536. return -1;
  537. }
  538. log(LOG_DEBUG,"generated directory digest begins with %s",hex_str(digest,4));
  539. if (strlcat(cp, "-----BEGIN SIGNATURE-----\n", maxlen) >= maxlen)
  540. goto truncated;
  541. i = strlen(s);
  542. cp = s+i;
  543. if (base64_encode(cp, maxlen-i, signature, 128) < 0) {
  544. log_fn(LOG_WARN,"couldn't base64-encode signature");
  545. return -1;
  546. }
  547. if (strlcat(s, "-----END SIGNATURE-----\n", maxlen) >= maxlen)
  548. goto truncated;
  549. return 0;
  550. truncated:
  551. log_fn(LOG_WARN,"tried to exceed string length.");
  552. return -1;
  553. }
  554. /** Most recently generated encoded signed directory. */
  555. static char *the_directory = NULL;
  556. static int the_directory_len = -1;
  557. static char *cached_directory = NULL; /* used only by non-auth dirservers */
  558. static time_t cached_directory_published = 0;
  559. static int cached_directory_len = -1;
  560. void dirserv_set_cached_directory(const char *directory, time_t when)
  561. {
  562. time_t now;
  563. tor_assert(!options.AuthoritativeDir);
  564. now = time(NULL);
  565. if (when>cached_directory_published &&
  566. when<now+ROUTER_ALLOW_SKEW) {
  567. tor_free(cached_directory);
  568. cached_directory = tor_strdup(directory);
  569. cached_directory_len = strlen(cached_directory);
  570. cached_directory_published = when;
  571. }
  572. }
  573. /** Set *<b>directory</b> to the most recently generated encoded signed
  574. * directory, generating a new one as necessary. */
  575. size_t dirserv_get_directory(const char **directory)
  576. {
  577. char *new_directory;
  578. char filename[512];
  579. if (!options.AuthoritativeDir) {
  580. if (cached_directory) {
  581. *directory = cached_directory;
  582. return (size_t) cached_directory_len;
  583. } else {
  584. /* no directory yet retrieved */
  585. return 0;
  586. }
  587. }
  588. if (the_directory_is_dirty) {
  589. new_directory = tor_malloc(MAX_DIR_SIZE);
  590. if (dirserv_dump_directory_to_string(new_directory, MAX_DIR_SIZE,
  591. get_identity_key())) {
  592. log(LOG_WARN, "Error creating directory.");
  593. free(new_directory);
  594. return 0;
  595. }
  596. tor_free(the_directory);
  597. the_directory = new_directory;
  598. the_directory_len = strlen(the_directory);
  599. log_fn(LOG_INFO,"New directory (size %d):\n%s",the_directory_len,
  600. the_directory);
  601. the_directory_is_dirty = 0;
  602. /* Now read the directory we just made in order to update our own
  603. * router lists. This does more signature checking than is strictly
  604. * necessary, but safe is better than sorry. */
  605. new_directory = tor_strdup(the_directory);
  606. /* use a new copy of the dir, since get_dir_from_string scribbles on it */
  607. if (router_load_routerlist_from_directory(new_directory, get_identity_key())) {
  608. log_fn(LOG_ERR, "We just generated a directory we can't parse. Dying.");
  609. exit(0);
  610. }
  611. free(new_directory);
  612. sprintf(filename,"%s/cached-directory", get_data_directory(&options));
  613. if(write_str_to_file(filename,the_directory) < 0) {
  614. log_fn(LOG_WARN, "Couldn't write cached directory to disk. Ignoring.");
  615. }
  616. } else {
  617. log(LOG_INFO,"Directory still clean, reusing.");
  618. }
  619. *directory = the_directory;
  620. return the_directory_len;
  621. }
  622. static char *runningrouters_string=NULL;
  623. static size_t runningrouters_len=0;
  624. /** Replace the current running-routers list with a newly generated one. */
  625. static int generate_runningrouters(crypto_pk_env_t *private_key)
  626. {
  627. char *s, *cp;
  628. char digest[DIGEST_LEN];
  629. char signature[PK_BYTES];
  630. int i, len;
  631. char published[33];
  632. time_t published_on;
  633. len = 1024+MAX_NICKNAME_LEN*smartlist_len(descriptor_list);
  634. s = tor_malloc_zero(len);
  635. if (list_running_servers(&cp))
  636. return -1;
  637. published_on = time(NULL);
  638. strftime(published, 32, "%Y-%m-%d %H:%M:%S", gmtime(&published_on));
  639. sprintf(s, "network-status\n"
  640. "published %s\n"
  641. "running-routers %s\n"
  642. "directory-signature %s\n"
  643. "-----BEGIN SIGNATURE-----\n",
  644. published, cp, options.Nickname);
  645. free(cp);
  646. if (router_get_runningrouters_hash(s,digest)) {
  647. log_fn(LOG_WARN,"couldn't compute digest");
  648. return -1;
  649. }
  650. if (crypto_pk_private_sign(private_key, digest, 20, signature) < 0) {
  651. log_fn(LOG_WARN,"couldn't sign digest");
  652. return -1;
  653. }
  654. i = strlen(s);
  655. cp = s+i;
  656. if (base64_encode(cp, len-i, signature, 128) < 0) {
  657. log_fn(LOG_WARN,"couldn't base64-encode signature");
  658. return -1;
  659. }
  660. if (strlcat(s, "-----END SIGNATURE-----\n", len) >= len) {
  661. return -1;
  662. }
  663. tor_free(runningrouters_string);
  664. runningrouters_string = s;
  665. runningrouters_len = strlen(s);
  666. runningrouters_is_dirty = 0;
  667. return 0;
  668. }
  669. /** Set *<b>rr</b> to the most recently generated encoded signed
  670. * running-routers list, generating a new one as necessary. */
  671. size_t dirserv_get_runningrouters(const char **rr)
  672. {
  673. if (runningrouters_is_dirty) {
  674. if(generate_runningrouters(get_identity_key())) {
  675. log_fn(LOG_ERR, "Couldn't generate running-routers list?");
  676. return -1;
  677. }
  678. }
  679. *rr = runningrouters_string;
  680. return runningrouters_len;
  681. }
  682. /*
  683. Local Variables:
  684. mode:c
  685. indent-tabs-mode:nil
  686. c-basic-offset:2
  687. End:
  688. */