dirserv.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729
  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)
  166. {
  167. int i;
  168. fingerprint_entry_t *ent;
  169. if (!fingerprint_list)
  170. return 0;
  171. for (i=0;i<smartlist_len(fingerprint_list);++i) {
  172. ent = smartlist_get(fingerprint_list, i);
  173. if (!strcasecmp(nickname,ent->nickname)) {
  174. return 1;
  175. }
  176. }
  177. return 0;
  178. }
  179. /** Clear the current fingerprint list. */
  180. void
  181. dirserv_free_fingerprint_list()
  182. {
  183. int i;
  184. fingerprint_entry_t *ent;
  185. if (!fingerprint_list)
  186. return;
  187. for (i = 0; i < smartlist_len(fingerprint_list); ++i) {
  188. ent = smartlist_get(fingerprint_list, i);
  189. tor_free(ent->nickname);
  190. tor_free(ent->fingerprint);
  191. tor_free(ent);
  192. }
  193. smartlist_free(fingerprint_list);
  194. fingerprint_list = NULL;
  195. }
  196. /*
  197. * Descriptor list
  198. */
  199. /** A directory server's view of a server descriptor. Contains both
  200. * parsed and unparsed versions. */
  201. typedef struct descriptor_entry_t {
  202. char *nickname;
  203. time_t published;
  204. size_t desc_len;
  205. char *descriptor;
  206. routerinfo_t *router;
  207. } descriptor_entry_t;
  208. /** List of all server descriptors that this dirserv is holding. */
  209. static smartlist_t *descriptor_list = NULL;
  210. /** Release the storage held by <b>desc</b> */
  211. static void free_descriptor_entry(descriptor_entry_t *desc)
  212. {
  213. tor_free(desc->descriptor);
  214. tor_free(desc->nickname);
  215. routerinfo_free(desc->router);
  216. free(desc);
  217. }
  218. /** Release all storage that the dirserv is holding for server
  219. * descriptors. */
  220. void
  221. dirserv_free_descriptors()
  222. {
  223. if (!descriptor_list)
  224. return;
  225. SMARTLIST_FOREACH(descriptor_list, descriptor_entry_t *, d,
  226. free_descriptor_entry(d));
  227. smartlist_clear(descriptor_list);
  228. }
  229. /** Parse the server descriptor at *desc and maybe insert it into the
  230. * list of service descriptors, and (if the descriptor is well-formed)
  231. * advance *desc immediately past the descriptor's end.
  232. *
  233. * Return 1 if descriptor is well-formed and accepted;
  234. * 0 if well-formed and server is unapproved;
  235. * -1 if not well-formed or other error.
  236. */
  237. int
  238. dirserv_add_descriptor(const char **desc)
  239. {
  240. descriptor_entry_t *ent = NULL;
  241. routerinfo_t *ri = NULL;
  242. int i, r, found=-1;
  243. char *start, *end;
  244. char *desc_tmp = NULL;
  245. const char *cp;
  246. size_t desc_len;
  247. time_t now;
  248. if (!descriptor_list)
  249. descriptor_list = smartlist_create();
  250. start = strstr(*desc, "router ");
  251. if (!start) {
  252. log_fn(LOG_WARN, "no 'router' line found. This is not a descriptor.");
  253. return -1;
  254. }
  255. if ((end = strstr(start+6, "\nrouter "))) {
  256. ++end; /* Include NL. */
  257. } else if ((end = strstr(start+6, "\ndirectory-signature"))) {
  258. ++end;
  259. } else {
  260. end = start+strlen(start);
  261. }
  262. desc_len = end-start;
  263. cp = desc_tmp = tor_strndup(start, desc_len);
  264. /* Check: is the descriptor syntactically valid? */
  265. ri = router_parse_entry_from_string(cp, NULL);
  266. tor_free(desc_tmp);
  267. if (!ri) {
  268. log(LOG_WARN, "Couldn't parse descriptor");
  269. return -1;
  270. }
  271. /* Okay. Now check whether the fingerprint is recognized. */
  272. r = dirserv_router_fingerprint_is_known(ri);
  273. if(r<1) {
  274. if(r==0) {
  275. char fp[FINGERPRINT_LEN+1];
  276. log_fn(LOG_WARN, "Unknown nickname %s (%s:%d). Not adding.",
  277. ri->nickname, ri->address, ri->or_port);
  278. if (crypto_pk_get_fingerprint(ri->identity_pkey, fp) < 0) {
  279. log_fn(LOG_WARN, "Error computing fingerprint for %s", ri->nickname);
  280. } else {
  281. log_fn(LOG_WARN, "Fingerprint line: %s %s", ri->nickname, fp);
  282. }
  283. } else {
  284. log_fn(LOG_WARN, "Known nickname %s, wrong fingerprint. Not adding.", ri->nickname);
  285. }
  286. routerinfo_free(ri);
  287. *desc = end;
  288. return 0;
  289. }
  290. /* Is there too much clock skew? */
  291. now = time(NULL);
  292. if (ri->published_on > now+ROUTER_ALLOW_SKEW) {
  293. log_fn(LOG_WARN, "Publication time for nickname %s is too far in the future; possible clock skew. Not adding.", ri->nickname);
  294. routerinfo_free(ri);
  295. *desc = end;
  296. return 0;
  297. }
  298. if (ri->published_on < now-ROUTER_MAX_AGE) {
  299. log_fn(LOG_WARN, "Publication time for router with nickname %s is too far in the past. Not adding.", ri->nickname);
  300. routerinfo_free(ri);
  301. *desc = end;
  302. return 0;
  303. }
  304. /* Do we already have an entry for this router? */
  305. for (i = 0; i < smartlist_len(descriptor_list); ++i) {
  306. ent = smartlist_get(descriptor_list, i);
  307. if (!strcasecmp(ri->nickname, ent->nickname)) {
  308. found = i;
  309. break;
  310. }
  311. }
  312. if (found >= 0) {
  313. /* if so, decide whether to update it. */
  314. if (ent->published > ri->published_on) {
  315. /* We already have a newer descriptor */
  316. log_fn(LOG_INFO,"We already have a newer desc for nickname %s. Not adding.",ri->nickname);
  317. /* This isn't really an error; return success. */
  318. routerinfo_free(ri);
  319. *desc = end;
  320. return 1;
  321. }
  322. /* We don't have a newer one; we'll update this one. */
  323. log_fn(LOG_INFO,"Dirserv updating desc for nickname %s",ri->nickname);
  324. free_descriptor_entry(ent);
  325. smartlist_del_keeporder(descriptor_list, found);
  326. } else {
  327. /* Add at the end. */
  328. log_fn(LOG_INFO,"Dirserv adding desc for nickname %s",ri->nickname);
  329. }
  330. ent = tor_malloc(sizeof(descriptor_entry_t));
  331. ent->nickname = tor_strdup(ri->nickname);
  332. ent->published = ri->published_on;
  333. ent->desc_len = desc_len;
  334. ent->descriptor = tor_malloc(desc_len+1);
  335. strncpy(ent->descriptor, start, desc_len);
  336. ent->descriptor[desc_len] = '\0';
  337. ent->router = ri;
  338. smartlist_add(descriptor_list, ent);
  339. *desc = end;
  340. directory_set_dirty();
  341. return 1;
  342. }
  343. /** Remove all descriptors whose nicknames or fingerprints we don't
  344. * recognize. (Descriptors that used to be good can become
  345. * unrecognized when we reload the fingerprint list.)
  346. */
  347. static void
  348. directory_remove_unrecognized(void)
  349. {
  350. int i;
  351. descriptor_entry_t *ent;
  352. if (!descriptor_list)
  353. descriptor_list = smartlist_create();
  354. for (i = 0; i < smartlist_len(descriptor_list); ++i) {
  355. ent = smartlist_get(descriptor_list, i);
  356. if (dirserv_router_fingerprint_is_known(ent->router)<=0) {
  357. log(LOG_INFO, "Router %s is no longer recognized",
  358. ent->nickname);
  359. free_descriptor_entry(ent);
  360. smartlist_del(descriptor_list, i--);
  361. }
  362. }
  363. }
  364. /** Mark the directory as <b>dirty</b> -- when we're next asked for a
  365. * directory, we will rebuild it instead of reusing the most recently
  366. * generated one.
  367. */
  368. void
  369. directory_set_dirty()
  370. {
  371. the_directory_is_dirty = 1;
  372. runningrouters_is_dirty = 1;
  373. }
  374. /** Load all descriptors from a directory stored in the string
  375. * <b>dir</b>.
  376. */
  377. int
  378. dirserv_load_from_directory_string(const char *dir)
  379. {
  380. const char *cp = dir;
  381. while(1) {
  382. cp = strstr(cp, "\nrouter ");
  383. if (!cp) break;
  384. ++cp;
  385. if (dirserv_add_descriptor(&cp) < 0) {
  386. return -1;
  387. }
  388. --cp; /*Back up to newline.*/
  389. }
  390. return 0;
  391. }
  392. /** Set *<b>nicknames_out</b> to a comma-separated list of all the ORs that we
  393. * believe are currently running (because we have open connections to
  394. * them). Return 0 on success; -1 on error.
  395. */
  396. static int
  397. list_running_servers(char **nicknames_out)
  398. {
  399. connection_t **connection_array;
  400. int n_conns;
  401. connection_t *conn;
  402. char *cp;
  403. int i;
  404. int length;
  405. smartlist_t *nicknames;
  406. *nicknames_out = NULL;
  407. nicknames = smartlist_create();
  408. smartlist_add(nicknames, options.Nickname);
  409. get_connection_array(&connection_array, &n_conns);
  410. for (i = 0; i<n_conns; ++i) {
  411. conn = connection_array[i];
  412. if (conn->type != CONN_TYPE_OR || conn->state != OR_CONN_STATE_OPEN)
  413. continue; /* only list successfully handshaked OR's. */
  414. if(!conn->nickname) /* it's an OP, don't list it */
  415. continue;
  416. if (!router_nickname_is_approved(conn->nickname))
  417. continue; /* If we removed them from the approved list, don't list it.*/
  418. smartlist_add(nicknames, conn->nickname);
  419. }
  420. length = smartlist_len(nicknames) + 1; /* spaces + EOS + 1. */
  421. SMARTLIST_FOREACH(nicknames, char *, c, length += strlen(c));
  422. *nicknames_out = tor_malloc_zero(length);
  423. cp = *nicknames_out;
  424. for (i = 0; i<smartlist_len(nicknames); ++i) {
  425. if (i)
  426. strcat(cp, " ");
  427. strcat(cp, (char*)smartlist_get(nicknames,i)); /* can't overflow */
  428. while (*cp)
  429. ++cp;
  430. }
  431. smartlist_free(nicknames);
  432. return 0;
  433. }
  434. /** Remove any descriptors from the directory that are more than ROUTER_MAX_AGE
  435. * seconds old.
  436. */
  437. void
  438. dirserv_remove_old_servers(void)
  439. {
  440. int i;
  441. time_t cutoff;
  442. descriptor_entry_t *ent;
  443. if (!descriptor_list)
  444. descriptor_list = smartlist_create();
  445. cutoff = time(NULL) - ROUTER_MAX_AGE;
  446. for (i = 0; i < smartlist_len(descriptor_list); ++i) {
  447. ent = smartlist_get(descriptor_list, i);
  448. if (ent->published < cutoff) {
  449. /* descriptor_list[i] is too old. Remove it. */
  450. free_descriptor_entry(ent);
  451. smartlist_del(descriptor_list, i--);
  452. directory_set_dirty();
  453. }
  454. }
  455. }
  456. /** Dump all routers currently in the directory into the string
  457. * <b>s</b>, using at most <b>maxlen</b> characters, and signing the
  458. * directory with <b>private_key</b>. Return 0 on success, -1 on
  459. * failure.
  460. */
  461. int
  462. dirserv_dump_directory_to_string(char *s, unsigned int maxlen,
  463. crypto_pk_env_t *private_key)
  464. {
  465. char *cp, *eos;
  466. char digest[20];
  467. char signature[128];
  468. char published[33];
  469. time_t published_on;
  470. int i;
  471. eos = s+maxlen;
  472. if (!descriptor_list)
  473. descriptor_list = smartlist_create();
  474. if (list_running_servers(&cp))
  475. return -1;
  476. dirserv_remove_old_servers();
  477. published_on = time(NULL);
  478. strftime(published, 32, "%Y-%m-%d %H:%M:%S", gmtime(&published_on));
  479. snprintf(s, maxlen,
  480. "signed-directory\n"
  481. "published %s\n"
  482. "recommended-software %s\n"
  483. "running-routers %s\n\n",
  484. published, options.RecommendedVersions, cp);
  485. free(cp);
  486. i = strlen(s);
  487. cp = s+i;
  488. SMARTLIST_FOREACH(descriptor_list, descriptor_entry_t *, d,
  489. if (strlcat(s, d->descriptor, maxlen) >= maxlen)
  490. goto truncated);
  491. /* These multiple strlcat calls are inefficient, but dwarfed by the RSA
  492. signature.
  493. */
  494. if (strlcat(s, "directory-signature ", maxlen) >= maxlen)
  495. goto truncated;
  496. if (strlcat(s, options.Nickname, maxlen) >= maxlen)
  497. goto truncated;
  498. if (strlcat(s, "\n", maxlen) >= maxlen)
  499. goto truncated;
  500. if (router_get_dir_hash(s,digest)) {
  501. log_fn(LOG_WARN,"couldn't compute digest");
  502. return -1;
  503. }
  504. if (crypto_pk_private_sign(private_key, digest, 20, signature) < 0) {
  505. log_fn(LOG_WARN,"couldn't sign digest");
  506. return -1;
  507. }
  508. log(LOG_DEBUG,"generated directory digest begins with %s",hex_str(digest,4));
  509. if (strlcat(cp, "-----BEGIN SIGNATURE-----\n", maxlen) >= maxlen)
  510. goto truncated;
  511. i = strlen(s);
  512. cp = s+i;
  513. if (base64_encode(cp, maxlen-i, signature, 128) < 0) {
  514. log_fn(LOG_WARN,"couldn't base64-encode signature");
  515. return -1;
  516. }
  517. if (strlcat(s, "-----END SIGNATURE-----\n", maxlen) >= maxlen)
  518. goto truncated;
  519. return 0;
  520. truncated:
  521. log_fn(LOG_WARN,"tried to exceed string length.");
  522. return -1;
  523. }
  524. /** Most recently generated encoded signed directory. */
  525. static char *the_directory = NULL;
  526. static int the_directory_len = -1;
  527. static char *cached_directory = NULL;
  528. static time_t cached_directory_published = 0;
  529. static int cached_directory_len = -1;
  530. void dirserv_set_cached_directory(const char *directory, time_t when)
  531. {
  532. time_t now;
  533. char filename[512];
  534. if (!options.AuthoritativeDir)
  535. return;
  536. now = time(NULL);
  537. if (when>cached_directory_published &&
  538. when<now+ROUTER_ALLOW_SKEW) {
  539. tor_free(cached_directory);
  540. cached_directory = tor_strdup(directory);
  541. cached_directory_len = strlen(cached_directory);
  542. cached_directory_published = when;
  543. sprintf(filename,"%s/cached-directory", options.DataDirectory);
  544. if(write_str_to_file(filename,cached_directory) < 0) {
  545. log_fn(LOG_WARN, "Couldn't write cached directory to disk. Ignoring.");
  546. }
  547. }
  548. }
  549. /** Set *<b>directory</b> to the most recently generated encoded signed
  550. * directory, generating a new one as necessary. */
  551. size_t dirserv_get_directory(const char **directory)
  552. {
  553. char *new_directory;
  554. char filename[512];
  555. if (!options.AuthoritativeDir) {
  556. if (cached_directory) {
  557. *directory = cached_directory;
  558. return (size_t) cached_directory_len;
  559. } else {
  560. /* no directory yet retrieved */
  561. return 0;
  562. }
  563. }
  564. if (the_directory_is_dirty) {
  565. new_directory = tor_malloc(MAX_DIR_SIZE);
  566. if (dirserv_dump_directory_to_string(new_directory, MAX_DIR_SIZE,
  567. get_identity_key())) {
  568. log(LOG_WARN, "Error creating directory.");
  569. free(new_directory);
  570. return 0;
  571. }
  572. tor_free(the_directory);
  573. the_directory = new_directory;
  574. the_directory_len = strlen(the_directory);
  575. log_fn(LOG_INFO,"New directory (size %d):\n%s",the_directory_len,
  576. the_directory);
  577. the_directory_is_dirty = 0;
  578. /* Now read the directory we just made in order to update our own
  579. * router lists. This does more signature checking than is strictly
  580. * necessary, but safe is better than sorry. */
  581. new_directory = tor_strdup(the_directory);
  582. /* use a new copy of the dir, since get_dir_from_string scribbles on it */
  583. if (router_load_routerlist_from_directory(new_directory, get_identity_key())) {
  584. log_fn(LOG_ERR, "We just generated a directory we can't parse. Dying.");
  585. exit(0);
  586. }
  587. free(new_directory);
  588. sprintf(filename,"%s/cached-directory", options.DataDirectory);
  589. if(write_str_to_file(filename,the_directory) < 0) {
  590. log_fn(LOG_WARN, "Couldn't write cached directory to disk. Ignoring.");
  591. }
  592. } else {
  593. log(LOG_INFO,"Directory still clean, reusing.");
  594. }
  595. *directory = the_directory;
  596. return the_directory_len;
  597. }
  598. static char *runningrouters_string=NULL;
  599. static size_t runningrouters_len=0;
  600. /** Replace the current running-routers list with a newly generated one. */
  601. static int generate_runningrouters(crypto_pk_env_t *private_key)
  602. {
  603. char *s, *cp;
  604. char digest[DIGEST_LEN];
  605. char signature[PK_BYTES];
  606. int i, len;
  607. char published[33];
  608. time_t published_on;
  609. len = 1024+MAX_NICKNAME_LEN*smartlist_len(descriptor_list);
  610. s = tor_malloc_zero(len);
  611. if (list_running_servers(&cp))
  612. return -1;
  613. published_on = time(NULL);
  614. strftime(published, 32, "%Y-%m-%d %H:%M:%S", gmtime(&published_on));
  615. sprintf(s, "network-status\n"
  616. "published %s\n"
  617. "running-routers %s\n"
  618. "directory-signature %s\n"
  619. "-----BEGIN SIGNATURE-----\n",
  620. published, cp, options.Nickname);
  621. free(cp);
  622. if (router_get_runningrouters_hash(s,digest)) {
  623. log_fn(LOG_WARN,"couldn't compute digest");
  624. return -1;
  625. }
  626. if (crypto_pk_private_sign(private_key, digest, 20, signature) < 0) {
  627. log_fn(LOG_WARN,"couldn't sign digest");
  628. return -1;
  629. }
  630. i = strlen(s);
  631. cp = s+i;
  632. if (base64_encode(cp, len-i, signature, 128) < 0) {
  633. log_fn(LOG_WARN,"couldn't base64-encode signature");
  634. return -1;
  635. }
  636. if (strlcat(s, "-----END SIGNATURE-----\n", len) >= len) {
  637. return -1;
  638. }
  639. tor_free(runningrouters_string);
  640. runningrouters_string = s;
  641. runningrouters_len = strlen(s);
  642. runningrouters_is_dirty = 0;
  643. return 0;
  644. }
  645. /** Set *<b>rr</b> to the most recently generated encoded signed
  646. * running-routers list, generating a new one as necessary. */
  647. size_t dirserv_get_runningrouters(const char **rr)
  648. {
  649. if (runningrouters_is_dirty) {
  650. if(generate_runningrouters(get_identity_key())) {
  651. log_fn(LOG_ERR, "Couldn't generate running-routers list?");
  652. return -1;
  653. }
  654. }
  655. *rr = runningrouters_string;
  656. return runningrouters_len;
  657. }
  658. /*
  659. Local Variables:
  660. mode:c
  661. indent-tabs-mode:nil
  662. c-basic-offset:2
  663. End:
  664. */