Beispiel #1
0
static void
test_md_corrupt_desc(void *arg)
{
  char *cp = NULL;
  smartlist_t *sl = NULL;
  (void) arg;

  sl = microdescs_add_to_cache(get_microdesc_cache(),
                               "@last-listed 2015-06-22 10:00:00\n"
                               "onion-k\n",
                               NULL, SAVED_IN_JOURNAL, 0, time(NULL), NULL);
  tt_int_op(smartlist_len(sl), OP_EQ, 0);
  smartlist_free(sl);

  sl = microdescs_add_to_cache(get_microdesc_cache(),
                               "@last-listed 2015-06-22 10:00:00\n"
                               "wiggly\n",
                               NULL, SAVED_IN_JOURNAL, 0, time(NULL), NULL);
  tt_int_op(smartlist_len(sl), OP_EQ, 0);
  smartlist_free(sl);

  tor_asprintf(&cp, "%s\n%s", test_md1, "@foobar\nonion-wobble\n");

  sl = microdescs_add_to_cache(get_microdesc_cache(),
                               cp, cp+strlen(cp),
                               SAVED_IN_JOURNAL, 0, time(NULL), NULL);
  tt_int_op(smartlist_len(sl), OP_EQ, 0);

 done:
  tor_free(cp);
  smartlist_free(sl);
}
Beispiel #2
0
static void
test_md_cache_broken(void *data)
{
  or_options_t *options;
  char *fn=NULL;
  microdesc_cache_t *mc = NULL;

  (void)data;

  options = get_options_mutable();
  tt_assert(options);
  tor_free(options->CacheDirectory);
  options->CacheDirectory = tor_strdup(get_fname("md_datadir_test2"));

#ifdef _WIN32
  tt_int_op(0, OP_EQ, mkdir(options->CacheDirectory));
#else
  tt_int_op(0, OP_EQ, mkdir(options->CacheDirectory, 0700));
#endif

  tor_asprintf(&fn, "%s"PATH_SEPARATOR"cached-microdescs",
               options->CacheDirectory);

  write_str_to_file(fn, truncated_md, 1);

  mc = get_microdesc_cache();
  tt_assert(mc);

 done:
  if (options)
    tor_free(options->CacheDirectory);
  tor_free(fn);
  microdesc_free_all();
}
static void
test_md_cache(void *data)
{
  or_options_t *options = NULL;
  microdesc_cache_t *mc = NULL ;
  smartlist_t *added = NULL, *wanted = NULL;
  microdesc_t *md1, *md2, *md3;
  char d1[DIGEST256_LEN], d2[DIGEST256_LEN], d3[DIGEST256_LEN];
  const char *test_md3_noannotation = strchr(test_md3, '\n')+1;
  time_t time1, time2, time3;
  char *fn = NULL, *s = NULL;
  (void)data;

  options = get_options_mutable();
  tt_assert(options);

  time1 = time(NULL);
  time2 = time(NULL) - 2*24*60*60;
  time3 = time(NULL) - 15*24*60*60;

  /* Possibly, turn this into a test setup/cleanup pair */
  tor_free(options->DataDirectory);
  options->DataDirectory = tor_strdup(get_fname("md_datadir_test"));
#ifdef _WIN32
  tt_int_op(0, ==, mkdir(options->DataDirectory));
#else
  tt_int_op(0, ==, mkdir(options->DataDirectory, 0700));
#endif

  tt_assert(!strcmpstart(test_md3_noannotation, "onion-key"));

  crypto_digest256(d1, test_md1, strlen(test_md1), DIGEST_SHA256);
  crypto_digest256(d2, test_md2, strlen(test_md1), DIGEST_SHA256);
  crypto_digest256(d3, test_md3_noannotation, strlen(test_md3_noannotation),
                   DIGEST_SHA256);

  mc = get_microdesc_cache();

  added = microdescs_add_to_cache(mc, test_md1, NULL, SAVED_NOWHERE, 0,
                                  time1, NULL);
  tt_int_op(1, ==, smartlist_len(added));
  md1 = smartlist_get(added, 0);
  smartlist_free(added);
  added = NULL;

  wanted = smartlist_new();
  added = microdescs_add_to_cache(mc, test_md2, NULL, SAVED_NOWHERE, 0,
                                  time2, wanted);
  /* Should fail, since we didn't list test_md2's digest in wanted */
  tt_int_op(0, ==, smartlist_len(added));
  smartlist_free(added);
  added = NULL;

  smartlist_add(wanted, tor_memdup(d2, DIGEST256_LEN));
  smartlist_add(wanted, tor_memdup(d3, DIGEST256_LEN));
  added = microdescs_add_to_cache(mc, test_md2, NULL, SAVED_NOWHERE, 0,
                                  time2, wanted);
  /* Now it can work. md2 should have been added */
  tt_int_op(1, ==, smartlist_len(added));
  md2 = smartlist_get(added, 0);
  /* And it should have gotten removed from 'wanted' */
  tt_int_op(smartlist_len(wanted), ==, 1);
  test_mem_op(smartlist_get(wanted, 0), ==, d3, DIGEST256_LEN);
  smartlist_free(added);
  added = NULL;

  added = microdescs_add_to_cache(mc, test_md3, NULL,
                                  SAVED_NOWHERE, 0, -1, NULL);
  /* Must fail, since SAVED_NOWHERE precludes annotations */
  tt_int_op(0, ==, smartlist_len(added));
  smartlist_free(added);
  added = NULL;

  added = microdescs_add_to_cache(mc, test_md3_noannotation, NULL,
                                  SAVED_NOWHERE, 0, time3, NULL);
  /* Now it can work */
  tt_int_op(1, ==, smartlist_len(added));
  md3 = smartlist_get(added, 0);
  smartlist_free(added);
  added = NULL;

  /* Okay.  We added 1...3.  Let's poke them to see how they look, and make
   * sure they're really in the journal. */
  tt_ptr_op(md1, ==, microdesc_cache_lookup_by_digest256(mc, d1));
  tt_ptr_op(md2, ==, microdesc_cache_lookup_by_digest256(mc, d2));
  tt_ptr_op(md3, ==, microdesc_cache_lookup_by_digest256(mc, d3));

  tt_int_op(md1->last_listed, ==, time1);
  tt_int_op(md2->last_listed, ==, time2);
  tt_int_op(md3->last_listed, ==, time3);

  tt_int_op(md1->saved_location, ==, SAVED_IN_JOURNAL);
  tt_int_op(md2->saved_location, ==, SAVED_IN_JOURNAL);
  tt_int_op(md3->saved_location, ==, SAVED_IN_JOURNAL);

  tt_int_op(md1->bodylen, ==, strlen(test_md1));
  tt_int_op(md2->bodylen, ==, strlen(test_md2));
  tt_int_op(md3->bodylen, ==, strlen(test_md3_noannotation));
  test_mem_op(md1->body, ==, test_md1, strlen(test_md1));
  test_mem_op(md2->body, ==, test_md2, strlen(test_md2));
  test_mem_op(md3->body, ==, test_md3_noannotation,
              strlen(test_md3_noannotation));

  tor_asprintf(&fn, "%s"PATH_SEPARATOR"cached-microdescs.new",
               options->DataDirectory);
  s = read_file_to_str(fn, RFTS_BIN, NULL);
  tt_assert(s);
  test_mem_op(md1->body, ==, s + md1->off, md1->bodylen);
  test_mem_op(md2->body, ==, s + md2->off, md2->bodylen);
  test_mem_op(md3->body, ==, s + md3->off, md3->bodylen);

  tt_ptr_op(md1->family, ==, NULL);
  tt_ptr_op(md3->family, !=, NULL);
  tt_int_op(smartlist_len(md3->family), ==, 3);
  tt_str_op(smartlist_get(md3->family, 0), ==, "nodeX");

  /* Now rebuild the cache! */
  tt_int_op(microdesc_cache_rebuild(mc, 1), ==, 0);

  tt_int_op(md1->saved_location, ==, SAVED_IN_CACHE);
  tt_int_op(md2->saved_location, ==, SAVED_IN_CACHE);
  tt_int_op(md3->saved_location, ==, SAVED_IN_CACHE);

  /* The journal should be empty now */
  tor_free(s);
  s = read_file_to_str(fn, RFTS_BIN, NULL);
  tt_str_op(s, ==, "");
  tor_free(s);
  tor_free(fn);

  /* read the cache. */
  tor_asprintf(&fn, "%s"PATH_SEPARATOR"cached-microdescs",
               options->DataDirectory);
  s = read_file_to_str(fn, RFTS_BIN, NULL);
  test_mem_op(md1->body, ==, s + md1->off, strlen(test_md1));
  test_mem_op(md2->body, ==, s + md2->off, strlen(test_md2));
  test_mem_op(md3->body, ==, s + md3->off, strlen(test_md3_noannotation));

  /* Okay, now we are going to forget about the cache entirely, and reload it
   * from the disk. */
  microdesc_free_all();
  mc = get_microdesc_cache();
  md1 = microdesc_cache_lookup_by_digest256(mc, d1);
  md2 = microdesc_cache_lookup_by_digest256(mc, d2);
  md3 = microdesc_cache_lookup_by_digest256(mc, d3);
  test_assert(md1);
  test_assert(md2);
  test_assert(md3);
  test_mem_op(md1->body, ==, s + md1->off, strlen(test_md1));
  test_mem_op(md2->body, ==, s + md2->off, strlen(test_md2));
  test_mem_op(md3->body, ==, s + md3->off, strlen(test_md3_noannotation));

  tt_int_op(md1->last_listed, ==, time1);
  tt_int_op(md2->last_listed, ==, time2);
  tt_int_op(md3->last_listed, ==, time3);

  /* Okay, now we are going to clear out everything older than a week old.
   * In practice, that means md3 */
  microdesc_cache_clean(mc, time(NULL)-7*24*60*60, 1/*force*/);
  tt_ptr_op(md1, ==, microdesc_cache_lookup_by_digest256(mc, d1));
  tt_ptr_op(md2, ==, microdesc_cache_lookup_by_digest256(mc, d2));
  tt_ptr_op(NULL, ==, microdesc_cache_lookup_by_digest256(mc, d3));
  md3 = NULL; /* it's history now! */

  /* rebuild again, make sure it stays gone. */
  microdesc_cache_rebuild(mc, 1);
  tt_ptr_op(md1, ==, microdesc_cache_lookup_by_digest256(mc, d1));
  tt_ptr_op(md2, ==, microdesc_cache_lookup_by_digest256(mc, d2));
  tt_ptr_op(NULL, ==, microdesc_cache_lookup_by_digest256(mc, d3));

 done:
  if (options)
    tor_free(options->DataDirectory);
  microdesc_free_all();

  smartlist_free(added);
  if (wanted)
    SMARTLIST_FOREACH(wanted, char *, cp, tor_free(cp));
  smartlist_free(wanted);
  tor_free(s);
  tor_free(fn);
}
Beispiel #4
0
static void
test_md_reject_cache(void *arg)
{
  (void) arg;
  microdesc_cache_t *mc = NULL ;
  smartlist_t *added = NULL, *wanted = smartlist_new();
  or_options_t *options = get_options_mutable();
  char buf[DIGEST256_LEN];

  tor_free(options->CacheDirectory);
  options->CacheDirectory = tor_strdup(get_fname("md_datadir_test_rej"));
  mock_rgsbd_val_a = tor_malloc_zero(sizeof(routerstatus_t));
  mock_rgsbd_val_b = tor_malloc_zero(sizeof(routerstatus_t));
  mock_ns_val = tor_malloc_zero(sizeof(networkstatus_t));

  mock_ns_val->valid_after = time(NULL) - 86400;
  mock_ns_val->valid_until = time(NULL) + 86400;
  mock_ns_val->flavor = FLAV_MICRODESC;

#ifdef _WIN32
  tt_int_op(0, OP_EQ, mkdir(options->CacheDirectory));
#else
  tt_int_op(0, OP_EQ, mkdir(options->CacheDirectory, 0700));
#endif

  MOCK(router_get_mutable_consensus_status_by_descriptor_digest,
       mock_router_get_status_by_digest);
  MOCK(networkstatus_get_latest_consensus_by_flavor, mock_ns_get_by_flavor);

  mc = get_microdesc_cache();
#define ADD(hex)                                                        \
  do {                                                                  \
    tt_int_op(sizeof(buf),OP_EQ,base16_decode(buf,sizeof(buf),          \
                hex,strlen(hex)));\
    smartlist_add(wanted, tor_memdup(buf, DIGEST256_LEN));              \
  } while (0)

  /* invalid,0 */
  ADD("5d76bf1c6614e885614a1e0ad074e1ab4ea14655ebeefb1736a71b5ed8a15a51");
  /* invalid,2 */
  ADD("20d1576c5ab11bbcff0dedb1db4a3cfcc8bc8dd839d8cbfef92d00a1a7d7b294");
  /* valid, 6 */
  ADD("53f740bd222ab37f19f604b1d3759aa65eff1fbce9ac254bd0fa50d4af9b1bae");
  /* valid, 8 */
  ADD("a0a155562d8093d8fd0feb7b93b7226e17f056c2142aab7a4ea8c5867a0376d5");

  added = microdescs_add_to_cache(mc, MD_PARSE_TEST_DATA, NULL,
                                  SAVED_NOWHERE, 0, time(NULL), wanted);

  tt_int_op(smartlist_len(added), OP_EQ, 2);
  tt_int_op(mock_rgsbd_called, OP_EQ, 2);
  tt_int_op(mock_rgsbd_val_a->dl_status.n_download_failures, OP_EQ, 255);
  tt_int_op(mock_rgsbd_val_b->dl_status.n_download_failures, OP_EQ, 255);

 done:
  UNMOCK(networkstatus_get_latest_consensus_by_flavor);
  UNMOCK(router_get_mutable_consensus_status_by_descriptor_digest);
  tor_free(options->CacheDirectory);
  microdesc_free_all();
  smartlist_free(added);
  SMARTLIST_FOREACH(wanted, char *, cp, tor_free(cp));
  smartlist_free(wanted);
  tor_free(mock_rgsbd_val_a);
  tor_free(mock_rgsbd_val_b);
  tor_free(mock_ns_val);
}
Beispiel #5
0
/** Tell the nodelist that the current usable consensus is <b>ns</b>.
 * This makes the nodelist change all of the routerstatus entries for
 * the nodes, drop nodes that no longer have enough info to get used,
 * and grab microdescriptors into nodes as appropriate.
 */
