Esempio n. 1
0
static void
NS(logv)(int severity, log_domain_mask_t domain, const char *funcname,
    const char *suffix, const char *format, va_list ap)
{
  switch (CALLED(logv))
  {
    case 0:
      tt_int_op(severity, OP_EQ, LOG_NOTICE);
      tt_int_op(domain, OP_EQ, LD_HEARTBEAT);
      tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL);
      tt_ptr_op(suffix, OP_EQ, NULL);
      tt_str_op(format, OP_EQ,
          "Heartbeat: Tor's uptime is %s, with %d circuits open. "
          "I've sent %s and received %s.%s");
      tt_str_op(va_arg(ap, char *), OP_EQ, "0:00 hours");  /* uptime */
      tt_int_op(va_arg(ap, int), OP_EQ, 0);  /* count_circuits() */
      tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB");  /* bw_sent */
      tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB");  /* bw_rcvd */
      tt_str_op(va_arg(ap, char *), OP_EQ, "");  /* hibernating */
      break;
    case 1:
      tt_int_op(severity, OP_EQ, LOG_NOTICE);
      tt_int_op(domain, OP_EQ, LD_HEARTBEAT);
      tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL);
      tt_ptr_op(suffix, OP_EQ, NULL);
      tt_str_op(format, OP_EQ,
          "Average packaged cell fullness: %2.3f%%. TLS write overhead: %.f%%");
      tt_double_op(fabs(va_arg(ap, double) - 50.0), <=, DBL_EPSILON);
      tt_double_op(fabs(va_arg(ap, double) - 0.0), <=, DBL_EPSILON);
      break;
    default:
      tt_abort_msg("unexpected call to logv()");  // TODO: prettyprint args
      break;
  }

  done:
    CALLED(logv)++;
}
Esempio n. 2
0
static void
test_address_get_if_addrs_internal_fail(void *arg)
{
  smartlist_t *results1 = NULL, *results2 = NULL;
  int rv = 0;
  uint32_t ipv4h_addr = 0;
  tor_addr_t ipv6_addr;

  memset(&ipv6_addr, 0, sizeof(tor_addr_t));

  (void)arg;

  MOCK(get_interface_addresses_raw,
       mock_get_interface_addresses_raw_fail);
  MOCK(get_interface_address6_via_udp_socket_hack,
       mock_get_interface_address6_via_udp_socket_hack_fail);

  results1 = get_interface_address6_list(LOG_ERR, AF_INET6, 1);
  tt_ptr_op(results1, OP_NE, NULL);
  tt_int_op(smartlist_len(results1),OP_EQ,0);

  results2 = get_interface_address_list(LOG_ERR, 1);
  tt_ptr_op(results2, OP_NE, NULL);
  tt_int_op(smartlist_len(results2),OP_EQ,0);

  rv = get_interface_address6(LOG_ERR, AF_INET6, &ipv6_addr);
  tt_int_op(rv, OP_EQ, -1);

  rv = get_interface_address(LOG_ERR, &ipv4h_addr);
  tt_int_op(rv, OP_EQ, -1);

 done:
  UNMOCK(get_interface_addresses_raw);
  UNMOCK(get_interface_address6_via_udp_socket_hack);
  interface_address6_list_free(results1);
  interface_address6_list_free(results2);
  return;
}
Esempio n. 3
0
/**
 * Calling bridge_get_addrport() should give me the address and port
 * of the bridge.  In this case, we sort the smartlist of bridges on
 * fingerprints and choose the first one.
 */
static void
test_bridges_bridge_get_addrport(void *arg)
{
  smartlist_t *bridgelist;
  const bridge_info_t *bridge;
  const tor_addr_port_t *addrport;

  helper_add_bridges_to_bridgelist(arg);
  bridgelist = (smartlist_t*)bridge_list_get();
  tt_ptr_op(bridgelist, OP_NE, NULL);

  // This should be the bridge at 6.6.6.6:6666 with fingerprint
  // 0000000000000000000000000000000000000000
  bridge = smartlist_get(bridgelist, 0);
  tt_ptr_op(bridge, OP_NE, NULL);

  addrport = bridge_get_addr_port(bridge);
  tt_int_op(addrport->port, OP_EQ, 6666);

 done:
  mark_bridge_list();
  sweep_bridge_list();
}
Esempio n. 4
0
static void
chan_test_channel_dump_statistics_mock(channel_t *chan, int severity)
{
  tt_ptr_op(chan, OP_NE, NULL);

  (void)severity;

  if (chan != NULL && chan == dump_statistics_mock_target) {
    ++dump_statistics_mock_matches;
  }

 done:
  return;
}
Esempio n. 5
0
addr_policy_result_t
NS(compare_tor_addr_to_addr_policy)(const tor_addr_t *addr, uint16_t port,
    const smartlist_t *policy)
{
  (void)port;
  (void)policy;
  CALLED(compare_tor_addr_to_addr_policy)++;
  tt_ptr_op(addr, OP_EQ, MOCK_TOR_ADDR_PTR);

  return ADDR_POLICY_ACCEPTED;

  done:
    return 0;
}
Esempio n. 6
0
static void
NS(test_main)(void *arg)
{
  const char *input;
  char *name;
  (void)arg;

  /* strlen(c) < 4 */
  input = "xxx";
  name = routerset_get_countryname(input);
  tt_ptr_op(name, OP_EQ, NULL);
  tor_free(name);

  /* c[0] != '{' */
  input = "xxx}";
  name = routerset_get_countryname(input);
  tt_ptr_op(name, OP_EQ, NULL);
  tor_free(name);

  /* c[3] != '}' */
  input = "{xxx";
  name = routerset_get_countryname(input);
  tt_ptr_op(name, OP_EQ, NULL);
  tor_free(name);

  /* tor_strlower */
  input = "{XX}";
  name = routerset_get_countryname(input);
  tt_str_op(name, OP_EQ, "xx");
  tor_free(name);

  input = "{xx}";
  name = routerset_get_countryname(input);
  tt_str_op(name, OP_EQ, "xx");
  done:
    tor_free(name);
}
Esempio n. 7
0
static void
NS(logv)(int severity, log_domain_mask_t domain, const char *funcname,
  const char *suffix, const char *format, va_list ap)
{
  if (severity == LOG_INFO)
    return;
  ++NS(n_msgs);

  tt_int_op(severity, OP_EQ, LOG_NOTICE);
  tt_int_op(domain, OP_EQ, LD_HEARTBEAT);
  tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL);
  tt_ptr_op(suffix, OP_EQ, NULL);
  tt_str_op(format, OP_EQ,
      "Heartbeat: Tor's uptime is %s, with %d circuits open. "
      "I've sent %s and received %s.%s");
  tt_str_op(va_arg(ap, char *), OP_EQ, "0:00 hours");  /* uptime */
  tt_int_op(va_arg(ap, int), OP_EQ, 0);  /* count_circuits() */
  tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB");  /* bw_sent */
  tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB");  /* bw_rcvd */
  tt_str_op(va_arg(ap, char *), OP_EQ, " We are currently hibernating.");

  done:
    ;
}
Esempio n. 8
0
/**
 * Calling find_bridge_by_digest() when we do NOT have a bridge with that
 * identity digest should return NULL.
 */
static void
test_bridges_find_bridge_by_digest_unknown(void *arg)
{
  const char *fingerprint = "cccccccccccccccccccccccccccccccccccccccc";
  bridge_info_t *bridge;

  helper_add_bridges_to_bridgelist(arg);

  bridge = find_bridge_by_digest(fingerprint);

  tt_ptr_op(bridge, OP_EQ, NULL);

 done:
  mark_bridge_list();
  sweep_bridge_list();
}
Esempio n. 9
0
static void
test_rend_cache_failure_purge(void *data)
{
  (void)data;

  // Handles a null failure cache
  strmap_free(rend_cache_failure, rend_cache_failure_entry_free_);
  rend_cache_failure = NULL;

  rend_cache_failure_purge();

  tt_ptr_op(rend_cache_failure, OP_NE, NULL);
  tt_int_op(strmap_size(rend_cache_failure), OP_EQ, 0);

 done:
  rend_cache_free_all();
}
Esempio n. 10
0
static void
NS(logv)(int severity, log_domain_mask_t domain,
  const char *funcname, const char *suffix, const char *format, va_list ap)
{
  switch (CALLED(logv))
  {
    case 0:
      tt_int_op(severity, OP_EQ, LOG_NOTICE);
      tt_int_op(domain, OP_EQ, LD_HEARTBEAT);
      tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL);
      tt_ptr_op(suffix, OP_EQ, NULL);
      tt_str_op(format, OP_EQ,
          "Heartbeat: It seems like we are not in the cached consensus.");
      break;
    case 1:
      tt_int_op(severity, OP_EQ, LOG_NOTICE);
      tt_int_op(domain, OP_EQ, LD_HEARTBEAT);
      tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL);
      tt_ptr_op(suffix, OP_EQ, NULL);
      tt_str_op(format, OP_EQ,
          "Heartbeat: Tor's uptime is %s, with %d circuits open. "
          "I've sent %s and received %s.%s");
      tt_str_op(va_arg(ap, char *), OP_EQ, "0:00 hours");  /* uptime */
      tt_int_op(va_arg(ap, int), OP_EQ, 0);  /* count_circuits() */
      tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB");  /* bw_sent */
      tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB");  /* bw_rcvd */
      tt_str_op(va_arg(ap, char *), OP_EQ, "");  /* hibernating */
      break;
    case 2:
      tt_int_op(severity, OP_EQ, LOG_INFO);
      break;
    case 3:
      tt_int_op(severity, OP_EQ, LOG_NOTICE);
      tt_int_op(domain, OP_EQ, LD_HEARTBEAT);
      tt_ptr_op(strstr(funcname, "rep_hist_log_circuit_handshake_stats"),
                OP_NE, NULL);
      tt_ptr_op(suffix, OP_EQ, NULL);
      tt_str_op(format, OP_EQ,
        "Circuit handshake stats since last time: %d/%d TAP, %d/%d NTor.");
      tt_int_op(va_arg(ap, int), OP_EQ, 1);  /* handshakes assigned (TAP) */
      tt_int_op(va_arg(ap, int), OP_EQ, 1);  /* handshakes requested (TAP) */
      tt_int_op(va_arg(ap, int), OP_EQ, 1);  /* handshakes assigned (NTOR) */
      tt_int_op(va_arg(ap, int), OP_EQ, 1);  /* handshakes requested (NTOR) */
      break;
    default:
      tt_abort_msg("unexpected call to logv()");  // TODO: prettyprint args
      break;
  }

  done:
    CALLED(logv)++;
}
Esempio n. 11
0
static void
test_ext_or_cookie_auth_testvec(void *arg)
{
  char *reply=NULL, *client_hash=NULL;
  size_t reply_len;
  char *mem_op_hex_tmp=NULL;

  const char client_nonce[] = "But when I look ahead up the whi";
  (void)arg;

  ext_or_auth_cookie = tor_malloc_zero(32);
  memcpy(ext_or_auth_cookie, "Gliding wrapt in a brown mantle," , 32);
  ext_or_auth_cookie_is_set = 1;

  MOCK(crypto_rand, crypto_rand_return_tse_str);

  tt_int_op(0, OP_EQ,
            handle_client_auth_nonce(client_nonce, 32, &client_hash, &reply,
                                     &reply_len));
  tt_ptr_op(reply, OP_NE, NULL );
  tt_uint_op(reply_len, OP_EQ, 64);
  tt_mem_op(reply+32,OP_EQ, "te road There is always another ", 32);
  /* HMACSHA256("Gliding wrapt in a brown mantle,"
   *     "ExtORPort authentication server-to-client hash"
   *     "But when I look ahead up the write road There is always another ");
   */
  test_memeq_hex(reply,
                 "ec80ed6e546d3b36fdfc22fe1315416b"
                 "029f1ade7610d910878b62eeb7403821");
  /* HMACSHA256("Gliding wrapt in a brown mantle,"
   *     "ExtORPort authentication client-to-server hash"
   *     "But when I look ahead up the write road There is always another ");
   * (Both values computed using Python CLI.)
   */
  test_memeq_hex(client_hash,
                 "ab391732dd2ed968cd40c087d1b1f25b"
                 "33b3cd77ff79bd80c2074bbf438119a2");

 done:
  UNMOCK(crypto_rand);
  tor_free(reply);
  tor_free(client_hash);
  tor_free(mem_op_hex_tmp);
}
Esempio n. 12
0
static void
NS(test_main)(void *arg)
{
  routerset_t *set = NULL;
  routerset_t **setp = &set;
  int r;
  (void)arg;

  NS_MOCK(geoip_get_country);

  r = routerset_add_unknown_ccs(setp, 0);

  tt_ptr_op(*setp, OP_NE, NULL);
  tt_int_op(r, OP_EQ, 0);

  done:
    if (set != NULL)
      routerset_free(set);
}
Esempio n. 13
0
static void
test_address_get_if_addrs6_list_no_internal(void *arg)
{
  smartlist_t *results = NULL;

  (void)arg;

  /* We might drop a log_err */
  setup_full_capture_of_logs(LOG_ERR);
  results = get_interface_address6_list(LOG_ERR, AF_INET6, 0);
  tt_int_op(smartlist_len(mock_saved_logs()), OP_LE, 1);
  if (smartlist_len(mock_saved_logs()) == 1) {
    expect_log_msg_containing_either4("connect() failed",
                                      "unable to create socket",
                                      "Address that we determined via UDP "
                                      "socket magic is unsuitable for public "
                                      "comms.",
                                      "getsockname() to determine interface "
                                      "failed");
  }
  teardown_capture_of_logs();

  tt_ptr_op(results, OP_NE, NULL);
  /* Work even on systems without IPv6 interfaces */
  tt_int_op(smartlist_len(results),OP_GE,0);

  tt_assert(!smartlist_contains_localhost_tor_addr(results));
  tt_assert(!smartlist_contains_multicast_tor_addr(results));
  tt_assert(!smartlist_contains_internal_tor_addr(results));
  tt_assert(!smartlist_contains_null_tor_addr(results));

  /* if there are any addresses, they must be IPv6 */
  tt_assert(!smartlist_contains_ipv4_tor_addr(results));
  if (smartlist_len(results) > 0) {
    tt_assert(smartlist_contains_ipv6_tor_addr(results));
  }

 done:
  teardown_capture_of_logs();
  interface_address6_list_free(results);
  return;
}
Esempio n. 14
0
static void
NS(test_main)(void *arg)
{
  routerset_t *set = routerset_new();
  (void)arg;

  NS_MOCK(geoip_is_loaded);
  NS_MOCK(geoip_get_n_countries);

  routerset_refresh_countries(set);

  tt_ptr_op(set->countries, OP_EQ, NULL);
  tt_int_op(set->n_countries, OP_EQ, 0);
  tt_int_op(CALLED(geoip_is_loaded), OP_EQ, 1);
  tt_int_op(CALLED(geoip_get_n_countries), OP_EQ, 0);

  done:
    NS_UNMOCK(geoip_is_loaded);
    NS_UNMOCK(geoip_get_n_countries);
    routerset_free(set);
}
Esempio n. 15
0
/** Test choose_random_entry() with only one of our routers being a
    guard node. */
