Esempio n. 1
0
/** Do common setup for test_timely_consensus() and
 * test_early_consensus().  Call networkstatus_set_current_consensus()
 * on a constructed consensus and with an appropriately-modified
 * approx_time.  Callers expect presence or absence of appropriate log
 * messages and control events. */
static int
test_skew_common(void *arg, time_t now, unsigned long *offset)
{
  char *consensus = NULL;
  int retval = 0;

  *offset = strtoul(arg, NULL, 10);

  /* Initialize the SRV subsystem */
  MOCK(get_my_v3_authority_cert, get_my_v3_authority_cert_m);
  mock_cert = authority_cert_parse_from_string(AUTHORITY_CERT_1,
                                               strlen(AUTHORITY_CERT_1),
                                               NULL);
  sr_init(0);
  UNMOCK(get_my_v3_authority_cert);

  construct_consensus(&consensus, now);
  tt_assert(consensus);

  update_approx_time(now + *offset);

  mock_apparent_skew = 0;
  /* Caller will call UNMOCK() */
  MOCK(clock_skew_warning, mock_clock_skew_warning);
  /* Caller will call teardown_capture_of_logs() */
  setup_capture_of_logs(LOG_WARN);
  retval = networkstatus_set_current_consensus(consensus, strlen(consensus),
                                               "microdesc", 0,
                                               NULL);

 done:
  tor_free(consensus);
  return retval;
}
static void
test_conn_edge_ap_handshake_rewrite_and_attach_closes_conn_for_excluded_exit(void *data)
{
  entry_connection_t *conn = entry_connection_new(CONN_TYPE_AP, AF_INET);
  addressmap_init();
  origin_circuit_t *circuit = NULL;
  crypt_path_t *path = NULL;
  (void) data;

  MOCK(get_options, get_options_mock);
  MOCK(connection_ap_handshake_rewrite, connection_ap_handshake_rewrite_mock);
  MOCK(connection_mark_unattached_ap_, connection_mark_unattached_ap_mock);
  MOCK(node_get_by_nickname, node_get_by_nickname_mock);

  init_rewrite_mock();
  init_exit_node_mock();
  init_mock_options();

  rewrite_mock->should_close = 0;
  rewrite_mock->exit_source = ADDRMAPSRC_NONE;
  SET_SOCKS_ADDRESS(conn->socks_request, "http://www.wellformed.exit");
  conn->socks_request->command = SOCKS_COMMAND_CONNECT;
  strlcpy(exit_node_mock->rs->nickname, "wellformed", MAX_NICKNAME_LEN+1);

  options_mock->AllowDotExit = 1;
  options_mock->StrictNodes = 0;
  options_mock->SafeLogging_ = SAFELOG_SCRUB_NONE;

  excluded_nodes = routerset_new();
  smartlist_add(excluded_nodes->list, tor_strdup("wellformed"));
  strmap_set(excluded_nodes->names, tor_strdup("wellformed"), exit_node_mock);
  options_mock->ExcludeExitNodes = excluded_nodes;

  int prev_log = setup_capture_of_logs(LOG_INFO);
  int res = connection_ap_handshake_rewrite_and_attach(conn, circuit, path);

  tt_int_op(unattachment_reason_spy, OP_EQ, END_STREAM_REASON_TORPROTOCOL);
  tt_int_op(res, OP_EQ, -1);
  tt_str_op(mock_saved_log_at(-1), OP_EQ, "Excluded relay in exit address 'http://www.exit'. Refusing.\n");

  done:
    UNMOCK(get_options);
    UNMOCK(connection_ap_handshake_rewrite);
    UNMOCK(connection_mark_unattached_ap_);
    UNMOCK(node_get_by_nickname);

    destroy_rewrite_mock();
    destroy_mock_options();
    destroy_exit_node_mock();
    tor_free(excluded_nodes);
    tor_free(circuit);
    tor_free(path);
    teardown_capture_of_logs(prev_log);
}
Esempio n. 3
0
/** Test warn_early_consensus(), expecting no warning  */
static void
test_warn_early_consensus_no(const networkstatus_t *c, time_t now,
                             long offset)
{
  mock_apparent_skew = 0;
  setup_capture_of_logs(LOG_WARN);
  warn_early_consensus(c, "microdesc", now + offset);
  expect_no_log_msg_containing("behind the time published in the consensus");
  tt_int_op(mock_apparent_skew, OP_EQ, 0);
 done:
  teardown_capture_of_logs();
}
Esempio n. 4
0
/** Test warn_early_consensus(), expecting a warning */
static void
test_warn_early_consensus_yes(const networkstatus_t *c, time_t now,
                              long offset)
{
  mock_apparent_skew = 0;
  setup_capture_of_logs(LOG_WARN);
  warn_early_consensus(c, "microdesc", now + offset);
  /* Can't use expect_single_log_msg() because of unrecognized authorities */
  expect_log_msg_containing("behind the time published in the consensus");
  tt_int_op(mock_apparent_skew, OP_EQ, offset);
 done:
  teardown_capture_of_logs();
}
Esempio n. 5
0
static void
test_util_process_clear_waitpid_callback(void *ignored)
{
  (void)ignored;
  waitpid_callback_t *res;
  int previous_log = setup_capture_of_logs(LOG_WARN);
  pid_t pid = (pid_t)43;

  clear_waitpid_callback(NULL);

  res = set_waitpid_callback(pid, temp_callback, NULL);
  clear_waitpid_callback(res);
  clear_waitpid_callback(res);

  // done:
  teardown_capture_of_logs(previous_log);
}
Esempio n. 6
0
static void
test_util_process_set_waitpid_callback(void *ignored)
{
  (void)ignored;
  waitpid_callback_t *res;
  int previous_log = setup_capture_of_logs(LOG_WARN);
  pid_t pid = (pid_t)42;

  res = set_waitpid_callback(pid, temp_callback, NULL);
  tt_assert(res);

  res = set_waitpid_callback(pid, temp_callback, NULL);
  tt_assert(res);
  tt_str_op(mock_saved_log_at(0), OP_EQ, "Replaced a waitpid monitor on pid 42. That should be impossible.\n");

 done:
  teardown_capture_of_logs(previous_log);
}
static void
test_conn_edge_ap_handshake_rewrite_and_attach_closes_conn_for_unrecognized_exit_address(void *data)
{
  entry_connection_t *conn = entry_connection_new(CONN_TYPE_AP, AF_INET);
  addressmap_init();
  origin_circuit_t *circuit = NULL;
  crypt_path_t *path = NULL;
  (void) data;

  MOCK(get_options, get_options_mock);
  MOCK(connection_ap_handshake_rewrite, connection_ap_handshake_rewrite_mock);
  MOCK(connection_mark_unattached_ap_, connection_mark_unattached_ap_mock);

  init_rewrite_mock();
  init_mock_options();

  rewrite_mock->should_close = 0;
  rewrite_mock->exit_source = ADDRMAPSRC_NONE;
  SET_SOCKS_ADDRESS(conn->socks_request, "http://www.wellformed.exit");
  conn->socks_request->command = SOCKS_COMMAND_CONNECT;
  options_mock->AllowDotExit = 1;
  options_mock->SafeLogging_ = SAFELOG_SCRUB_NONE;

  int prev_log = setup_capture_of_logs(LOG_INFO);
  int res = connection_ap_handshake_rewrite_and_attach(conn, circuit, path);

  tt_int_op(unattachment_reason_spy, OP_EQ, END_STREAM_REASON_TORPROTOCOL);
  tt_int_op(res, OP_EQ, -1);
  tt_str_op(mock_saved_log_at(-1), OP_EQ, "Unrecognized relay in exit address 'http://www.exit'. Refusing.\n");

  done:
    UNMOCK(get_options);
    UNMOCK(connection_ap_handshake_rewrite);
    UNMOCK(connection_mark_unattached_ap_);

    destroy_rewrite_mock();
    destroy_mock_options();
    tor_free(circuit);
    tor_free(path);
    teardown_capture_of_logs(prev_log);
}
Esempio n. 8
0
static void
test_util_process_set_waitpid_callback(void *ignored)
{
  (void)ignored;
  waitpid_callback_t *res1 = NULL, *res2 = NULL;
  int previous_log = setup_capture_of_logs(LOG_WARN);
  pid_t pid = (pid_t)42;

  res1 = set_waitpid_callback(pid, temp_callback, NULL);
  tt_assert(res1);

  res2 = set_waitpid_callback(pid, temp_callback, NULL);
  tt_assert(res2);
  expect_log_msg("Replaced a waitpid monitor on pid 42. That should be "
            "impossible.\n");

 done:
  teardown_capture_of_logs(previous_log);
  clear_waitpid_callback(res1);
  clear_waitpid_callback(res2);
}
static void
test_conn_edge_ap_handshake_rewrite_and_attach_closes_conn_when_hostname_is_bogus(void *data)
{
  entry_connection_t *conn = entry_connection_new(CONN_TYPE_AP, AF_INET);
  addressmap_init();
  origin_circuit_t *circuit = NULL;
  crypt_path_t *path = NULL;
  (void) data;

  MOCK(get_options, get_options_mock);
  MOCK(connection_ap_handshake_rewrite, connection_ap_handshake_rewrite_mock);
  MOCK(connection_mark_unattached_ap_, connection_mark_unattached_ap_mock);

  init_mock_options();
  init_rewrite_mock();

  options_mock->SafeLogging_ = SAFELOG_SCRUB_NONE;
  rewrite_mock->should_close = 0;
  SET_SOCKS_ADDRESS(conn->socks_request, "http://www.bogus.onion");
  conn->socks_request->command = SOCKS_COMMAND_CONNECT;

  int prev_log = setup_capture_of_logs(LOG_INFO);
  int res = connection_ap_handshake_rewrite_and_attach(conn, circuit, path);

  tt_int_op(unattachment_reason_spy, OP_EQ, END_STREAM_REASON_TORPROTOCOL);
  tt_int_op(res, OP_EQ, -1);
  tt_str_op(mock_saved_log_at(-1), OP_EQ, "Invalid onion hostname bogus; rejecting\n");

  done:
    UNMOCK(get_options);
    UNMOCK(connection_ap_handshake_rewrite);
    UNMOCK(connection_mark_unattached_ap_);

    destroy_rewrite_mock();
    tor_free(circuit);
    tor_free(path);
    destroy_mock_options();
    teardown_capture_of_logs(prev_log);
}
Esempio n. 10
0
static void
test_util_process_clear_waitpid_callback(void *ignored)
{
  (void)ignored;
  waitpid_callback_t *res;
  int previous_log = setup_capture_of_logs(LOG_WARN);
  pid_t pid = (pid_t)43;

  clear_waitpid_callback(NULL);

  res = set_waitpid_callback(pid, temp_callback, NULL);
  clear_waitpid_callback(res);
  expect_no_log_entry();

#if 0
  /* No.  This is use-after-free.  We don't _do_ that. XXXX */
  clear_waitpid_callback(res);
  expect_log_msg("Couldn't remove waitpid monitor for pid 43.\n");
#endif

 done:
  teardown_capture_of_logs(previous_log);
}
Esempio n. 11
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. 12
0
/**
 * As setup_capture_of_logs, but do not relay log messages into the main
 * logging system.
 *
 * Avoid using this function; use setup_capture_of_logs() instead if you
 * can. If you must use this function, then make sure you detect any
 * unexpected log messages, and treat them as test failures. */