void
nodelist_set_consensus(networkstatus_t *ns)
{
  const or_options_t *options = get_options();
  int authdir = authdir_mode_v3(options);
  int client = !server_mode(options);

  init_nodelist();
  if (ns->flavor == FLAV_MICRODESC)
    (void) get_microdesc_cache(); /* Make sure it exists first. */

  SMARTLIST_FOREACH(the_nodelist->nodes, node_t *, node,
                    node->rs = NULL);

  SMARTLIST_FOREACH_BEGIN(ns->routerstatus_list, routerstatus_t *, rs) {
    node_t *node = node_get_or_create(rs->identity_digest);
    node->rs = rs;
    if (ns->flavor == FLAV_MICRODESC) {
      if (node->md == NULL ||
          tor_memneq(node->md->digest,rs->descriptor_digest,DIGEST256_LEN)) {
        if (node->md)
          node->md->held_by_nodes--;
        node->md = microdesc_cache_lookup_by_digest256(NULL,
                                                       rs->descriptor_digest);
        if (node->md)
          node->md->held_by_nodes++;
      }
    }

    node_set_country(node);

    /* If we're not an authdir, believe others. */
    if (!authdir) {
      node->is_valid = rs->is_valid;
      node->is_running = rs->is_flagged_running;
      node->is_fast = rs->is_fast;
      node->is_stable = rs->is_stable;
      node->is_possible_guard = rs->is_possible_guard;
      node->is_exit = rs->is_exit;
      node->is_bad_directory = rs->is_bad_directory;
      node->is_bad_exit = rs->is_bad_exit;
      node->is_hs_dir = rs->is_hs_dir;
      node->ipv6_preferred = 0;
      if (client && options->ClientPreferIPv6ORPort == 1 &&
          (tor_addr_is_null(&rs->ipv6_addr) == 0 ||
           (node->md && tor_addr_is_null(&node->md->ipv6_addr) == 0)))
        node->ipv6_preferred = 1;
    }

  } SMARTLIST_FOREACH_END(rs);

  nodelist_purge();

  if (! authdir) {
    SMARTLIST_FOREACH_BEGIN(the_nodelist->nodes, node_t *, node) {
      /* We have no routerstatus for this router. Clear flags so we can skip
       * it, maybe.*/
      if (!node->rs) {
        tor_assert(node->ri); /* if it had only an md, or nothing, purge
                               * would have removed it. */
        if (node->ri->purpose == ROUTER_PURPOSE_GENERAL) {
          /* Clear all flags. */
          node->is_valid = node->is_running = node->is_hs_dir =
            node->is_fast = node->is_stable =
            node->is_possible_guard = node->is_exit =
            node->is_bad_exit = node->is_bad_directory =
            node->ipv6_preferred = 0;
        }
      }
    } SMARTLIST_FOREACH_END(node);
  }