static void
test_choose_random_entry_one_possible_guard(void *arg)
{
  const node_t *chosen_entry = NULL;
  node_t *the_guard = NULL;
  smartlist_t *our_nodelist = NULL;

  (void) arg;

  /* Set one of the nodes to be a guard. */
  our_nodelist = nodelist_get_list();
  the_guard = smartlist_get(our_nodelist, 4); /* chosen by fair dice roll */
  the_guard->is_possible_guard = 1;

  /* Pick an entry. Make sure we pick the node we marked as guard. */
  chosen_entry = choose_random_entry(NULL);
  tt_ptr_op(chosen_entry, OP_EQ, the_guard);

 done:
  ;
}
Esempio n. 16
0
static void
NS(test_main)(void *arg)
{
  routerset_t *rs;
  (void)arg;

  rs = routerset_new();

  tt_ptr_op(rs, OP_NE, NULL);
  tt_ptr_op(rs->list, OP_NE, NULL);
  tt_ptr_op(rs->names, OP_NE, NULL);
  tt_ptr_op(rs->digests, OP_NE, NULL);
  tt_ptr_op(rs->policies, OP_NE, NULL);
  tt_ptr_op(rs->country_names, OP_NE, NULL);

  done:
    routerset_free(rs);
}
Esempio n. 17
0
/* Test inbound cell. The callstack is:
 *  channel_process_cell()
 *    -> chan->cell_handler()
 *
 * This test is about checking if we can process an inbound cell down to the
 * channel handler. */
static void
test_channel_inbound_cell(void *arg)
{
  channel_t *chan = NULL;
  cell_t *cell = NULL;
  int old_count;

  (void) arg;

  /* The channel will be freed so we need to hijack this so the scheduler
   * doesn't get confused. */
  MOCK(scheduler_release_channel, scheduler_release_channel_mock);

  /* Accept cells to lower layer */
  test_chan_accept_cells = 1;

  chan = new_fake_channel();
  tt_assert(chan);
  /* Start it off in OPENING */
  chan->state = CHANNEL_STATE_OPENING;

  /* Try to register it */
  channel_register(chan);
  tt_int_op(chan->registered, OP_EQ, 1);

  /* Open it */
  channel_change_state_open(chan);
  tt_int_op(chan->state, OP_EQ, CHANNEL_STATE_OPEN);
  tt_int_op(chan->has_been_open, OP_EQ, 1);

  /* Receive a cell now. */
  cell = tor_malloc_zero(sizeof(*cell));
  make_fake_cell(cell);
  old_count = test_chan_fixed_cells_recved;
  channel_process_cell(chan, cell);
  tt_int_op(test_chan_fixed_cells_recved, OP_EQ, old_count);
  tt_assert(monotime_coarse_is_zero(&chan->timestamp_xfer));
  tt_u64_op(chan->timestamp_active, OP_EQ, 0);
  tt_u64_op(chan->timestamp_recv, OP_EQ, 0);

  /* Setup incoming cell handlers. We don't care about var cell, the channel
   * layers is not handling those. */
  channel_set_cell_handlers(chan, chan_test_cell_handler, NULL);
  tt_ptr_op(chan->cell_handler, OP_EQ, chan_test_cell_handler);
  /* Now process the cell, we should see it. */
  old_count = test_chan_fixed_cells_recved;
  channel_process_cell(chan, cell);
  tt_int_op(test_chan_fixed_cells_recved, OP_EQ, old_count + 1);
  /* We should have a series of timestamp set. */
  tt_assert(!monotime_coarse_is_zero(&chan->timestamp_xfer));
  tt_u64_op(chan->timestamp_active, OP_NE, 0);
  tt_u64_op(chan->timestamp_recv, OP_NE, 0);
  tt_assert(monotime_coarse_is_zero(&chan->next_padding_time));
  tt_u64_op(chan->n_cells_recved, OP_EQ, 1);
  tt_u64_op(chan->n_bytes_recved, OP_EQ, get_cell_network_size(0));

  /* Close it */
  old_count = test_close_called;
  channel_mark_for_close(chan);
  tt_int_op(chan->state, OP_EQ, CHANNEL_STATE_CLOSING);
  tt_int_op(chan->reason_for_closing, OP_EQ, CHANNEL_CLOSE_REQUESTED);
  tt_int_op(test_close_called, OP_EQ, old_count + 1);

  /* This closes the channe so it calls in the scheduler, make sure of it. */
  old_count = test_releases_count;
  chan_test_finish_close(chan);
  tt_int_op(test_releases_count, OP_EQ, old_count + 1);
  tt_int_op(chan->state, OP_EQ, CHANNEL_STATE_CLOSED);

  /* The channel will be free, lets make sure it is not accessible. */
  uint64_t chan_id = chan->global_identifier;
  tt_ptr_op(channel_find_by_global_id(chan_id), OP_EQ, chan);
  channel_run_cleanup();
  chan = channel_find_by_global_id(chan_id);
  tt_assert(chan == NULL);

 done:
  tor_free(cell);
  UNMOCK(scheduler_release_channel);
}
Esempio n. 18
0
/* Test outbound cell. The callstack is:
 *  channel_flush_some_cells()
 *   -> channel_flush_from_first_active_circuit()
 *     -> channel_write_packed_cell()
 *       -> write_packed_cell()
 *         -> chan->write_packed_cell() fct ptr.
 *
 * This test goes from a cell in a circuit up to the channel write handler
 * that should put them on the connection outbuf. */
