test_microdesc.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. /* Copyright (c) 2010-2013, The Tor Project, Inc. */
  2. /* See LICENSE for licensing information */
  3. #include "orconfig.h"
  4. #include "or.h"
  5. #include "config.h"
  6. #include "dirvote.h"
  7. #include "microdesc.h"
  8. #include "routerlist.h"
  9. #include "routerparse.h"
  10. #include "test.h"
  11. #ifdef _WIN32
  12. /* For mkdir() */
  13. #include <direct.h>
  14. #else
  15. #include <dirent.h>
  16. #endif
  17. static const char test_md1[] =
  18. "onion-key\n"
  19. "-----BEGIN RSA PUBLIC KEY-----\n"
  20. "MIGJAoGBAMjlHH/daN43cSVRaHBwgUfnszzAhg98EvivJ9Qxfv51mvQUxPjQ07es\n"
  21. "gV/3n8fyh3Kqr/ehi9jxkdgSRfSnmF7giaHL1SLZ29kA7KtST+pBvmTpDtHa3ykX\n"
  22. "Xorc7hJvIyTZoc1HU+5XSynj3gsBE5IGK1ZRzrNS688LnuZMVp1tAgMBAAE=\n"
  23. "-----END RSA PUBLIC KEY-----\n";
  24. static const char test_md2[] =
  25. "onion-key\n"
  26. "-----BEGIN RSA PUBLIC KEY-----\n"
  27. "MIGJAoGBAMIixIowh2DyPmDNMDwBX2DHcYcqdcH1zdIQJZkyV6c6rQHnvbcaDoSg\n"
  28. "jgFSLJKpnGmh71FVRqep+yVB0zI1JY43kuEnXry2HbZCD9UDo3d3n7t015X5S7ON\n"
  29. "bSSYtQGPwOr6Epf96IF6DoQxy4iDnPUAlejuhAG51s1y6/rZQ3zxAgMBAAE=\n"
  30. "-----END RSA PUBLIC KEY-----\n";
  31. static const char test_md3[] =
  32. "@last-listed 2009-06-22\n"
  33. "onion-key\n"
  34. "-----BEGIN RSA PUBLIC KEY-----\n"
  35. "MIGJAoGBAMH3340d4ENNGrqx7UxT+lB7x6DNUKOdPEOn4teceE11xlMyZ9TPv41c\n"
  36. "qj2fRZzfxlc88G/tmiaHshmdtEpklZ740OFqaaJVj4LjPMKFNE+J7Xc1142BE9Ci\n"
  37. "KgsbjGYe2RY261aADRWLetJ8T9QDMm+JngL4288hc8pq1uB/3TAbAgMBAAE=\n"
  38. "-----END RSA PUBLIC KEY-----\n"
  39. "p accept 1-700,800-1000\n"
  40. "family nodeX nodeY nodeZ\n";
  41. static void
  42. test_md_cache(void *data)
  43. {
  44. or_options_t *options = NULL;
  45. microdesc_cache_t *mc = NULL ;
  46. smartlist_t *added = NULL, *wanted = NULL;
  47. microdesc_t *md1, *md2, *md3;
  48. char d1[DIGEST256_LEN], d2[DIGEST256_LEN], d3[DIGEST256_LEN];
  49. const char *test_md3_noannotation = strchr(test_md3, '\n')+1;
  50. time_t time1, time2, time3;
  51. char *fn = NULL, *s = NULL;
  52. (void)data;
  53. options = get_options_mutable();
  54. tt_assert(options);
  55. time1 = time(NULL);
  56. time2 = time(NULL) - 2*24*60*60;
  57. time3 = time(NULL) - 15*24*60*60;
  58. /* Possibly, turn this into a test setup/cleanup pair */
  59. tor_free(options->DataDirectory);
  60. options->DataDirectory = tor_strdup(get_fname("md_datadir_test"));
  61. #ifdef _WIN32
  62. tt_int_op(0, ==, mkdir(options->DataDirectory));
  63. #else
  64. tt_int_op(0, ==, mkdir(options->DataDirectory, 0700));
  65. #endif
  66. tt_assert(!strcmpstart(test_md3_noannotation, "onion-key"));
  67. crypto_digest256(d1, test_md1, strlen(test_md1), DIGEST_SHA256);
  68. crypto_digest256(d2, test_md2, strlen(test_md1), DIGEST_SHA256);
  69. crypto_digest256(d3, test_md3_noannotation, strlen(test_md3_noannotation),
  70. DIGEST_SHA256);
  71. mc = get_microdesc_cache();
  72. added = microdescs_add_to_cache(mc, test_md1, NULL, SAVED_NOWHERE, 0,
  73. time1, NULL);
  74. tt_int_op(1, ==, smartlist_len(added));
  75. md1 = smartlist_get(added, 0);
  76. smartlist_free(added);
  77. added = NULL;
  78. wanted = smartlist_new();
  79. added = microdescs_add_to_cache(mc, test_md2, NULL, SAVED_NOWHERE, 0,
  80. time2, wanted);
  81. /* Should fail, since we didn't list test_md2's digest in wanted */
  82. tt_int_op(0, ==, smartlist_len(added));
  83. smartlist_free(added);
  84. added = NULL;
  85. smartlist_add(wanted, tor_memdup(d2, DIGEST256_LEN));
  86. smartlist_add(wanted, tor_memdup(d3, DIGEST256_LEN));
  87. added = microdescs_add_to_cache(mc, test_md2, NULL, SAVED_NOWHERE, 0,
  88. time2, wanted);
  89. /* Now it can work. md2 should have been added */
  90. tt_int_op(1, ==, smartlist_len(added));
  91. md2 = smartlist_get(added, 0);
  92. /* And it should have gotten removed from 'wanted' */
  93. tt_int_op(smartlist_len(wanted), ==, 1);
  94. test_mem_op(smartlist_get(wanted, 0), ==, d3, DIGEST256_LEN);
  95. smartlist_free(added);
  96. added = NULL;
  97. added = microdescs_add_to_cache(mc, test_md3, NULL,
  98. SAVED_NOWHERE, 0, -1, NULL);
  99. /* Must fail, since SAVED_NOWHERE precludes annotations */
  100. tt_int_op(0, ==, smartlist_len(added));
  101. smartlist_free(added);
  102. added = NULL;
  103. added = microdescs_add_to_cache(mc, test_md3_noannotation, NULL,
  104. SAVED_NOWHERE, 0, time3, NULL);
  105. /* Now it can work */
  106. tt_int_op(1, ==, smartlist_len(added));
  107. md3 = smartlist_get(added, 0);
  108. smartlist_free(added);
  109. added = NULL;
  110. /* Okay. We added 1...3. Let's poke them to see how they look, and make
  111. * sure they're really in the journal. */
  112. tt_ptr_op(md1, ==, microdesc_cache_lookup_by_digest256(mc, d1));
  113. tt_ptr_op(md2, ==, microdesc_cache_lookup_by_digest256(mc, d2));
  114. tt_ptr_op(md3, ==, microdesc_cache_lookup_by_digest256(mc, d3));
  115. tt_int_op(md1->last_listed, ==, time1);
  116. tt_int_op(md2->last_listed, ==, time2);
  117. tt_int_op(md3->last_listed, ==, time3);
  118. tt_int_op(md1->saved_location, ==, SAVED_IN_JOURNAL);
  119. tt_int_op(md2->saved_location, ==, SAVED_IN_JOURNAL);
  120. tt_int_op(md3->saved_location, ==, SAVED_IN_JOURNAL);
  121. tt_int_op(md1->bodylen, ==, strlen(test_md1));
  122. tt_int_op(md2->bodylen, ==, strlen(test_md2));
  123. tt_int_op(md3->bodylen, ==, strlen(test_md3_noannotation));
  124. test_mem_op(md1->body, ==, test_md1, strlen(test_md1));
  125. test_mem_op(md2->body, ==, test_md2, strlen(test_md2));
  126. test_mem_op(md3->body, ==, test_md3_noannotation,
  127. strlen(test_md3_noannotation));
  128. tor_asprintf(&fn, "%s"PATH_SEPARATOR"cached-microdescs.new",
  129. options->DataDirectory);
  130. s = read_file_to_str(fn, RFTS_BIN, NULL);
  131. tt_assert(s);
  132. test_mem_op(md1->body, ==, s + md1->off, md1->bodylen);
  133. test_mem_op(md2->body, ==, s + md2->off, md2->bodylen);
  134. test_mem_op(md3->body, ==, s + md3->off, md3->bodylen);
  135. tt_ptr_op(md1->family, ==, NULL);
  136. tt_ptr_op(md3->family, !=, NULL);
  137. tt_int_op(smartlist_len(md3->family), ==, 3);
  138. tt_str_op(smartlist_get(md3->family, 0), ==, "nodeX");
  139. /* Now rebuild the cache! */
  140. tt_int_op(microdesc_cache_rebuild(mc, 1), ==, 0);
  141. tt_int_op(md1->saved_location, ==, SAVED_IN_CACHE);
  142. tt_int_op(md2->saved_location, ==, SAVED_IN_CACHE);
  143. tt_int_op(md3->saved_location, ==, SAVED_IN_CACHE);
  144. /* The journal should be empty now */
  145. tor_free(s);
  146. s = read_file_to_str(fn, RFTS_BIN, NULL);
  147. tt_str_op(s, ==, "");
  148. tor_free(s);
  149. tor_free(fn);
  150. /* read the cache. */
  151. tor_asprintf(&fn, "%s"PATH_SEPARATOR"cached-microdescs",
  152. options->DataDirectory);
  153. s = read_file_to_str(fn, RFTS_BIN, NULL);
  154. test_mem_op(md1->body, ==, s + md1->off, strlen(test_md1));
  155. test_mem_op(md2->body, ==, s + md2->off, strlen(test_md2));
  156. test_mem_op(md3->body, ==, s + md3->off, strlen(test_md3_noannotation));
  157. /* Okay, now we are going to forget about the cache entirely, and reload it
  158. * from the disk. */
  159. microdesc_free_all();
  160. mc = get_microdesc_cache();
  161. md1 = microdesc_cache_lookup_by_digest256(mc, d1);
  162. md2 = microdesc_cache_lookup_by_digest256(mc, d2);
  163. md3 = microdesc_cache_lookup_by_digest256(mc, d3);
  164. test_assert(md1);
  165. test_assert(md2);
  166. test_assert(md3);
  167. test_mem_op(md1->body, ==, s + md1->off, strlen(test_md1));
  168. test_mem_op(md2->body, ==, s + md2->off, strlen(test_md2));
  169. test_mem_op(md3->body, ==, s + md3->off, strlen(test_md3_noannotation));
  170. tt_int_op(md1->last_listed, ==, time1);
  171. tt_int_op(md2->last_listed, ==, time2);
  172. tt_int_op(md3->last_listed, ==, time3);
  173. /* Okay, now we are going to clear out everything older than a week old.
  174. * In practice, that means md3 */
  175. microdesc_cache_clean(mc, time(NULL)-7*24*60*60, 1/*force*/);
  176. tt_ptr_op(md1, ==, microdesc_cache_lookup_by_digest256(mc, d1));
  177. tt_ptr_op(md2, ==, microdesc_cache_lookup_by_digest256(mc, d2));
  178. tt_ptr_op(NULL, ==, microdesc_cache_lookup_by_digest256(mc, d3));
  179. md3 = NULL; /* it's history now! */
  180. /* rebuild again, make sure it stays gone. */
  181. tt_int_op(microdesc_cache_rebuild(mc, 1), ==, 0);
  182. tt_ptr_op(md1, ==, microdesc_cache_lookup_by_digest256(mc, d1));
  183. tt_ptr_op(md2, ==, microdesc_cache_lookup_by_digest256(mc, d2));
  184. tt_ptr_op(NULL, ==, microdesc_cache_lookup_by_digest256(mc, d3));
  185. /* Re-add md3, and make sure we can rebuild the cache. */
  186. added = microdescs_add_to_cache(mc, test_md3_noannotation, NULL,
  187. SAVED_NOWHERE, 0, time3, NULL);
  188. tt_int_op(1, ==, smartlist_len(added));
  189. md3 = smartlist_get(added, 0);
  190. smartlist_free(added);
  191. added = NULL;
  192. tt_int_op(md1->saved_location, ==, SAVED_IN_CACHE);
  193. tt_int_op(md2->saved_location, ==, SAVED_IN_CACHE);
  194. tt_int_op(md3->saved_location, ==, SAVED_IN_JOURNAL);
  195. tt_int_op(microdesc_cache_rebuild(mc, 1), ==, 0);
  196. tt_int_op(md3->saved_location, ==, SAVED_IN_CACHE);
  197. done:
  198. if (options)
  199. tor_free(options->DataDirectory);
  200. microdesc_free_all();
  201. smartlist_free(added);
  202. if (wanted)
  203. SMARTLIST_FOREACH(wanted, char *, cp, tor_free(cp));
  204. smartlist_free(wanted);
  205. tor_free(s);
  206. tor_free(fn);
  207. }
  208. static const char truncated_md[] =
  209. "@last-listed 2013-08-08 19:02:59\n"
  210. "onion-key\n"
  211. "-----BEGIN RSA PUBLIC KEY-----\n"
  212. "MIGJAoGBAM91vLFNaM+gGhnRIdz2Cm/Kl7Xz0cOobIdVzhS3cKUJfk867hCuTipS\n"
  213. "NveLBzNopvgXKruAAzEj3cACxk6Q8lv5UWOGCD1UolkgsWSE62RBjap44g+oc9J1\n"
  214. "RI9968xOTZw0VaBQg9giEILNXl0djoikQ+5tQRUvLDDa67gpa5Q1AgMBAAE=\n"
  215. "-----END RSA PUBLIC KEY-----\n"
  216. "family @\n";
  217. static void
  218. test_md_cache_broken(void *data)
  219. {
  220. or_options_t *options;
  221. char *fn=NULL;
  222. microdesc_cache_t *mc = NULL;
  223. (void)data;
  224. options = get_options_mutable();
  225. tt_assert(options);
  226. tor_free(options->DataDirectory);
  227. options->DataDirectory = tor_strdup(get_fname("md_datadir_test2"));
  228. #ifdef _WIN32
  229. tt_int_op(0, ==, mkdir(options->DataDirectory));
  230. #else
  231. tt_int_op(0, ==, mkdir(options->DataDirectory, 0700));
  232. #endif
  233. tor_asprintf(&fn, "%s"PATH_SEPARATOR"cached-microdescs",
  234. options->DataDirectory);
  235. write_str_to_file(fn, truncated_md, 1);
  236. mc = get_microdesc_cache();
  237. tt_assert(mc);
  238. done:
  239. if (options)
  240. tor_free(options->DataDirectory);
  241. tor_free(fn);
  242. microdesc_free_all();
  243. }
  244. /* Generated by chutney. */
  245. static const char test_ri[] =
  246. "router test005r 127.0.0.1 5005 0 7005\n"
  247. "platform Tor 0.2.5.4-alpha-dev on Linux\n"
  248. "protocols Link 1 2 Circuit 1\n"
  249. "published 2014-05-06 22:57:55\n"
  250. "fingerprint 09DE 3BA2 48C2 1C3F 3760 6CD3 8460 43A6 D5EC F59E\n"
  251. "uptime 0\n"
  252. "bandwidth 1073741824 1073741824 0\n"
  253. "extra-info-digest 361F9428F9FA4DD854C03DDBCC159D0D9FA996C9\n"
  254. "onion-key\n"
  255. "-----BEGIN RSA PUBLIC KEY-----\n"
  256. "MIGJAoGBANBJz8Vldl12aFeSMPLiA4nOetLDN0oxU8bB1SDhO7Uu2zdWYVYAF5J0\n"
  257. "st7WvrVy/jA9v/fsezNAPskBanecHRSkdMTpkcgRPMHE7CTGEwIy1Yp1X4bPgDlC\n"
  258. "VCnbs5Pcts5HnWEYNK7qHDAUn+IlmjOO+pTUY8uyq+GQVz6H9wFlAgMBAAE=\n"
  259. "-----END RSA PUBLIC KEY-----\n"
  260. "signing-key\n"
  261. "-----BEGIN RSA PUBLIC KEY-----\n"
  262. "MIGJAoGBANbGUC4802Ke6C3nOVxN0U0HhIRrs32cQFEL4v+UUMJPgjbistHBvOax\n"
  263. "CWVR/sMXM2kKJeGThJ9ZUs2p9dDG4WHPUXgkMqzTTEeeFa7pQKU0brgbmLaJq0Pi\n"
  264. "mxmqC5RkTHa5bQvq6QlSFprAEoovV27cWqBM9jVdV9hyc//6kwPzAgMBAAE=\n"
  265. "-----END RSA PUBLIC KEY-----\n"
  266. "hidden-service-dir\n"
  267. "ntor-onion-key Gg73xH7+kTfT6bi1uNVx9gwQdQas9pROIfmc4NpAdC4=\n"
  268. "reject *:25\n"
  269. "reject *:119\n"
  270. "reject *:135-139\n"
  271. "reject *:445\n"
  272. "reject *:563\n"
  273. "reject *:1214\n"
  274. "reject *:4661-4666\n"
  275. "reject *:6346-6429\n"
  276. "reject *:6699\n"
  277. "reject *:6881-6999\n"
  278. "accept *:*\n"
  279. "router-signature\n"
  280. "-----BEGIN SIGNATURE-----\n"
  281. "ImzX5PF2vRCrG1YzGToyjoxYhgh1vtHEDjmP+tIS/iil1DSnHZNpHSuHp0L1jE9S\n"
  282. "yZyrtKaqpBE/aecAM3j4CWCn/ipnAAQkHcyRLin1bYvqBtRzyopVCRlUhF+uWrLq\n"
  283. "t0xkIE39ss/EwmQr7iIgkdVH4oRIMsjYnFFJBG26nYY=\n"
  284. "-----END SIGNATURE-----\n";
  285. static const char test_md_8[] =
  286. "onion-key\n"
  287. "-----BEGIN RSA PUBLIC KEY-----\n"
  288. "MIGJAoGBANBJz8Vldl12aFeSMPLiA4nOetLDN0oxU8bB1SDhO7Uu2zdWYVYAF5J0\n"
  289. "st7WvrVy/jA9v/fsezNAPskBanecHRSkdMTpkcgRPMHE7CTGEwIy1Yp1X4bPgDlC\n"
  290. "VCnbs5Pcts5HnWEYNK7qHDAUn+IlmjOO+pTUY8uyq+GQVz6H9wFlAgMBAAE=\n"
  291. "-----END RSA PUBLIC KEY-----\n"
  292. "p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999\n";
  293. static const char test_md_16[] =
  294. "onion-key\n"
  295. "-----BEGIN RSA PUBLIC KEY-----\n"
  296. "MIGJAoGBANBJz8Vldl12aFeSMPLiA4nOetLDN0oxU8bB1SDhO7Uu2zdWYVYAF5J0\n"
  297. "st7WvrVy/jA9v/fsezNAPskBanecHRSkdMTpkcgRPMHE7CTGEwIy1Yp1X4bPgDlC\n"
  298. "VCnbs5Pcts5HnWEYNK7qHDAUn+IlmjOO+pTUY8uyq+GQVz6H9wFlAgMBAAE=\n"
  299. "-----END RSA PUBLIC KEY-----\n"
  300. "ntor-onion-key Gg73xH7+kTfT6bi1uNVx9gwQdQas9pROIfmc4NpAdC4=\n"
  301. "p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999\n";
  302. static const char test_md_18[] =
  303. "onion-key\n"
  304. "-----BEGIN RSA PUBLIC KEY-----\n"
  305. "MIGJAoGBANBJz8Vldl12aFeSMPLiA4nOetLDN0oxU8bB1SDhO7Uu2zdWYVYAF5J0\n"
  306. "st7WvrVy/jA9v/fsezNAPskBanecHRSkdMTpkcgRPMHE7CTGEwIy1Yp1X4bPgDlC\n"
  307. "VCnbs5Pcts5HnWEYNK7qHDAUn+IlmjOO+pTUY8uyq+GQVz6H9wFlAgMBAAE=\n"
  308. "-----END RSA PUBLIC KEY-----\n"
  309. "ntor-onion-key Gg73xH7+kTfT6bi1uNVx9gwQdQas9pROIfmc4NpAdC4=\n"
  310. "p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999\n"
  311. "id rsa1024 Cd47okjCHD83YGzThGBDptXs9Z4\n";
  312. static void
  313. test_md_generate(void *arg)
  314. {
  315. routerinfo_t *ri;
  316. microdesc_t *md = NULL;
  317. (void)arg;
  318. ri = router_parse_entry_from_string(test_ri, NULL, 0, 0, NULL);
  319. tt_assert(ri);
  320. md = dirvote_create_microdescriptor(ri, 8);
  321. tt_str_op(md->body, ==, test_md_8);
  322. /* XXXX test family lines. */
  323. /* XXXX test method 14 for A lines. */
  324. /* XXXX test method 15 for P6 lines. */
  325. microdesc_free(md);
  326. md = NULL;
  327. md = dirvote_create_microdescriptor(ri, 16);
  328. tt_str_op(md->body, ==, test_md_16);
  329. microdesc_free(md);
  330. md = NULL;
  331. md = dirvote_create_microdescriptor(ri, 18);
  332. tt_str_op(md->body, ==, test_md_18);
  333. done:
  334. microdesc_free(md);
  335. routerinfo_free(ri);
  336. }
  337. struct testcase_t microdesc_tests[] = {
  338. { "cache", test_md_cache, TT_FORK, NULL, NULL },
  339. { "broken_cache", test_md_cache_broken, TT_FORK, NULL, NULL },
  340. { "generate", test_md_generate, 0, NULL, NULL },
  341. END_OF_TESTCASES
  342. };