void
setup_full_capture_of_logs(int new_level)
{
  setup_capture_of_logs(new_level);
  echo_to_real_logs = 0;
}
Esempio n. 13
0
/** Test that we will use our directory guards to fetch mds even if we don't
 *  have any dirinfo (tests bug #23862). */
static void
test_directory_guard_fetch_with_no_dirinfo(void *arg)
{
  int retval;
  char *consensus_text_md = NULL;
  or_options_t *options = get_options_mutable();
  time_t now = time(NULL);

  (void) arg;

  hibernate_set_state_for_testing_(HIBERNATE_STATE_LIVE);

  /* Initialize the SRV subsystem */
  MOCK(get_my_v3_authority_cert, get_my_v3_authority_cert_m);
  mock_cert = authority_cert_parse_from_string(AUTHORITY_CERT_1,
                                               strlen(AUTHORITY_CERT_1),
                                               NULL);
  sr_init(0);
  UNMOCK(get_my_v3_authority_cert);

  /* Initialize the entry node configuration from the ticket */
  options->UseEntryGuards = 1;
  options->StrictNodes = 1;
  get_options_mutable()->EntryNodes = routerset_new();
  routerset_parse(get_options_mutable()->EntryNodes,
                  "2121212121212121212121212121212121212121", "foo");

  /* Mock some functions */
  dummy_state = tor_malloc_zero(sizeof(or_state_t));
  MOCK(get_or_state, get_or_state_replacement);
  MOCK(directory_initiate_request, mock_directory_initiate_request);
  /* we need to mock this one to avoid memleaks */
  MOCK(circuit_guard_state_new, mock_circuit_guard_state_new);

  /* Call guards_update_all() to simulate loading our state file (see
   * entry_guards_load_guards_from_state() and ticket #23989). */
  guards_update_all();

  /* Test logic: Simulate the arrival of a new consensus when we have no
   * dirinfo at all. Tor will need to fetch the mds from the consensus. Make
   * sure that Tor will use the specified entry guard instead of relying on the
   * fallback directories. */

  /* Fixup the dirconn that will deliver the consensus */
  dir_connection_t *conn = dir_connection_new(AF_INET);
  tor_addr_from_ipv4h(&conn->base_.addr, 0x7f000001);
  conn->base_.port = 8800;
  TO_CONN(conn)->address = tor_strdup("127.0.0.1");
  conn->base_.purpose = DIR_PURPOSE_FETCH_CONSENSUS;
  conn->requested_resource = tor_strdup("ns");

  /* Construct a consensus */
  construct_consensus(&consensus_text_md, now);
  tt_assert(consensus_text_md);

  /* Place the consensus in the dirconn */
  response_handler_args_t args;
  memset(&args, 0, sizeof(response_handler_args_t));
  args.status_code = 200;
  args.body = consensus_text_md;
  args.body_len = strlen(consensus_text_md);

  /* Update approx time so that the consensus is considered live */
  update_approx_time(now+1010);

  setup_capture_of_logs(LOG_DEBUG);

  /* Now handle the consensus */
  retval = handle_response_fetch_consensus(conn, &args);
  tt_int_op(retval, OP_EQ, 0);

  /* Make sure that our primary guard was chosen */
  expect_log_msg_containing("Selected primary guard router3");

 done:
  tor_free(consensus_text_md);
  tor_free(dummy_state);
  connection_free_minimal(TO_CONN(conn));
  entry_guards_free_all();
  teardown_capture_of_logs();
}
Esempio n. 14
0
static void
test_virtaddrmap_persist(void *data)
{
  (void)data;
  const char *a, *b, *c;
  tor_addr_t addr;
  char *ones = NULL;

  addressmap_init();

  // Try a hostname.
  a = addressmap_register_virtual_address(RESOLVED_TYPE_HOSTNAME,
                                          tor_strdup("foobar.baz"));
  tt_assert(a);
  tt_assert(!strcmpend(a, ".virtual"));

  // mock crypto_rand to repeat the same result twice; make sure we get
  // different outcomes.  (Because even though the odds for receiving the
  // same 80-bit address twice is only 1/2^40, it could still happen for
  // some user -- but running our test through 2^40 iterations isn't
  // reasonable.)
  canned_data = "1234567890" // the first call returns this.
                "1234567890" // the second call returns this.
                "abcdefghij"; // the third call returns this.
  canned_data_len = 30;
  MOCK(crypto_rand, crypto_canned);

  a = addressmap_register_virtual_address(RESOLVED_TYPE_HOSTNAME,
                                          tor_strdup("quuxit.baz"));
  b = addressmap_register_virtual_address(RESOLVED_TYPE_HOSTNAME,
                                          tor_strdup("nescio.baz"));
  tt_assert(a);
  tt_assert(b);
  tt_str_op(a, OP_EQ, "gezdgnbvgy3tqojq.virtual");
  tt_str_op(b, OP_EQ, "mfrggzdfmztwq2lk.virtual");

  // Now try something to get us an ipv4 address
  UNMOCK(crypto_rand);
  tt_int_op(0,OP_EQ, parse_virtual_addr_network("192.168.0.0/16",
                                                AF_INET, 0, NULL));
  a = addressmap_register_virtual_address(RESOLVED_TYPE_IPV4,
                                          tor_strdup("foobar.baz"));
  tt_assert(a);
  tt_assert(!strcmpstart(a, "192.168."));
  tor_addr_parse(&addr, a);
  tt_int_op(AF_INET, OP_EQ, tor_addr_family(&addr));

  b = addressmap_register_virtual_address(RESOLVED_TYPE_IPV4,
                                          tor_strdup("quuxit.baz"));
  tt_str_op(b, OP_NE, a);
  tt_assert(!strcmpstart(b, "192.168."));

  // Try some canned entropy and verify all the we discard duplicates,
  // addresses that end with 0, and addresses that end with 255.
  MOCK(crypto_rand, crypto_canned);
  canned_data = "\x01\x02\x03\x04" // okay
                "\x01\x02\x03\x04" // duplicate
                "\x03\x04\x00\x00" // bad ending 1
                "\x05\x05\x00\xff" // bad ending 2
                "\x05\x06\x07\xf0"; // okay
  canned_data_len = 20;
  a = addressmap_register_virtual_address(RESOLVED_TYPE_IPV4,
                                          tor_strdup("wumble.onion"));
  b = addressmap_register_virtual_address(RESOLVED_TYPE_IPV4,
                                          tor_strdup("wumpus.onion"));
  tt_str_op(a, OP_EQ, "192.168.3.4");
  tt_str_op(b, OP_EQ, "192.168.7.240");

  // Now try IPv6!
  UNMOCK(crypto_rand);
  tt_int_op(0,OP_EQ, parse_virtual_addr_network("1010:F000::/20",
                                                AF_INET6, 0, NULL));
  a = addressmap_register_virtual_address(RESOLVED_TYPE_IPV6,
                                          tor_strdup("foobar.baz"));
  tt_assert(a);
  tt_assert(!strcmpstart(a, "[1010:f"));
  tor_addr_parse(&addr, a);
  tt_int_op(AF_INET6, OP_EQ, tor_addr_family(&addr));

  b = addressmap_register_virtual_address(RESOLVED_TYPE_IPV6,
                                          tor_strdup("quuxit.baz"));
  tt_str_op(b, OP_NE, a);
  tt_assert(!strcmpstart(b, "[1010:f"));

  // Try IPv6 with canned entropy, to make sure we detect duplicates.
  MOCK(crypto_rand, crypto_canned);
  canned_data = "acanthopterygian" // okay
                "cinematographist" // okay
                "acanthopterygian" // duplicate
                "acanthopterygian" // duplicate
                "acanthopterygian" // duplicate
                "cinematographist" // duplicate
                "coadministration"; // okay
  canned_data_len = 16 * 7;
  a = addressmap_register_virtual_address(RESOLVED_TYPE_IPV6,
                                          tor_strdup("wuffle.baz"));
  b = addressmap_register_virtual_address(RESOLVED_TYPE_IPV6,
                                          tor_strdup("gribble.baz"));
  c = addressmap_register_virtual_address(RESOLVED_TYPE_IPV6,
                                      tor_strdup("surprisingly-legible.baz"));
  tt_str_op(a, OP_EQ, "[1010:f16e:7468:6f70:7465:7279:6769:616e]");
  tt_str_op(b, OP_EQ, "[1010:fe65:6d61:746f:6772:6170:6869:7374]");
  tt_str_op(c, OP_EQ, "[1010:f164:6d69:6e69:7374:7261:7469:6f6e]");

  // Try address exhaustion: make sure we can actually fail if we
  // get too many already-existing addresses.
  canned_data_len = 128*1024;
  canned_data = ones = tor_malloc(canned_data_len);
  memset(ones, 1, canned_data_len);
  // There is some chance this one will fail if a previous random
  // allocation gave out the address already.
  a = addressmap_register_virtual_address(RESOLVED_TYPE_IPV4,
                                          tor_strdup("might-work.onion"));
  if (a) {
    tt_str_op(a, OP_EQ, "192.168.1.1");
  }
  setup_capture_of_logs(LOG_WARN);
  // This one will definitely fail, since we've set up the RNG to hand
  // out "1" forever.
  b = addressmap_register_virtual_address(RESOLVED_TYPE_IPV4,
                                          tor_strdup("wont-work.onion"));
  tt_assert(b == NULL);
  expect_single_log_msg_containing("Ran out of virtual addresses!");

 done:
  UNMOCK(crypto_rand);
  tor_free(ones);
  addressmap_free_all();
  teardown_capture_of_logs();
}