static void
test_channel_outbound_cell(void *arg)
{
  int old_count;
  channel_t *chan = NULL;
  packed_cell_t *p_cell = NULL, *p_cell2 = NULL;
  origin_circuit_t *circ = NULL;
  cell_queue_t *queue;

  (void) arg;

  /* Set the test time to be mocked, since this test assumes that no
   * time will pass, ewma values will not need to be re-scaled, and so on */
  monotime_enable_test_mocking();
  monotime_set_mock_time_nsec(U64_LITERAL(1000000000) * 12345);

  cmux_ewma_set_options(NULL,NULL);

  /* The channel will be freed so we need to hijack this so the scheduler
   * doesn't get confused. */
  MOCK(scheduler_release_channel, scheduler_release_channel_mock);

  /* Accept cells to lower layer */
  test_chan_accept_cells = 1;

  /* Setup a valid circuit to queue a cell. */
  circ = origin_circuit_new();
  tt_assert(circ);
  /* Circuit needs an origin purpose to be considered origin. */
  TO_CIRCUIT(circ)->purpose = CIRCUIT_PURPOSE_C_GENERAL;
  TO_CIRCUIT(circ)->n_circ_id = 42;
  /* This is the outbound test so use the next channel queue. */
  queue = &TO_CIRCUIT(circ)->n_chan_cells;
  /* Setup packed cell to queue on the circuit. */
  p_cell = packed_cell_new();
  tt_assert(p_cell);
  p_cell2 = packed_cell_new();
  tt_assert(p_cell2);
  /* Setup a channel to put the circuit on. */
  chan = new_fake_channel();
  tt_assert(chan);
  chan->state = CHANNEL_STATE_OPENING;
  channel_change_state_open(chan);
  /* Outbound channel. */
  channel_mark_outgoing(chan);
  /* Try to register it so we can clean it through the channel cleanup
   * process. */
  channel_register(chan);
  tt_int_op(chan->registered, OP_EQ, 1);
  /* Set EWMA policy so we can pick it when flushing. */
  circuitmux_set_policy(chan->cmux, &ewma_policy);
  tt_ptr_op(circuitmux_get_policy(chan->cmux), OP_EQ, &ewma_policy);

  /* Register circuit to the channel circid map which will attach the circuit
   * to the channel's cmux as well. */
  circuit_set_n_circid_chan(TO_CIRCUIT(circ), 42, chan);
  tt_int_op(channel_num_circuits(chan), OP_EQ, 1);
  /* Test the cmux state. */
  tt_ptr_op(TO_CIRCUIT(circ)->n_mux, OP_EQ, chan->cmux);
  tt_int_op(circuitmux_is_circuit_attached(chan->cmux, TO_CIRCUIT(circ)),
            OP_EQ, 1);

  /* Flush the channel without any cell on it. */
  old_count = test_cells_written;
  ssize_t flushed = channel_flush_some_cells(chan, 1);
  tt_i64_op(flushed, OP_EQ, 0);
  tt_int_op(test_cells_written, OP_EQ, old_count);
  tt_int_op(channel_more_to_flush(chan), OP_EQ, 0);
  tt_int_op(circuitmux_num_active_circuits(chan->cmux), OP_EQ, 0);
  tt_int_op(circuitmux_num_cells(chan->cmux), OP_EQ, 0);
  tt_int_op(circuitmux_is_circuit_active(chan->cmux, TO_CIRCUIT(circ)),
            OP_EQ, 0);
  tt_u64_op(chan->n_cells_xmitted, OP_EQ, 0);
  tt_u64_op(chan->n_bytes_xmitted, OP_EQ, 0);

  /* Queue cell onto the next queue that is the outbound direction. Than
   * update its cmux so the circuit can be picked when flushing cells. */
  cell_queue_append(queue, p_cell);
  p_cell = NULL;
  tt_int_op(queue->n, OP_EQ, 1);
  cell_queue_append(queue, p_cell2);
  p_cell2 = NULL;
  tt_int_op(queue->n, OP_EQ, 2);

  update_circuit_on_cmux(TO_CIRCUIT(circ), CELL_DIRECTION_OUT);
  tt_int_op(circuitmux_num_active_circuits(chan->cmux), OP_EQ, 1);
  tt_int_op(circuitmux_num_cells(chan->cmux), OP_EQ, 2);
  tt_int_op(circuitmux_is_circuit_active(chan->cmux, TO_CIRCUIT(circ)),
            OP_EQ, 1);

  /* From this point on, we have a queued cell on an active circuit attached
   * to the channel's cmux. */

  /* Flush the first cell. This is going to go down the call stack. */
  old_count = test_cells_written;
  flushed = channel_flush_some_cells(chan, 1);
  tt_i64_op(flushed, OP_EQ, 1);
  tt_int_op(test_cells_written, OP_EQ, old_count + 1);
  tt_int_op(circuitmux_num_cells(chan->cmux), OP_EQ, 1);
  tt_int_op(channel_more_to_flush(chan), OP_EQ, 1);
  /* Circuit should remain active because there is a second cell queued. */
  tt_int_op(circuitmux_is_circuit_active(chan->cmux, TO_CIRCUIT(circ)),
            OP_EQ, 1);
  /* Should still be attached. */
  tt_int_op(circuitmux_is_circuit_attached(chan->cmux, TO_CIRCUIT(circ)),
            OP_EQ, 1);
  tt_u64_op(chan->n_cells_xmitted, OP_EQ, 1);
  tt_u64_op(chan->n_bytes_xmitted, OP_EQ, get_cell_network_size(0));

  /* Flush second cell. This is going to go down the call stack. */
  old_count = test_cells_written;
  flushed = channel_flush_some_cells(chan, 1);
  tt_i64_op(flushed, OP_EQ, 1);
  tt_int_op(test_cells_written, OP_EQ, old_count + 1);
  tt_int_op(circuitmux_num_cells(chan->cmux), OP_EQ, 0);
  tt_int_op(channel_more_to_flush(chan), OP_EQ, 0);
  /* No more cells should make the circuit inactive. */
  tt_int_op(circuitmux_is_circuit_active(chan->cmux, TO_CIRCUIT(circ)),
            OP_EQ, 0);
  /* Should still be attached. */
  tt_int_op(circuitmux_is_circuit_attached(chan->cmux, TO_CIRCUIT(circ)),
            OP_EQ, 1);
  tt_u64_op(chan->n_cells_xmitted, OP_EQ, 2);
  tt_u64_op(chan->n_bytes_xmitted, OP_EQ, get_cell_network_size(0) * 2);

 done:
  if (circ) {
    circuit_free_(TO_CIRCUIT(circ));
  }
  tor_free(p_cell);
  channel_free_all();
  UNMOCK(scheduler_release_channel);
  monotime_disable_test_mocking();
}
Esempio n. 19
0
static void
test_buffer_ext_or_cmd(void *arg)
{
  ext_or_cmd_t *cmd = NULL;
  generic_buffer_t *buf = generic_buffer_new();
  char *tmp = NULL;
  (void) arg;

  /* Empty -- should give "not there. */
  tt_int_op(0, OP_EQ, generic_buffer_fetch_ext_or_cmd(buf, &cmd));
  tt_ptr_op(NULL, OP_EQ, cmd);

  /* Three bytes: shouldn't work. */
  generic_buffer_add(buf, "\x00\x20\x00", 3);
  tt_int_op(0, OP_EQ, generic_buffer_fetch_ext_or_cmd(buf, &cmd));
  tt_ptr_op(NULL, OP_EQ, cmd);
  tt_int_op(3, OP_EQ, generic_buffer_len(buf));

  /* 0020 0000: That's a nil command. It should work. */
  generic_buffer_add(buf, "\x00", 1);
  tt_int_op(1, OP_EQ, generic_buffer_fetch_ext_or_cmd(buf, &cmd));
  tt_ptr_op(NULL, OP_NE, cmd);
  tt_int_op(0x20, OP_EQ, cmd->cmd);
  tt_int_op(0, OP_EQ, cmd->len);
  tt_int_op(0, OP_EQ, generic_buffer_len(buf));
  ext_or_cmd_free(cmd);
  cmd = NULL;

  /* Now try a length-6 command with one byte missing. */
  generic_buffer_add(buf, "\x10\x21\x00\x06""abcde", 9);
  tt_int_op(0, OP_EQ, generic_buffer_fetch_ext_or_cmd(buf, &cmd));
  tt_ptr_op(NULL, OP_EQ, cmd);
  generic_buffer_add(buf, "f", 1);
  tt_int_op(1, OP_EQ, generic_buffer_fetch_ext_or_cmd(buf, &cmd));
  tt_ptr_op(NULL, OP_NE, cmd);
  tt_int_op(0x1021, OP_EQ, cmd->cmd);
  tt_int_op(6, OP_EQ, cmd->len);
  tt_mem_op("abcdef", OP_EQ, cmd->body, 6);
  tt_int_op(0, OP_EQ, generic_buffer_len(buf));
  ext_or_cmd_free(cmd);
  cmd = NULL;

  /* Now try a length-10 command with 4 extra bytes. */
  generic_buffer_add(buf, "\xff\xff\x00\x0a"
                     "loremipsum\x10\x00\xff\xff", 18);
  tt_int_op(1, OP_EQ, generic_buffer_fetch_ext_or_cmd(buf, &cmd));
  tt_ptr_op(NULL, OP_NE, cmd);
  tt_int_op(0xffff, OP_EQ, cmd->cmd);
  tt_int_op(10, OP_EQ, cmd->len);
  tt_mem_op("loremipsum", OP_EQ, cmd->body, 10);
  tt_int_op(4, OP_EQ, generic_buffer_len(buf));
  ext_or_cmd_free(cmd);
  cmd = NULL;

  /* Finally, let's try a maximum-length command. We already have the header
   * waiting. */
  tt_int_op(0, OP_EQ, generic_buffer_fetch_ext_or_cmd(buf, &cmd));
  tmp = tor_malloc_zero(65535);
  generic_buffer_add(buf, tmp, 65535);
  tt_int_op(1, OP_EQ, generic_buffer_fetch_ext_or_cmd(buf, &cmd));
  tt_ptr_op(NULL, OP_NE, cmd);
  tt_int_op(0x1000, OP_EQ, cmd->cmd);
  tt_int_op(0xffff, OP_EQ, cmd->len);
  tt_mem_op(tmp, OP_EQ, cmd->body, 65535);
  tt_int_op(0, OP_EQ, generic_buffer_len(buf));
  ext_or_cmd_free(cmd);
  cmd = NULL;

 done:
  ext_or_cmd_free(cmd);
  generic_buffer_free(buf);
  tor_free(tmp);
}
Esempio n. 20
0
static void
test_channel_duplicates(void *arg)
{
  channel_t *chan = NULL;
  routerstatus_t rs;

  (void) arg;

  setup_full_capture_of_logs(LOG_INFO);
  /* Try a flat call with channel nor connections. */
  channel_check_for_duplicates();
  expect_log_msg_containing(
    "Found 0 connections to 0 relays. Found 0 current canonical "
    "connections, in 0 of which we were a non-canonical peer. "
    "0 relays had more than 1 connection, 0 had more than 2, and "
    "0 had more than 4 connections.");

  mock_ns = tor_malloc_zero(sizeof(*mock_ns));
  mock_ns->routerstatus_list = smartlist_new();
  MOCK(networkstatus_get_latest_consensus,
       mock_networkstatus_get_latest_consensus);

  chan = new_fake_channel();
  tt_assert(chan);
  chan->is_canonical = test_chan_is_canonical;
  memset(chan->identity_digest, 'A', sizeof(chan->identity_digest));
  channel_add_to_digest_map(chan);
  tt_ptr_op(channel_find_by_remote_identity(chan->identity_digest, NULL),
            OP_EQ, chan);

  /* No relay has been associated with this channel. */
  channel_check_for_duplicates();
  expect_log_msg_containing(
    "Found 0 connections to 0 relays. Found 0 current canonical "
    "connections, in 0 of which we were a non-canonical peer. "
    "0 relays had more than 1 connection, 0 had more than 2, and "
    "0 had more than 4 connections.");

  /* Associate relay to this connection in the consensus. */
  memset(&rs, 0, sizeof(rs));
  memset(rs.identity_digest, 'A', sizeof(rs.identity_digest));
  smartlist_add(mock_ns->routerstatus_list, &rs);

  /* Non opened channel. */
  chan->state = CHANNEL_STATE_CLOSING;
  channel_check_for_duplicates();
  expect_log_msg_containing(
    "Found 0 connections to 0 relays. Found 0 current canonical "
    "connections, in 0 of which we were a non-canonical peer. "
    "0 relays had more than 1 connection, 0 had more than 2, and "
    "0 had more than 4 connections.");
  chan->state = CHANNEL_STATE_OPEN;

  channel_check_for_duplicates();
  expect_log_msg_containing(
    "Found 1 connections to 1 relays. Found 0 current canonical "
    "connections, in 0 of which we were a non-canonical peer. "
    "0 relays had more than 1 connection, 0 had more than 2, and "
    "0 had more than 4 connections.");

  test_chan_should_be_canonical = 1;
  channel_check_for_duplicates();
  expect_log_msg_containing(
    "Found 1 connections to 1 relays. Found 1 current canonical "
    "connections, in 1 of which we were a non-canonical peer. "
    "0 relays had more than 1 connection, 0 had more than 2, and "
    "0 had more than 4 connections.");
  teardown_capture_of_logs();

 done:
  free_fake_channel(chan);
  smartlist_clear(mock_ns->routerstatus_list);
  networkstatus_vote_free(mock_ns);
  UNMOCK(networkstatus_get_latest_consensus);
}
Esempio n. 21
0
static void
test_rend_token_maps(void *arg)
{
  or_circuit_t *c1, *c2, *c3, *c4;
  const uint8_t tok1[REND_TOKEN_LEN] = "The cat can't tell y";
  const uint8_t tok2[REND_TOKEN_LEN] = "ou its name, and it ";
  const uint8_t tok3[REND_TOKEN_LEN] = "doesn't really care.";
  /* -- Adapted from a quote by Fredrik Lundh. */

  (void)arg;
  (void)tok1; //xxxx
  c1 = or_circuit_new(0, NULL);
  c2 = or_circuit_new(0, NULL);
  c3 = or_circuit_new(0, NULL);
  c4 = or_circuit_new(0, NULL);

  /* Make sure we really filled up the tok* variables */
  tt_int_op(tok1[REND_TOKEN_LEN-1], OP_EQ, 'y');
  tt_int_op(tok2[REND_TOKEN_LEN-1], OP_EQ, ' ');
  tt_int_op(tok3[REND_TOKEN_LEN-1], OP_EQ, '.');

  /* No maps; nothing there. */
  tt_ptr_op(NULL, OP_EQ, circuit_get_rendezvous(tok1));
  tt_ptr_op(NULL, OP_EQ, circuit_get_intro_point(tok1));

  circuit_set_rendezvous_cookie(c1, tok1);
  circuit_set_intro_point_digest(c2, tok2);

  tt_ptr_op(NULL, OP_EQ, circuit_get_rendezvous(tok3));
  tt_ptr_op(NULL, OP_EQ, circuit_get_intro_point(tok3));
  tt_ptr_op(NULL, OP_EQ, circuit_get_rendezvous(tok2));
  tt_ptr_op(NULL, OP_EQ, circuit_get_intro_point(tok1));

  /* Without purpose set, we don't get the circuits */
  tt_ptr_op(NULL, OP_EQ, circuit_get_rendezvous(tok1));
  tt_ptr_op(NULL, OP_EQ, circuit_get_intro_point(tok2));

  c1->base_.purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING;
  c2->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT;

  /* Okay, make sure they show up now. */
  tt_ptr_op(c1, OP_EQ, circuit_get_rendezvous(tok1));
  tt_ptr_op(c2, OP_EQ, circuit_get_intro_point(tok2));

  /* Two items at the same place with the same token. */
  c3->base_.purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING;
  circuit_set_rendezvous_cookie(c3, tok2);
  tt_ptr_op(c2, OP_EQ, circuit_get_intro_point(tok2));
  tt_ptr_op(c3, OP_EQ, circuit_get_rendezvous(tok2));

  /* Marking a circuit makes it not get returned any more */
  circuit_mark_for_close(TO_CIRCUIT(c1), END_CIRC_REASON_FINISHED);
  tt_ptr_op(NULL, OP_EQ, circuit_get_rendezvous(tok1));
  circuit_free(TO_CIRCUIT(c1));
  c1 = NULL;

  /* Freeing a circuit makes it not get returned any more. */
  circuit_free(TO_CIRCUIT(c2));
  c2 = NULL;
  tt_ptr_op(NULL, OP_EQ, circuit_get_intro_point(tok2));

  /* c3 -- are you still there? */
  tt_ptr_op(c3, OP_EQ, circuit_get_rendezvous(tok2));
  /* Change its cookie.  This never happens in Tor per se, but hey. */
  c3->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT;
  circuit_set_intro_point_digest(c3, tok3);

  tt_ptr_op(NULL, OP_EQ, circuit_get_rendezvous(tok2));
  tt_ptr_op(c3, OP_EQ, circuit_get_intro_point(tok3));

  /* Now replace c3 with c4. */
  c4->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT;
  circuit_set_intro_point_digest(c4, tok3);

  tt_ptr_op(c4, OP_EQ, circuit_get_intro_point(tok3));

  tt_ptr_op(c3->rendinfo, OP_EQ, NULL);
  tt_ptr_op(c4->rendinfo, OP_NE, NULL);
  tt_mem_op(c4->rendinfo, OP_EQ, tok3, REND_TOKEN_LEN);

  /* Now clear c4's cookie. */
  circuit_set_intro_point_digest(c4, NULL);
  tt_ptr_op(c4->rendinfo, OP_EQ, NULL);
  tt_ptr_op(NULL, OP_EQ, circuit_get_intro_point(tok3));

 done:
  if (c1)
    circuit_free(TO_CIRCUIT(c1));
  if (c2)
    circuit_free(TO_CIRCUIT(c2));
  if (c3)
    circuit_free(TO_CIRCUIT(c3));
  if (c4)
    circuit_free(TO_CIRCUIT(c4));
}
Esempio n. 22
0
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->CacheDirectory);
  options->CacheDirectory = tor_strdup(get_fname("md_datadir_test"));
#ifdef _WIN32
  tt_int_op(0, OP_EQ, mkdir(options->CacheDirectory));
#else
  tt_int_op(0, OP_EQ, mkdir(options->CacheDirectory, 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, OP_EQ, 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, OP_EQ, 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, OP_EQ, smartlist_len(added));
  md2 = smartlist_get(added, 0);
  /* And it should have gotten removed from 'wanted' */
  tt_int_op(smartlist_len(wanted), OP_EQ, 1);
  tt_mem_op(smartlist_get(wanted, 0), OP_EQ, 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, OP_EQ, 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, OP_EQ, 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, OP_EQ, microdesc_cache_lookup_by_digest256(mc, d1));
  tt_ptr_op(md2, OP_EQ, microdesc_cache_lookup_by_digest256(mc, d2));
  tt_ptr_op(md3, OP_EQ, microdesc_cache_lookup_by_digest256(mc, d3));

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

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

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

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

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

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

  tt_int_op(md1->saved_location, OP_EQ, SAVED_IN_CACHE);
  tt_int_op(md2->saved_location, OP_EQ, SAVED_IN_CACHE);
  tt_int_op(md3->saved_location, OP_EQ, 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, OP_EQ, "");
  tor_free(s);
  tor_free(fn);

  /* read the cache. */
  tor_asprintf(&fn, "%s"PATH_SEPARATOR"cached-microdescs",
               options->CacheDirectory);
  s = read_file_to_str(fn, RFTS_BIN, NULL);
  tt_mem_op(md1->body, OP_EQ, s + md1->off, strlen(test_md1));
  tt_mem_op(md2->body, OP_EQ, s + md2->off, strlen(test_md2));
  tt_mem_op(md3->body, OP_EQ, 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);
  tt_assert(md1);
  tt_assert(md2);
  tt_assert(md3);
  tt_mem_op(md1->body, OP_EQ, s + md1->off, strlen(test_md1));
  tt_mem_op(md2->body, OP_EQ, s + md2->off, strlen(test_md2));
  tt_mem_op(md3->body, OP_EQ, s + md3->off, strlen(test_md3_noannotation));

  tt_int_op(md1->last_listed, OP_EQ, time1);
  tt_int_op(md2->last_listed, OP_EQ, time2);
  tt_int_op(md3->last_listed, OP_EQ, 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, OP_EQ, microdesc_cache_lookup_by_digest256(mc, d1));
  tt_ptr_op(md2, OP_EQ, microdesc_cache_lookup_by_digest256(mc, d2));
  tt_ptr_op(NULL, OP_EQ, microdesc_cache_lookup_by_digest256(mc, d3));
  md3 = NULL; /* it's history now! */

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

  /* Re-add md3, and make sure we can rebuild the cache. */
  added = microdescs_add_to_cache(mc, test_md3_noannotation, NULL,
                                  SAVED_NOWHERE, 0, time3, NULL);
  tt_int_op(1, OP_EQ, smartlist_len(added));
  md3 = smartlist_get(added, 0);
  smartlist_free(added);
  added = NULL;
  tt_int_op(md1->saved_location, OP_EQ, SAVED_IN_CACHE);
  tt_int_op(md2->saved_location, OP_EQ, SAVED_IN_CACHE);
  tt_int_op(md3->saved_location, OP_EQ, SAVED_IN_JOURNAL);

  tt_int_op(microdesc_cache_rebuild(mc, 1), OP_EQ, 0);
  tt_int_op(md3->saved_location, OP_EQ, SAVED_IN_CACHE);

 done:
  if (options)
    tor_free(options->CacheDirectory);
  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);
}
Esempio n. 23
0
static void
subtest_halfstream_insertremove(int num)
{
  origin_circuit_t *circ =
      helper_create_origin_circuit(CIRCUIT_PURPOSE_C_GENERAL, 0);
  edge_connection_t *edgeconn;
  entry_connection_t *entryconn;
  streamid_t *streams = tor_malloc_zero(num*sizeof(streamid_t));
  int i = 0;

  circ->cpath->state = CPATH_STATE_AWAITING_KEYS;
  circ->cpath->deliver_window = CIRCWINDOW_START;

  entryconn = fake_entry_conn(circ, 23);
  edgeconn = ENTRY_TO_EDGE_CONN(entryconn);

  /* Explicity test all operations on an absent stream list */
  tt_int_op(connection_half_edge_is_valid_data(circ->half_streams,
            23), OP_EQ, 0);
  tt_int_op(connection_half_edge_is_valid_connected(circ->half_streams,
            23), OP_EQ, 0);
  tt_int_op(connection_half_edge_is_valid_sendme(circ->half_streams,
            23), OP_EQ, 0);
  tt_int_op(connection_half_edge_is_valid_resolved(circ->half_streams,
            23), OP_EQ, 0);
  tt_int_op(connection_half_edge_is_valid_end(circ->half_streams,
            23), OP_EQ, 0);

  /* Insert a duplicate element; verify that other elements absent;
   * ensure removing it once works */
  edgeconn->stream_id = 23;
  connection_half_edge_add(edgeconn, circ);
  connection_half_edge_add(edgeconn, circ);
  connection_half_edge_add(edgeconn, circ);

  /* Verify that other elements absent */
  tt_int_op(connection_half_edge_is_valid_data(circ->half_streams,
            22), OP_EQ, 0);
  tt_int_op(connection_half_edge_is_valid_connected(circ->half_streams,
            22), OP_EQ, 0);
  tt_int_op(connection_half_edge_is_valid_sendme(circ->half_streams,
            22), OP_EQ, 0);
  tt_int_op(connection_half_edge_is_valid_resolved(circ->half_streams,
            22), OP_EQ, 0);
  tt_int_op(connection_half_edge_is_valid_end(circ->half_streams,
            22), OP_EQ, 0);

  tt_int_op(connection_half_edge_is_valid_data(circ->half_streams,
            24), OP_EQ, 0);
  tt_int_op(connection_half_edge_is_valid_connected(circ->half_streams,
            24), OP_EQ, 0);
  tt_int_op(connection_half_edge_is_valid_sendme(circ->half_streams,
            24), OP_EQ, 0);
  tt_int_op(connection_half_edge_is_valid_resolved(circ->half_streams,
            24), OP_EQ, 0);
  tt_int_op(connection_half_edge_is_valid_end(circ->half_streams,
            24), OP_EQ, 0);

  /* Verify we only remove it once */
  tt_int_op(connection_half_edge_is_valid_end(circ->half_streams,
            23), OP_EQ, 1);
  tt_int_op(connection_half_edge_is_valid_end(circ->half_streams,
            23), OP_EQ, 0);

  halfstream_insert(circ, edgeconn, streams, num, 1);

  /* Remove half of them */
  for (i = 0; i < num/2; i++) {
    tt_int_op(connection_half_edge_is_valid_end(circ->half_streams,
                                                streams[i]),
              OP_EQ, 1);
  }

  /* Verify first half of list is gone */
  for (i = 0; i < num/2; i++) {
    tt_ptr_op(connection_half_edge_find_stream_id(circ->half_streams,
                                                  streams[i]),
              OP_EQ, NULL);
  }

  /* Verify second half of list is present */
  for (; i < num; i++) {
    tt_ptr_op(connection_half_edge_find_stream_id(circ->half_streams,
                                                  streams[i]),
              OP_NE, NULL);
  }

  /* Remove other half. Verify list is empty. */
  for (i = num/2; i < num; i++) {
    tt_int_op(connection_half_edge_is_valid_end(circ->half_streams,
                                                streams[i]),
              OP_EQ, 1);
  }
  tt_int_op(smartlist_len(circ->half_streams), OP_EQ, 0);

  /* Explicity test all operations on an empty stream list */
  tt_int_op(connection_half_edge_is_valid_data(circ->half_streams,
            23), OP_EQ, 0);
  tt_int_op(connection_half_edge_is_valid_connected(circ->half_streams,
            23), OP_EQ, 0);
  tt_int_op(connection_half_edge_is_valid_sendme(circ->half_streams,
            23), OP_EQ, 0);
  tt_int_op(connection_half_edge_is_valid_resolved(circ->half_streams,
            23), OP_EQ, 0);
  tt_int_op(connection_half_edge_is_valid_end(circ->half_streams,
            23), OP_EQ, 0);

  /* For valgrind, leave some around then free the circ */
  halfstream_insert(circ, edgeconn, NULL, 10, 0);

 done:
  tor_free(streams);
  circuit_free_(TO_CIRCUIT(circ));
  connection_free_minimal(ENTRY_TO_CONN(entryconn));
}
Esempio n. 24
0
static void
test_router_get_my_family(void *arg)
{
  (void)arg;
  or_options_t *options = options_new();
  smartlist_t *sl = NULL;
  char *join = NULL;
  // Overwrite the result of router_get_my_identity_digest().  This
  // happens to be okay, but only for testing.
  set_server_identity_key_digest_testing(
                                   (const uint8_t*)"holeinthebottomofthe");

  setup_capture_of_logs(LOG_WARN);

  // No family listed -- so there's no list.
  sl = get_my_declared_family(options);
  tt_ptr_op(sl, OP_EQ, NULL);
  expect_no_log_entry();

#define CLEAR() do {                                    \
    if (sl) {                                           \
      SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));  \
      smartlist_free(sl);                               \
    }                                                   \
    tor_free(join);                                     \
    mock_clean_saved_logs();                            \
  } while (0)

  // Add a single nice friendly hex member.  This should be enough
  // to have our own ID added.
  tt_ptr_op(options->MyFamily, OP_EQ, NULL);
  config_line_append(&options->MyFamily, "MyFamily",
                     "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");

  sl = get_my_declared_family(options);
  tt_ptr_op(sl, OP_NE, NULL);
  tt_int_op(smartlist_len(sl), OP_EQ, 2);
  join = smartlist_join_strings(sl, " ", 0, NULL);
  tt_str_op(join, OP_EQ,
            "$686F6C65696E746865626F74746F6D6F66746865 "
            "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
  expect_no_log_entry();
  CLEAR();

  // Add a hex member with a ~.  The ~ part should get removed.
  config_line_append(&options->MyFamily, "MyFamily",
                     "$0123456789abcdef0123456789abcdef01234567~Muffin");
  sl = get_my_declared_family(options);
  tt_ptr_op(sl, OP_NE, NULL);
  tt_int_op(smartlist_len(sl), OP_EQ, 3);
  join = smartlist_join_strings(sl, " ", 0, NULL);
  tt_str_op(join, OP_EQ,
            "$0123456789ABCDEF0123456789ABCDEF01234567 "
            "$686F6C65696E746865626F74746F6D6F66746865 "
            "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
  expect_no_log_entry();
  CLEAR();

  // Nickname lookup will fail, so a nickname will appear verbatim.
  config_line_append(&options->MyFamily, "MyFamily",
                     "BAGEL");
  sl = get_my_declared_family(options);
  tt_ptr_op(sl, OP_NE, NULL);
  tt_int_op(smartlist_len(sl), OP_EQ, 4);
  join = smartlist_join_strings(sl, " ", 0, NULL);
  tt_str_op(join, OP_EQ,
            "$0123456789ABCDEF0123456789ABCDEF01234567 "
            "$686F6C65696E746865626F74746F6D6F66746865 "
            "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA "
            "bagel");
  expect_single_log_msg_containing(
           "There is a router named \"BAGEL\" in my declared family, but "
           "I have no descriptor for it.");
  CLEAR();

  // A bogus digest should fail entirely.
  config_line_append(&options->MyFamily, "MyFamily",
                     "$painauchocolat");
  sl = get_my_declared_family(options);
  tt_ptr_op(sl, OP_NE, NULL);
  tt_int_op(smartlist_len(sl), OP_EQ, 4);
  join = smartlist_join_strings(sl, " ", 0, NULL);
  tt_str_op(join, OP_EQ,
            "$0123456789ABCDEF0123456789ABCDEF01234567 "
            "$686F6C65696E746865626F74746F6D6F66746865 "
            "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA "
            "bagel");
  // "BAGEL" is still there, but it won't make a warning, because we already
  // warned about it.
  expect_single_log_msg_containing(
           "There is a router named \"$painauchocolat\" in my declared "
           "family, but that isn't a legal digest or nickname. Skipping it.");
  CLEAR();

  // Let's introduce a node we can look up by nickname
  memset(&fake_node, 0, sizeof(fake_node));
  memcpy(fake_node.identity, "whydoyouasknonononon", DIGEST_LEN);
  MOCK(node_get_by_nickname, mock_node_get_by_nickname);

  config_line_append(&options->MyFamily, "MyFamily",
                     "CRUmpeT");
  sl = get_my_declared_family(options);
  tt_ptr_op(sl, OP_NE, NULL);
  tt_int_op(smartlist_len(sl), OP_EQ, 5);
  join = smartlist_join_strings(sl, " ", 0, NULL);
  tt_str_op(join, OP_EQ,
            "$0123456789ABCDEF0123456789ABCDEF01234567 "
            "$686F6C65696E746865626F74746F6D6F66746865 "
            "$776879646F796F7561736B6E6F6E6F6E6F6E6F6E "
            "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA "
            "bagel");
  // "BAGEL" is still there, but it won't make a warning, because we already
  // warned about it.  Some with "$painauchocolat".
  expect_single_log_msg_containing(
           "There is a router named \"CRUmpeT\" in my declared "
           "family, but it wasn't listed by digest. Please consider saying "
           "$776879646F796F7561736B6E6F6E6F6E6F6E6F6E instead, if that's "
           "what you meant.");
  CLEAR();
  UNMOCK(node_get_by_nickname);

  // Try a singleton list containing only us: It should give us NULL.
  config_free_lines(options->MyFamily);
  config_line_append(&options->MyFamily, "MyFamily",
                     "$686F6C65696E746865626F74746F6D6F66746865");
  sl = get_my_declared_family(options);
  tt_ptr_op(sl, OP_EQ, NULL);
  expect_no_log_entry();

 done:
  or_options_free(options);
  teardown_capture_of_logs();
  CLEAR();
  UNMOCK(node_get_by_nickname);

#undef CLEAR
}
Esempio n. 25
0
static void
test_buffer_pullup(void *arg)
{
  buf_t *buf;
  char *stuff, *tmp;
  const char *cp;
  size_t sz;
  (void)arg;
  stuff = tor_malloc(16384);
  tmp = tor_malloc(16384);

  buf = buf_new_with_capacity(3000); /* rounds up to next power of 2. */

  tt_assert(buf);
  tt_int_op(buf_get_default_chunk_size(buf), OP_EQ, 4096);

  tt_int_op(buf_get_total_allocation(), OP_EQ, 0);

  /* There are a bunch of cases for pullup.  One is the trivial case. Let's
     mess around with an empty buffer. */
  buf_pullup(buf, 16);
  buf_get_first_chunk_data(buf, &cp, &sz);
  tt_ptr_op(cp, OP_EQ, NULL);
  tt_uint_op(sz, OP_EQ, 0);

  /* Let's make sure nothing got allocated */
  tt_int_op(buf_get_total_allocation(), OP_EQ, 0);

  /* Case 1: everything puts into the first chunk with some moving. */

  /* Let's add some data. */
  crypto_rand(stuff, 16384);
  write_to_buf(stuff, 3000, buf);
  write_to_buf(stuff+3000, 3000, buf);
  buf_get_first_chunk_data(buf, &cp, &sz);
  tt_ptr_op(cp, OP_NE, NULL);
  tt_int_op(sz, OP_LE, 4096);

  /* Make room for 3000 bytes in the first chunk, so that the pullup-move code
   * can get tested. */
  tt_int_op(fetch_from_buf(tmp, 3000, buf), OP_EQ, 3000);
  tt_mem_op(tmp,OP_EQ, stuff, 3000);
  buf_pullup(buf, 2048);
  assert_buf_ok(buf);
  buf_get_first_chunk_data(buf, &cp, &sz);
  tt_ptr_op(cp, OP_NE, NULL);
  tt_int_op(sz, OP_GE, 2048);
  tt_mem_op(cp,OP_EQ, stuff+3000, 2048);
  tt_int_op(3000, OP_EQ, buf_datalen(buf));
  tt_int_op(fetch_from_buf(tmp, 3000, buf), OP_EQ, 0);
  tt_mem_op(tmp,OP_EQ, stuff+3000, 2048);

  buf_free(buf);

  /* Now try the large-chunk case. */
  buf = buf_new_with_capacity(3000); /* rounds up to next power of 2. */
  write_to_buf(stuff, 4000, buf);
  write_to_buf(stuff+4000, 4000, buf);
  write_to_buf(stuff+8000, 4000, buf);
  write_to_buf(stuff+12000, 4000, buf);
  tt_int_op(buf_datalen(buf), OP_EQ, 16000);
  buf_get_first_chunk_data(buf, &cp, &sz);
  tt_ptr_op(cp, OP_NE, NULL);
  tt_int_op(sz, OP_LE, 4096);

  buf_pullup(buf, 12500);
  assert_buf_ok(buf);
  buf_get_first_chunk_data(buf, &cp, &sz);
  tt_ptr_op(cp, OP_NE, NULL);
  tt_int_op(sz, OP_GE, 12500);
  tt_mem_op(cp,OP_EQ, stuff, 12500);
  tt_int_op(buf_datalen(buf), OP_EQ, 16000);

  fetch_from_buf(tmp, 12400, buf);
  tt_mem_op(tmp,OP_EQ, stuff, 12400);
  tt_int_op(buf_datalen(buf), OP_EQ, 3600);
  fetch_from_buf(tmp, 3500, buf);
  tt_mem_op(tmp,OP_EQ, stuff+12400, 3500);
  fetch_from_buf(tmp, 100, buf);
  tt_mem_op(tmp,OP_EQ, stuff+15900, 10);

  buf_free(buf);

  /* Make sure that the pull-up-whole-buffer case works */
  buf = buf_new_with_capacity(3000); /* rounds up to next power of 2. */
  write_to_buf(stuff, 4000, buf);
  write_to_buf(stuff+4000, 4000, buf);
  fetch_from_buf(tmp, 100, buf); /* dump 100 bytes from first chunk */
  buf_pullup(buf, 16000); /* Way too much. */
  assert_buf_ok(buf);
  buf_get_first_chunk_data(buf, &cp, &sz);
  tt_ptr_op(cp, OP_NE, NULL);
  tt_int_op(sz, OP_EQ, 7900);
  tt_mem_op(cp,OP_EQ, stuff+100, 7900);

  buf_free(buf);
  buf = NULL;

  tt_int_op(buf_get_total_allocation(), OP_EQ, 0);
 done:
  buf_free(buf);
  tor_free(stuff);
  tor_free(tmp);
}
Esempio n. 26
0
static void
test_channel_for_extend(void *arg)
{
  channel_t *chan1 = NULL, *chan2 = NULL;
  channel_t *ret_chan = NULL;
  char digest[DIGEST_LEN];
  ed25519_public_key_t ed_id;
  tor_addr_t addr;
  const char *msg;
  int launch;
  time_t now = time(NULL);

  (void) arg;

  memset(digest, 'A', sizeof(digest));
  memset(&ed_id, 'B', sizeof(ed_id));

  chan1 = new_fake_channel();
  tt_assert(chan1);
  /* Need to be registered to get added to the id map. */
  channel_register(chan1);
  tt_int_op(chan1->registered, OP_EQ, 1);
  /* We need those for the test. */
  chan1->is_canonical = test_chan_is_canonical;
  chan1->matches_target = test_chan_matches_target;
  chan1->timestamp_created = now - 9;

  chan2 = new_fake_channel();
  tt_assert(chan2);
  /* Need to be registered to get added to the id map. */
  channel_register(chan2);
  tt_int_op(chan2->registered, OP_EQ, 1);
  /* We need those for the test. */
  chan2->is_canonical = test_chan_is_canonical;
  chan2->matches_target = test_chan_matches_target;
  /* Make it older than chan1. */
  chan2->timestamp_created = chan1->timestamp_created - 1;

  /* Set channel identities and add it to the channel map. The last one to be
   * added is made the first one in the list so the lookup will always return
   * that one first. */
  channel_set_identity_digest(chan2, digest, &ed_id);
  channel_set_identity_digest(chan1, digest, &ed_id);
  tt_ptr_op(channel_find_by_remote_identity(digest, NULL), OP_EQ, chan1);
  tt_ptr_op(channel_find_by_remote_identity(digest, &ed_id), OP_EQ, chan1);

  /* The expected result is chan2 because it is older than chan1. */
  ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
  tt_assert(ret_chan);
  tt_ptr_op(ret_chan, OP_EQ, chan2);
  tt_int_op(launch, OP_EQ, 0);
  tt_str_op(msg, OP_EQ, "Connection is fine; using it.");

  /* Switch that around from previous test. */
  chan2->timestamp_created = chan1->timestamp_created + 1;
  ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
  tt_assert(ret_chan);
  tt_ptr_op(ret_chan, OP_EQ, chan1);
  tt_int_op(launch, OP_EQ, 0);
  tt_str_op(msg, OP_EQ, "Connection is fine; using it.");

  /* Same creation time, num circuits will be used and they both have 0 so the
   * channel 2 should be picked due to how channel_is_better() work. */
  chan2->timestamp_created = chan1->timestamp_created;
  ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
  tt_assert(ret_chan);
  tt_ptr_op(ret_chan, OP_EQ, chan1);
  tt_int_op(launch, OP_EQ, 0);
  tt_str_op(msg, OP_EQ, "Connection is fine; using it.");

  /* For the rest of the tests, we need channel 1 to be the older. */
  chan2->timestamp_created = chan1->timestamp_created + 1;

  /* Condemned the older channel. */
  chan1->state = CHANNEL_STATE_CLOSING;
  ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
  tt_assert(ret_chan);
  tt_ptr_op(ret_chan, OP_EQ, chan2);
  tt_int_op(launch, OP_EQ, 0);
  tt_str_op(msg, OP_EQ, "Connection is fine; using it.");
  chan1->state = CHANNEL_STATE_OPEN;

  /* Make the older channel a client one. */
  channel_mark_client(chan1);
  ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
  tt_assert(ret_chan);
  tt_ptr_op(ret_chan, OP_EQ, chan2);
  tt_int_op(launch, OP_EQ, 0);
  tt_str_op(msg, OP_EQ, "Connection is fine; using it.");
  channel_clear_client(chan1);

  /* Non matching ed identity with valid digest. */
  ed25519_public_key_t dumb_ed_id;
  memset(&dumb_ed_id, 0, sizeof(dumb_ed_id));
  ret_chan = channel_get_for_extend(digest, &dumb_ed_id, &addr, &msg,
                                    &launch);
  tt_assert(!ret_chan);
  tt_str_op(msg, OP_EQ, "Not connected. Connecting.");
  tt_int_op(launch, OP_EQ, 1);

  /* Opening channel, we'll check if the target address matches. */
  test_chan_should_match_target = 1;
  chan1->state = CHANNEL_STATE_OPENING;
  chan2->state = CHANNEL_STATE_OPENING;
  ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
  tt_assert(!ret_chan);
  tt_str_op(msg, OP_EQ, "Connection in progress; waiting.");
  tt_int_op(launch, OP_EQ, 0);
  chan1->state = CHANNEL_STATE_OPEN;
  chan2->state = CHANNEL_STATE_OPEN;

  /* Mark channel 1 as bad for circuits. */
  channel_mark_bad_for_new_circs(chan1);
  ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
  tt_assert(ret_chan);
  tt_ptr_op(ret_chan, OP_EQ, chan2);
  tt_int_op(launch, OP_EQ, 0);
  tt_str_op(msg, OP_EQ, "Connection is fine; using it.");
  chan1->is_bad_for_new_circs = 0;

  /* Mark both channels as unusable. */
  channel_mark_bad_for_new_circs(chan1);
  channel_mark_bad_for_new_circs(chan2);
  ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
  tt_assert(!ret_chan);
  tt_str_op(msg, OP_EQ, "Connections all too old, or too non-canonical. "
                        " Launching a new one.");
  tt_int_op(launch, OP_EQ, 1);
  chan1->is_bad_for_new_circs = 0;
  chan2->is_bad_for_new_circs = 0;

  /* Non canonical channels. */
  test_chan_should_match_target = 0;
  test_chan_canonical_should_be_reliable = 1;
  ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
  tt_assert(!ret_chan);
  tt_str_op(msg, OP_EQ, "Connections all too old, or too non-canonical. "
                        " Launching a new one.");
  tt_int_op(launch, OP_EQ, 1);

 done:
  free_fake_channel(chan1);
  free_fake_channel(chan2);
}
Esempio n. 27
0
File: test_hs.c Progetto: ageis/tor
/* Test that single onion poisoning works. */
static void
test_single_onion_poisoning(void *arg)
{
  or_options_t opt;
  mock_options = &opt;
  reset_options(mock_options, &mock_get_options_calls);
  MOCK(get_options, mock_get_options);

  int ret = -1;
  intptr_t create_dir_mask = (intptr_t)arg;
  /* Get directories with a random suffix so we can repeat the tests */
  mock_options->DataDirectory = tor_strdup(get_fname_rnd("test_data_dir"));
  rend_service_t *service_1 = tor_malloc_zero(sizeof(rend_service_t));
  char *dir1 = tor_strdup(get_fname_rnd("test_hs_dir1"));
  rend_service_t *service_2 = tor_malloc_zero(sizeof(rend_service_t));
  char *dir2 = tor_strdup(get_fname_rnd("test_hs_dir2"));
  smartlist_t *services = smartlist_new();
  char *poison_path = NULL;
  char *err_msg = NULL;

  mock_options->HiddenServiceSingleHopMode = 1;
  mock_options->HiddenServiceNonAnonymousMode = 1;

  /* Create the data directory, and, if the correct bit in arg is set,
   * create a directory for that service.
   * The data directory is required for the lockfile, which is used when
   * loading keys. */
  ret = check_private_dir(mock_options->DataDirectory, CPD_CREATE, NULL);
  tt_int_op(ret, OP_EQ, 0);
  if (create_dir_mask & CREATE_HS_DIR1) {
    ret = check_private_dir(dir1, CPD_CREATE, NULL);
    tt_int_op(ret, OP_EQ, 0);
  }
  if (create_dir_mask & CREATE_HS_DIR2) {
    ret = check_private_dir(dir2, CPD_CREATE, NULL);
    tt_int_op(ret, OP_EQ, 0);
  }

  service_1->directory = dir1;
  service_2->directory = dir2;
  /* The services own the directory pointers now */
  dir1 = dir2 = NULL;
  /* Add port to service 1 */
  service_1->ports = smartlist_new();
  service_2->ports = smartlist_new();
  rend_service_port_config_t *port1 = rend_service_parse_port_config("80", " ",
                                                                     &err_msg);
  tt_assert(port1);
  tt_ptr_op(err_msg, OP_EQ, NULL);
  smartlist_add(service_1->ports, port1);

  rend_service_port_config_t *port2 = rend_service_parse_port_config("90", " ",
                                                                     &err_msg);
  /* Add port to service 2 */
  tt_assert(port2);
  tt_ptr_op(err_msg, OP_EQ, NULL);
  smartlist_add(service_2->ports, port2);

  /* No services, a service to verify, no problem! */
  mock_options->HiddenServiceSingleHopMode = 0;
  mock_options->HiddenServiceNonAnonymousMode = 0;
  ret = rend_service_verify_single_onion_poison(service_1, mock_options);
  tt_int_op(ret, OP_EQ, 0);
  ret = rend_service_verify_single_onion_poison(service_2, mock_options);
  tt_int_op(ret, OP_EQ, 0);

  /* Either way, no problem. */
  mock_options->HiddenServiceSingleHopMode = 1;
  mock_options->HiddenServiceNonAnonymousMode = 1;
  ret = rend_service_verify_single_onion_poison(service_1, mock_options);
  tt_int_op(ret, OP_EQ, 0);
  ret = rend_service_verify_single_onion_poison(service_2, mock_options);
  tt_int_op(ret, OP_EQ, 0);

  /* Add the first service */
  ret = hs_check_service_private_dir(mock_options->User, service_1->directory,
                                     service_1->dir_group_readable, 1);
  tt_int_op(ret, OP_EQ, 0);
  smartlist_add(services, service_1);
  /* But don't add the second service yet. */

  /* Service directories, but no previous keys, no problem! */
  mock_options->HiddenServiceSingleHopMode = 0;
  mock_options->HiddenServiceNonAnonymousMode = 0;
  ret = rend_service_verify_single_onion_poison(service_1, mock_options);
  tt_int_op(ret, OP_EQ, 0);
  ret = rend_service_verify_single_onion_poison(service_2, mock_options);
  tt_int_op(ret, OP_EQ, 0);

  /* Either way, no problem. */
  mock_options->HiddenServiceSingleHopMode = 1;
  mock_options->HiddenServiceNonAnonymousMode = 1;
  ret = rend_service_verify_single_onion_poison(service_1, mock_options);
  tt_int_op(ret, OP_EQ, 0);
  ret = rend_service_verify_single_onion_poison(service_2, mock_options);
  tt_int_op(ret, OP_EQ, 0);

  /* Poison! Poison! Poison!
   * This can only be done in HiddenServiceSingleHopMode. */
  mock_options->HiddenServiceSingleHopMode = 1;
  mock_options->HiddenServiceNonAnonymousMode = 1;
  ret = rend_service_poison_new_single_onion_dir(service_1, mock_options);
  tt_int_op(ret, OP_EQ, 0);
  /* Poisoning twice is a no-op. */
  ret = rend_service_poison_new_single_onion_dir(service_1, mock_options);
  tt_int_op(ret, OP_EQ, 0);

  /* Poisoned service directories, but no previous keys, no problem! */
  mock_options->HiddenServiceSingleHopMode = 0;
  mock_options->HiddenServiceNonAnonymousMode = 0;
  ret = rend_service_verify_single_onion_poison(service_1, mock_options);
  tt_int_op(ret, OP_EQ, 0);
  ret = rend_service_verify_single_onion_poison(service_2, mock_options);
  tt_int_op(ret, OP_EQ, 0);

  /* Either way, no problem. */
  mock_options->HiddenServiceSingleHopMode = 1;
  mock_options->HiddenServiceNonAnonymousMode = 1;
  ret = rend_service_verify_single_onion_poison(service_1, mock_options);
  tt_int_op(ret, OP_EQ, 0);
  ret = rend_service_verify_single_onion_poison(service_2, mock_options);
  tt_int_op(ret, OP_EQ, 0);

  /* Now add some keys, and we'll have a problem. */
  ret = rend_service_load_all_keys(services);
  tt_int_op(ret, OP_EQ, 0);

  /* Poisoned service directories with previous keys are not allowed. */
  mock_options->HiddenServiceSingleHopMode = 0;
  mock_options->HiddenServiceNonAnonymousMode = 0;
  ret = rend_service_verify_single_onion_poison(service_1, mock_options);
  tt_int_op(ret, OP_LT, 0);
  ret = rend_service_verify_single_onion_poison(service_2, mock_options);
  tt_int_op(ret, OP_EQ, 0);

  /* But they are allowed if we're in non-anonymous mode. */
  mock_options->HiddenServiceSingleHopMode = 1;
  mock_options->HiddenServiceNonAnonymousMode = 1;
  ret = rend_service_verify_single_onion_poison(service_1, mock_options);
  tt_int_op(ret, OP_EQ, 0);
  ret = rend_service_verify_single_onion_poison(service_2, mock_options);
  tt_int_op(ret, OP_EQ, 0);

  /* Re-poisoning directories with existing keys is a no-op, because
   * directories with existing keys are ignored. */
  mock_options->HiddenServiceSingleHopMode = 1;
  mock_options->HiddenServiceNonAnonymousMode = 1;
  ret = rend_service_poison_new_single_onion_dir(service_1, mock_options);
  tt_int_op(ret, OP_EQ, 0);
  /* And it keeps the poison. */
  ret = rend_service_verify_single_onion_poison(service_1, mock_options);
  tt_int_op(ret, OP_EQ, 0);
  ret = rend_service_verify_single_onion_poison(service_2, mock_options);
  tt_int_op(ret, OP_EQ, 0);

  /* Now add the second service: it has no key and no poison file */
  ret = hs_check_service_private_dir(mock_options->User, service_2->directory,
                                     service_2->dir_group_readable, 1);
  tt_int_op(ret, OP_EQ, 0);
  smartlist_add(services, service_2);

  /* A new service, and an existing poisoned service. Not ok. */
  mock_options->HiddenServiceSingleHopMode = 0;
  mock_options->HiddenServiceNonAnonymousMode = 0;
  ret = rend_service_verify_single_onion_poison(service_1, mock_options);
  tt_int_op(ret, OP_LT, 0);
  ret = rend_service_verify_single_onion_poison(service_2, mock_options);
  tt_int_op(ret, OP_EQ, 0);

  /* But ok to add in non-anonymous mode. */
  mock_options->HiddenServiceSingleHopMode = 1;
  mock_options->HiddenServiceNonAnonymousMode = 1;
  ret = rend_service_verify_single_onion_poison(service_1, mock_options);
  tt_int_op(ret, OP_EQ, 0);
  ret = rend_service_verify_single_onion_poison(service_2, mock_options);
  tt_int_op(ret, OP_EQ, 0);

  /* Now remove the poisoning from the first service, and we have the opposite
   * problem. */
  poison_path = rend_service_sos_poison_path(service_1);
  tt_assert(poison_path);
  ret = unlink(poison_path);
  tt_int_op(ret, OP_EQ, 0);

  /* Unpoisoned service directories with previous keys are ok, as are empty
   * directories. */
  mock_options->HiddenServiceSingleHopMode = 0;
  mock_options->HiddenServiceNonAnonymousMode = 0;
  ret = rend_service_verify_single_onion_poison(service_1, mock_options);
  tt_int_op(ret, OP_EQ, 0);
  ret = rend_service_verify_single_onion_poison(service_2, mock_options);
  tt_int_op(ret, OP_EQ, 0);

  /* But the existing unpoisoned key is not ok in non-anonymous mode, even if
   * there is an empty service. */
  mock_options->HiddenServiceSingleHopMode = 1;
  mock_options->HiddenServiceNonAnonymousMode = 1;
  ret = rend_service_verify_single_onion_poison(service_1, mock_options);
  tt_int_op(ret, OP_LT, 0);
  ret = rend_service_verify_single_onion_poison(service_2, mock_options);
  tt_int_op(ret, OP_EQ, 0);

  /* Poisoning directories with existing keys is a no-op, because directories
   * with existing keys are ignored. But the new directory should poison. */
  mock_options->HiddenServiceSingleHopMode = 1;
  mock_options->HiddenServiceNonAnonymousMode = 1;
  ret = rend_service_poison_new_single_onion_dir(service_1, mock_options);
  tt_int_op(ret, OP_EQ, 0);
  ret = rend_service_poison_new_single_onion_dir(service_2, mock_options);
  tt_int_op(ret, OP_EQ, 0);
  /* And the old directory remains unpoisoned. */
  ret = rend_service_verify_single_onion_poison(service_1, mock_options);
  tt_int_op(ret, OP_LT, 0);
  ret = rend_service_verify_single_onion_poison(service_2, mock_options);
  tt_int_op(ret, OP_EQ, 0);

  /* And the new directory should be ignored, because it has no key. */
  mock_options->HiddenServiceSingleHopMode = 0;
  mock_options->HiddenServiceNonAnonymousMode = 0;
  ret = rend_service_verify_single_onion_poison(service_1, mock_options);
  tt_int_op(ret, OP_EQ, 0);
  ret = rend_service_verify_single_onion_poison(service_2, mock_options);
  tt_int_op(ret, OP_EQ, 0);

  /* Re-poisoning directories without existing keys is a no-op. */
  mock_options->HiddenServiceSingleHopMode = 1;
  mock_options->HiddenServiceNonAnonymousMode = 1;
  ret = rend_service_poison_new_single_onion_dir(service_1, mock_options);
  tt_int_op(ret, OP_EQ, 0);
  ret = rend_service_poison_new_single_onion_dir(service_2, mock_options);
  tt_int_op(ret, OP_EQ, 0);
  /* And the old directory remains unpoisoned. */
  ret = rend_service_verify_single_onion_poison(service_1, mock_options);
  tt_int_op(ret, OP_LT, 0);
  ret = rend_service_verify_single_onion_poison(service_2, mock_options);
  tt_int_op(ret, OP_EQ, 0);

 done:
  /* The test harness deletes the directories at exit */
  tor_free(poison_path);
  tor_free(dir1);
  tor_free(dir2);
  smartlist_free(services);
  rend_service_free(service_1);
  rend_service_free(service_2);
  UNMOCK(get_options);
  tor_free(mock_options->DataDirectory);
  tor_free(err_msg);
}
Esempio n. 28
0
static void
test_channel_dumpstats(void *arg)
{
  channel_t *ch = NULL;
  cell_t *cell = NULL;
  packed_cell_t *p_cell = NULL;
  int old_count;

  (void)arg;

  /* Mock these for duration of the test */
  MOCK(scheduler_channel_doesnt_want_writes,
       scheduler_channel_doesnt_want_writes_mock);
  MOCK(scheduler_release_channel,
       scheduler_release_channel_mock);

  /* Set up a new fake channel */
  ch = new_fake_channel();
  tt_assert(ch);

  /* Try to register it */
  channel_register(ch);
  tt_assert(ch->registered);

  /* Set up mock */
  dump_statistics_mock_target = ch;
  dump_statistics_mock_matches = 0;
  MOCK(channel_dump_statistics,
       chan_test_channel_dump_statistics_mock);

  /* Call channel_dumpstats() */
  channel_dumpstats(LOG_DEBUG);

  /* Assert that we hit the mock */
  tt_int_op(dump_statistics_mock_matches, OP_EQ, 1);

  /* Close the channel */
  channel_mark_for_close(ch);
  tt_int_op(ch->state, OP_EQ, CHANNEL_STATE_CLOSING);
  chan_test_finish_close(ch);
  tt_int_op(ch->state, OP_EQ, CHANNEL_STATE_CLOSED);

  /* Try again and hit the finished channel */
  channel_dumpstats(LOG_DEBUG);
  tt_int_op(dump_statistics_mock_matches, OP_EQ, 2);

  channel_run_cleanup();
  ch = NULL;

  /* Now we should hit nothing */
  channel_dumpstats(LOG_DEBUG);
  tt_int_op(dump_statistics_mock_matches, OP_EQ, 2);

  /* Unmock */
  UNMOCK(channel_dump_statistics);
  dump_statistics_mock_target = NULL;
  dump_statistics_mock_matches = 0;

  /* Now make another channel */
  ch = new_fake_channel();
  tt_assert(ch);
  channel_register(ch);
  tt_int_op(ch->registered, OP_EQ, 1);
  /* Lie about its age so dumpstats gets coverage for rate calculations */
  ch->timestamp_created = time(NULL) - 30;
  tt_int_op(ch->timestamp_created, OP_GT, 0);
  tt_int_op(time(NULL), OP_GT, ch->timestamp_created);

  /* Put cells through it both ways to make the counters non-zero */
  p_cell = packed_cell_new();
  test_chan_accept_cells = 1;
  old_count = test_cells_written;
  channel_write_packed_cell(ch, p_cell);
  tt_int_op(test_cells_written, OP_EQ, old_count + 1);
  tt_u64_op(ch->n_bytes_xmitted, OP_GT, 0);
  tt_u64_op(ch->n_cells_xmitted, OP_GT, 0);

  /* Receive path */
  channel_set_cell_handlers(ch,
                            chan_test_cell_handler,
                            chan_test_var_cell_handler);
  tt_ptr_op(channel_get_cell_handler(ch), OP_EQ, chan_test_cell_handler);
  tt_ptr_op(channel_get_var_cell_handler(ch), OP_EQ,
            chan_test_var_cell_handler);
  cell = tor_malloc_zero(sizeof(*cell));
  old_count = test_chan_fixed_cells_recved;
  channel_process_cell(ch, cell);
  tt_int_op(test_chan_fixed_cells_recved, OP_EQ, old_count + 1);
  tt_u64_op(ch->n_bytes_recved, OP_GT, 0);
  tt_u64_op(ch->n_cells_recved, OP_GT, 0);

  /* Test channel_dump_statistics */
  ch->describe_transport = chan_test_describe_transport;
  ch->dumpstats = chan_test_dumpstats;
  test_chan_should_be_canonical = 1;
  ch->is_canonical = test_chan_is_canonical;
  old_count = test_dumpstats_calls;
  channel_dump_statistics(ch, LOG_DEBUG);
  tt_int_op(test_dumpstats_calls, OP_EQ, old_count + 1);

  /* Close the channel */
  channel_mark_for_close(ch);
  tt_int_op(ch->state, OP_EQ, CHANNEL_STATE_CLOSING);
  chan_test_finish_close(ch);
  tt_int_op(ch->state, OP_EQ, CHANNEL_STATE_CLOSED);
  channel_run_cleanup();
  ch = NULL;

 done:
  free_fake_channel(ch);
  tor_free(cell);

  UNMOCK(scheduler_channel_doesnt_want_writes);
  UNMOCK(scheduler_release_channel);

  return;
}
Esempio n. 29
0
static void
test_clist_maps(void *arg)
{
  channel_t *ch1 = new_fake_channel();
  channel_t *ch2 = new_fake_channel();
  channel_t *ch3 = new_fake_channel();
  or_circuit_t *or_c1=NULL, *or_c2=NULL;

  (void) arg;

  MOCK(circuitmux_attach_circuit, circuitmux_attach_mock);
  MOCK(circuitmux_detach_circuit, circuitmux_detach_mock);
  memset(&cam, 0, sizeof(cam));
  memset(&cdm, 0, sizeof(cdm));

  tt_assert(ch1);
  tt_assert(ch2);
  tt_assert(ch3);

  ch1->cmux = tor_malloc(1);
  ch2->cmux = tor_malloc(1);
  ch3->cmux = tor_malloc(1);

  or_c1 = or_circuit_new(100, ch2);
  tt_assert(or_c1);
  GOT_CMUX_ATTACH(ch2->cmux, or_c1, CELL_DIRECTION_IN);
  tt_int_op(or_c1->p_circ_id, OP_EQ, 100);
  tt_ptr_op(or_c1->p_chan, OP_EQ, ch2);

  or_c2 = or_circuit_new(100, ch1);
  tt_assert(or_c2);
  GOT_CMUX_ATTACH(ch1->cmux, or_c2, CELL_DIRECTION_IN);
  tt_int_op(or_c2->p_circ_id, OP_EQ, 100);
  tt_ptr_op(or_c2->p_chan, OP_EQ, ch1);

  circuit_set_n_circid_chan(TO_CIRCUIT(or_c1), 200, ch1);
  GOT_CMUX_ATTACH(ch1->cmux, or_c1, CELL_DIRECTION_OUT);

  circuit_set_n_circid_chan(TO_CIRCUIT(or_c2), 200, ch2);
  GOT_CMUX_ATTACH(ch2->cmux, or_c2, CELL_DIRECTION_OUT);

  tt_ptr_op(circuit_get_by_circid_channel(200, ch1), OP_EQ, TO_CIRCUIT(or_c1));
  tt_ptr_op(circuit_get_by_circid_channel(200, ch2), OP_EQ, TO_CIRCUIT(or_c2));
  tt_ptr_op(circuit_get_by_circid_channel(100, ch2), OP_EQ, TO_CIRCUIT(or_c1));
  /* Try the same thing again, to test the "fast" path. */
  tt_ptr_op(circuit_get_by_circid_channel(100, ch2), OP_EQ, TO_CIRCUIT(or_c1));
  tt_assert(circuit_id_in_use_on_channel(100, ch2));
  tt_assert(! circuit_id_in_use_on_channel(101, ch2));

  /* Try changing the circuitid and channel of that circuit. */
  circuit_set_p_circid_chan(or_c1, 500, ch3);
  GOT_CMUX_DETACH(ch2->cmux, TO_CIRCUIT(or_c1));
  GOT_CMUX_ATTACH(ch3->cmux, TO_CIRCUIT(or_c1), CELL_DIRECTION_IN);
  tt_ptr_op(circuit_get_by_circid_channel(100, ch2), OP_EQ, NULL);
  tt_assert(! circuit_id_in_use_on_channel(100, ch2));
  tt_ptr_op(circuit_get_by_circid_channel(500, ch3), OP_EQ, TO_CIRCUIT(or_c1));

  /* Now let's see about destroy handling. */
  tt_assert(! circuit_id_in_use_on_channel(205, ch2));
  tt_assert(circuit_id_in_use_on_channel(200, ch2));
  channel_note_destroy_pending(ch2, 200);
  channel_note_destroy_pending(ch2, 205);
  channel_note_destroy_pending(ch1, 100);
  tt_assert(circuit_id_in_use_on_channel(205, ch2))
  tt_assert(circuit_id_in_use_on_channel(200, ch2));
  tt_assert(circuit_id_in_use_on_channel(100, ch1));

  tt_assert(TO_CIRCUIT(or_c2)->n_delete_pending != 0);
  tt_ptr_op(circuit_get_by_circid_channel(200, ch2), OP_EQ, TO_CIRCUIT(or_c2));
  tt_ptr_op(circuit_get_by_circid_channel(100, ch1), OP_EQ, TO_CIRCUIT(or_c2));

  /* Okay, now free ch2 and make sure that the circuit ID is STILL not
   * usable, because we haven't declared the destroy to be nonpending */
  tt_int_op(cdm.ncalls, OP_EQ, 0);
  circuit_free(TO_CIRCUIT(or_c2));
  or_c2 = NULL; /* prevent free */
  tt_int_op(cdm.ncalls, OP_EQ, 2);
  memset(&cdm, 0, sizeof(cdm));
  tt_assert(circuit_id_in_use_on_channel(200, ch2));
  tt_assert(circuit_id_in_use_on_channel(100, ch1));
  tt_ptr_op(circuit_get_by_circid_channel(200, ch2), OP_EQ, NULL);
  tt_ptr_op(circuit_get_by_circid_channel(100, ch1), OP_EQ, NULL);

  /* Now say that the destroy is nonpending */
  channel_note_destroy_not_pending(ch2, 200);
  tt_ptr_op(circuit_get_by_circid_channel(200, ch2), OP_EQ, NULL);
  channel_note_destroy_not_pending(ch1, 100);
  tt_ptr_op(circuit_get_by_circid_channel(100, ch1), OP_EQ, NULL);
  tt_assert(! circuit_id_in_use_on_channel(200, ch2));
  tt_assert(! circuit_id_in_use_on_channel(100, ch1));

 done:
  if (or_c1)
    circuit_free(TO_CIRCUIT(or_c1));
  if (or_c2)
    circuit_free(TO_CIRCUIT(or_c2));
  if (ch1)
    tor_free(ch1->cmux);
  if (ch2)
    tor_free(ch2->cmux);
  if (ch3)
    tor_free(ch3->cmux);
  tor_free(ch1);
  tor_free(ch2);
  tor_free(ch3);
  UNMOCK(circuitmux_attach_circuit);
  UNMOCK(circuitmux_detach_circuit);
}
Esempio n. 30
0
static void
test_channel_id_map(void *arg)
{
  (void)arg;
#define N_CHAN 6
  char rsa_id[N_CHAN][DIGEST_LEN];
  ed25519_public_key_t *ed_id[N_CHAN];
  channel_t *chan[N_CHAN];
  int i;
  ed25519_public_key_t ed_zero;
  memset(&ed_zero, 0, sizeof(ed_zero));

  tt_int_op(DIGEST_LEN, OP_EQ, sizeof(rsa_id[0])); // Do I remember C?

  for (i = 0; i < N_CHAN; ++i) {
    crypto_rand(rsa_id[i], DIGEST_LEN);
    ed_id[i] = tor_malloc_zero(sizeof(*ed_id[i]));
    crypto_rand((char*)ed_id[i]->pubkey, sizeof(ed_id[i]->pubkey));
  }

  /* For channel 3, have no Ed identity. */
  tor_free(ed_id[3]);

  /* Channel 2 and 4 have same ROSA identity */
  memcpy(rsa_id[4], rsa_id[2], DIGEST_LEN);

  /* Channel 2 and 4 and 5 have same RSA identity */
  memcpy(rsa_id[4], rsa_id[2], DIGEST_LEN);
  memcpy(rsa_id[5], rsa_id[2], DIGEST_LEN);

  /* Channels 2 and 5 have same Ed25519 identity */
  memcpy(ed_id[5], ed_id[2], sizeof(*ed_id[2]));

  for (i = 0; i < N_CHAN; ++i) {
    chan[i] = new_fake_channel();
    channel_register(chan[i]);
    channel_set_identity_digest(chan[i], rsa_id[i], ed_id[i]);
  }

  /* Lookup by RSA id only */
  tt_ptr_op(chan[0], OP_EQ,
            channel_find_by_remote_identity(rsa_id[0], NULL));
  tt_ptr_op(chan[1], OP_EQ,
            channel_find_by_remote_identity(rsa_id[1], NULL));
  tt_ptr_op(chan[3], OP_EQ,
            channel_find_by_remote_identity(rsa_id[3], NULL));
  channel_t *ch;
  ch = channel_find_by_remote_identity(rsa_id[2], NULL);
  tt_assert(ch == chan[2] || ch == chan[4] || ch == chan[5]);
  ch = channel_next_with_rsa_identity(ch);
  tt_assert(ch == chan[2] || ch == chan[4] || ch == chan[5]);
  ch = channel_next_with_rsa_identity(ch);
  tt_assert(ch == chan[2] || ch == chan[4] || ch == chan[5]);
  ch = channel_next_with_rsa_identity(ch);
  tt_ptr_op(ch, OP_EQ, NULL);

  /* As above, but with zero Ed25519 ID (meaning "any ID") */
  tt_ptr_op(chan[0], OP_EQ,
            channel_find_by_remote_identity(rsa_id[0], &ed_zero));
  tt_ptr_op(chan[1], OP_EQ,
            channel_find_by_remote_identity(rsa_id[1], &ed_zero));
  tt_ptr_op(chan[3], OP_EQ,
            channel_find_by_remote_identity(rsa_id[3], &ed_zero));
  ch = channel_find_by_remote_identity(rsa_id[2], &ed_zero);
  tt_assert(ch == chan[2] || ch == chan[4] || ch == chan[5]);
  ch = channel_next_with_rsa_identity(ch);
  tt_assert(ch == chan[2] || ch == chan[4] || ch == chan[5]);
  ch = channel_next_with_rsa_identity(ch);
  tt_assert(ch == chan[2] || ch == chan[4] || ch == chan[5]);
  ch = channel_next_with_rsa_identity(ch);
  tt_ptr_op(ch, OP_EQ, NULL);

  /* Lookup nonexistent RSA identity */
  tt_ptr_op(NULL, OP_EQ,
            channel_find_by_remote_identity("!!!!!!!!!!!!!!!!!!!!", NULL));

  /* Look up by full identity pair */
  tt_ptr_op(chan[0], OP_EQ,
            channel_find_by_remote_identity(rsa_id[0], ed_id[0]));
  tt_ptr_op(chan[1], OP_EQ,
            channel_find_by_remote_identity(rsa_id[1], ed_id[1]));
  tt_ptr_op(chan[3], OP_EQ,
            channel_find_by_remote_identity(rsa_id[3], ed_id[3] /*NULL*/));
  tt_ptr_op(chan[4], OP_EQ,
            channel_find_by_remote_identity(rsa_id[4], ed_id[4]));
  ch = channel_find_by_remote_identity(rsa_id[2], ed_id[2]);
  tt_assert(ch == chan[2] || ch == chan[5]);

  /* Look up RSA identity with wrong ed25519 identity */
  tt_ptr_op(NULL, OP_EQ,
            channel_find_by_remote_identity(rsa_id[4], ed_id[0]));
  tt_ptr_op(NULL, OP_EQ,
            channel_find_by_remote_identity(rsa_id[2], ed_id[1]));
  tt_ptr_op(NULL, OP_EQ,
            channel_find_by_remote_identity(rsa_id[3], ed_id[1]));

 done:
  for (i = 0; i < N_CHAN; ++i) {
    channel_clear_identity_digest(chan[i]);
    channel_unregister(chan[i]);
    free_fake_channel(chan[i]);
    tor_free(ed_id[i]);
  }
#undef N_CHAN
}