static void test_rend_cache_decrement_allocation(void *data) { (void)data; // Test when the cache has enough allocations rend_cache_total_allocation = 10; rend_cache_decrement_allocation(3); tt_int_op(rend_cache_total_allocation, OP_EQ, 7); // Test when there are not enough allocations rend_cache_total_allocation = 1; setup_full_capture_of_logs(LOG_WARN); rend_cache_decrement_allocation(2); tt_int_op(rend_cache_total_allocation, OP_EQ, 0); expect_single_log_msg_containing( "Underflow in rend_cache_decrement_allocation"); teardown_capture_of_logs(); // And again rend_cache_decrement_allocation(2); tt_int_op(rend_cache_total_allocation, OP_EQ, 0); done: teardown_capture_of_logs(); }
static void test_rend_cache_increment_allocation(void *data) { (void)data; // Test when the cache is not overflowing rend_cache_total_allocation = 5; rend_cache_increment_allocation(3); tt_int_op(rend_cache_total_allocation, OP_EQ, 8); // Test when there are too many allocations rend_cache_total_allocation = SIZE_MAX-1; setup_full_capture_of_logs(LOG_WARN); rend_cache_increment_allocation(2); tt_u64_op(rend_cache_total_allocation, OP_EQ, SIZE_MAX); expect_single_log_msg_containing( "Overflow in rend_cache_increment_allocation"); teardown_capture_of_logs(); // And again rend_cache_increment_allocation(2); tt_u64_op(rend_cache_total_allocation, OP_EQ, SIZE_MAX); done: teardown_capture_of_logs(); }
/* Try sending an ESTABLISH_INTRO cell on a circuit that is already an intro * point. Should fail. */ static void test_establish_intro_wrong_purpose(void *arg) { int retval; ssize_t cell_len = 0; char circ_nonce[DIGEST_LEN] = {0}; uint8_t cell_body[RELAY_PAYLOAD_SIZE]; or_circuit_t *intro_circ = or_circuit_new(0,NULL); (void)arg; /* Get the auth key of the intro point */ crypto_rand(circ_nonce, sizeof(circ_nonce)); memcpy(intro_circ->rend_circ_nonce, circ_nonce, DIGEST_LEN); /* Set a bad circuit purpose!! :) */ circuit_change_purpose(TO_CIRCUIT(intro_circ), CIRCUIT_PURPOSE_INTRO_POINT); /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we attempt to parse it. */ cell_len = new_establish_intro_encoded_cell(circ_nonce, cell_body); tt_i64_op(cell_len, OP_GT, 0); /* Receive the cell. Should fail. */ setup_full_capture_of_logs(LOG_INFO); retval = hs_intro_received_establish_intro(intro_circ, cell_body, cell_len); expect_log_msg_containing("Rejecting ESTABLISH_INTRO on non-OR circuit."); teardown_capture_of_logs(); tt_int_op(retval, OP_EQ, -1); done: circuit_free_(TO_CIRCUIT(intro_circ)); }
/* Send a legit ESTABLISH_INTRO cell but slightly change the signature. Should * fail. */ static void test_establish_intro_wrong_sig(void *arg) { int retval; char circ_nonce[DIGEST_LEN] = {0}; uint8_t cell_body[RELAY_PAYLOAD_SIZE]; ssize_t cell_len = 0; or_circuit_t *intro_circ = or_circuit_new(0,NULL); (void) arg; /* Get the auth key of the intro point */ crypto_rand(circ_nonce, sizeof(circ_nonce)); helper_prepare_circ_for_intro(intro_circ, circ_nonce); /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we attempt to parse it. */ cell_len = new_establish_intro_encoded_cell(circ_nonce, cell_body); tt_i64_op(cell_len, OP_GT, 0); /* Mutate the last byte (signature)! :) */ cell_body[cell_len - 1]++; /* Receive the cell. Should fail. */ setup_full_capture_of_logs(LOG_INFO); retval = hs_intro_received_establish_intro(intro_circ, cell_body, (size_t)cell_len); expect_log_msg_containing("Failed to verify ESTABLISH_INTRO cell."); teardown_capture_of_logs(); tt_int_op(retval, OP_EQ, -1); done: circuit_free_(TO_CIRCUIT(intro_circ)); }
/** We simulate a failure to create an ESTABLISH_INTRO cell */ static void test_gen_establish_intro_cell_bad(void *arg) { (void) arg; ssize_t cell_len = 0; trn_cell_establish_intro_t *cell = NULL; char circ_nonce[DIGEST_LEN] = {0}; hs_service_intro_point_t *ip = NULL; MOCK(ed25519_sign_prefixed, mock_ed25519_sign_prefixed); crypto_rand(circ_nonce, sizeof(circ_nonce)); setup_full_capture_of_logs(LOG_WARN); /* Easiest way to make that function fail is to mock the ed25519_sign_prefixed() function and make it fail. */ cell = trn_cell_establish_intro_new(); tt_assert(cell); ip = service_intro_point_new(NULL); cell_len = hs_cell_build_establish_intro(circ_nonce, ip, NULL); service_intro_point_free(ip); expect_log_msg_containing("Unable to make signature for " "ESTABLISH_INTRO cell."); teardown_capture_of_logs(); tt_i64_op(cell_len, OP_EQ, -1); done: trn_cell_establish_intro_free(cell); UNMOCK(ed25519_sign_prefixed); }
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; }
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); }
/** 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(); }
/** 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(); }
/** Test non-early consensus */ static void test_timely_consensus(void *arg) { time_t now = time(NULL); unsigned long offset = 0; int retval = 0; retval = test_skew_common(arg, now, &offset); (void)offset; expect_no_log_msg_containing("behind the time published in the consensus"); tt_int_op(retval, OP_EQ, 0); tt_int_op(mock_apparent_skew, OP_EQ, 0); done: teardown_capture_of_logs(); UNMOCK(clock_skew_warning); }
/** Test early consensus */ static void test_early_consensus(void *arg) { time_t now = time(NULL); unsigned long offset = 0; int retval = 0; retval = test_skew_common(arg, 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(retval, OP_EQ, 0); /* This depends on construct_consensus() setting valid_after=now+1000 */ tt_int_op(mock_apparent_skew, OP_EQ, offset - 1000); done: teardown_capture_of_logs(); UNMOCK(clock_skew_warning); }
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); }
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); }
/* Send a legit ESTABLISH_INTRO cell but with a wrong sig length. Should * fail. */ static void test_establish_intro_wrong_sig_len(void *arg) { int retval; char circ_nonce[DIGEST_LEN] = {0}; uint8_t cell_body[RELAY_PAYLOAD_SIZE]; ssize_t cell_len = 0; size_t bad_sig_len = ED25519_SIG_LEN - 1; trn_cell_establish_intro_t *cell = NULL; or_circuit_t *intro_circ = or_circuit_new(0,NULL); (void) arg; /* Get the auth key of the intro point */ crypto_rand(circ_nonce, sizeof(circ_nonce)); helper_prepare_circ_for_intro(intro_circ, circ_nonce); /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we * attempt to parse it. */ cell_len = new_establish_intro_cell(circ_nonce, &cell); tt_i64_op(cell_len, OP_GT, 0); tt_assert(cell); /* Mangle the signature length. */ trn_cell_establish_intro_set_sig_len(cell, bad_sig_len); trn_cell_establish_intro_setlen_sig(cell, bad_sig_len); /* Encode cell. */ cell_len = trn_cell_establish_intro_encode(cell_body, sizeof(cell_body), cell); tt_int_op(cell_len, OP_GT, 0); /* Receive the cell. Should fail. */ setup_full_capture_of_logs(LOG_INFO); retval = hs_intro_received_establish_intro(intro_circ, cell_body, cell_len); expect_log_msg_containing("ESTABLISH_INTRO sig len is invalid"); teardown_capture_of_logs(); tt_int_op(retval, OP_EQ, -1); done: trn_cell_establish_intro_free(cell); circuit_free_(TO_CIRCUIT(intro_circ)); }
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); }
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); }
/* Send an empty ESTABLISH_INTRO cell. Should fail. */ static void test_establish_intro_wrong_keytype(void *arg) { int retval; or_circuit_t *intro_circ = or_circuit_new(0,NULL); char circ_nonce[DIGEST_LEN] = {0}; (void) arg; /* Get the auth key of the intro point */ crypto_rand(circ_nonce, sizeof(circ_nonce)); helper_prepare_circ_for_intro(intro_circ, circ_nonce); /* Receive the cell. Should fail. */ setup_full_capture_of_logs(LOG_INFO); retval = hs_intro_received_establish_intro(intro_circ, (uint8_t *) "", 0); expect_log_msg_containing("Empty ESTABLISH_INTRO cell."); teardown_capture_of_logs(); tt_int_op(retval, OP_EQ, -1); done: circuit_free_(TO_CIRCUIT(intro_circ)); }
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); }
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(); }
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); }
/* Send a legit ESTABLISH_INTRO cell but with a wrong MAC. Should fail. */ static void test_establish_intro_wrong_mac(void *arg) { int retval; char circ_nonce[DIGEST_LEN] = {0}; ssize_t cell_len = 0; uint8_t cell_body[RELAY_PAYLOAD_SIZE]; trn_cell_establish_intro_t *cell = NULL; or_circuit_t *intro_circ = or_circuit_new(0,NULL); (void) arg; /* Get the auth key of the intro point */ crypto_rand(circ_nonce, sizeof(circ_nonce)); helper_prepare_circ_for_intro(intro_circ, circ_nonce); /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we * attempt to parse it. */ cell_len = new_establish_intro_cell(circ_nonce, &cell); tt_i64_op(cell_len, OP_GT, 0); tt_assert(cell); /* Mangle one byte of the MAC. */ uint8_t *handshake_ptr = trn_cell_establish_intro_getarray_handshake_mac(cell); handshake_ptr[TRUNNEL_SHA3_256_LEN - 1]++; /* We need to resign the payload with that change. */ { ed25519_signature_t sig; ed25519_keypair_t key_struct; /* New keypair for the signature since we don't have access to the private * key material generated earlier when creating the cell. */ retval = ed25519_keypair_generate(&key_struct, 0); tt_int_op(retval, OP_EQ, 0); uint8_t *auth_key_ptr = trn_cell_establish_intro_getarray_auth_key(cell); memcpy(auth_key_ptr, key_struct.pubkey.pubkey, ED25519_PUBKEY_LEN); /* Encode payload so we can sign it. */ cell_len = trn_cell_establish_intro_encode(cell_body, sizeof(cell_body), cell); tt_i64_op(cell_len, OP_GT, 0); retval = ed25519_sign_prefixed(&sig, cell_body, cell_len - (ED25519_SIG_LEN + sizeof(cell->sig_len)), ESTABLISH_INTRO_SIG_PREFIX, &key_struct); tt_int_op(retval, OP_EQ, 0); /* And write the signature to the cell */ uint8_t *sig_ptr = trn_cell_establish_intro_getarray_sig(cell); memcpy(sig_ptr, sig.sig, cell->sig_len); /* Re-encode with the new signature. */ cell_len = trn_cell_establish_intro_encode(cell_body, sizeof(cell_body), cell); tt_i64_op(cell_len, OP_GT, 0); } /* Receive the cell. Should fail because our MAC is wrong. */ setup_full_capture_of_logs(LOG_INFO); retval = hs_intro_received_establish_intro(intro_circ, cell_body, cell_len); expect_log_msg_containing("ESTABLISH_INTRO handshake_auth not as expected"); teardown_capture_of_logs(); tt_int_op(retval, OP_EQ, -1); done: trn_cell_establish_intro_free(cell); circuit_free_(TO_CIRCUIT(intro_circ)); }
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 }
static void test_router_check_descriptor_bandwidth_changed(void *arg) { (void)arg; routerinfo_t routerinfo; memset(&routerinfo, 0, sizeof(routerinfo)); mock_router_get_my_routerinfo_result = NULL; MOCK(we_are_hibernating, mock_we_are_not_hibernating); MOCK(router_get_my_routerinfo, mock_router_get_my_routerinfo); mock_router_get_my_routerinfo_result = &routerinfo; /* When uptime is less than 24h, no previous bandwidth, no last_changed * Uptime: 10800, last_changed: 0, Previous bw: 0, Current bw: 0 */ routerinfo.bandwidthcapacity = 0; MOCK(get_uptime, mock_get_uptime_3h); setup_full_capture_of_logs(LOG_INFO); check_descriptor_bandwidth_changed(time(NULL)); expect_log_msg_not_containing( "Measured bandwidth has changed; rebuilding descriptor."); teardown_capture_of_logs(); /* When uptime is less than 24h, previous bandwidth, * last_changed more than 3h ago * Uptime: 10800, last_changed: 0, Previous bw: 10000, Current bw: 0 */ routerinfo.bandwidthcapacity = 10000; setup_full_capture_of_logs(LOG_INFO); check_descriptor_bandwidth_changed(time(NULL)); expect_log_msg_containing( "Measured bandwidth has changed; rebuilding descriptor."); teardown_capture_of_logs(); /* When uptime is less than 24h, previous bandwidth, * last_changed more than 3h ago, and hibernating * Uptime: 10800, last_changed: 0, Previous bw: 10000, Current bw: 0 */ UNMOCK(we_are_hibernating); MOCK(we_are_hibernating, mock_we_are_hibernating); routerinfo.bandwidthcapacity = 10000; setup_full_capture_of_logs(LOG_INFO); check_descriptor_bandwidth_changed(time(NULL)); expect_log_msg_not_containing( "Measured bandwidth has changed; rebuilding descriptor."); teardown_capture_of_logs(); UNMOCK(we_are_hibernating); MOCK(we_are_hibernating, mock_we_are_not_hibernating); /* When uptime is less than 24h, last_changed is not more than 3h ago * Uptime: 10800, last_changed: x, Previous bw: 10000, Current bw: 0 */ setup_full_capture_of_logs(LOG_INFO); check_descriptor_bandwidth_changed(time(NULL)); expect_log_msg_not_containing( "Measured bandwidth has changed; rebuilding descriptor."); teardown_capture_of_logs(); /* When uptime is less than 24h and bandwidthcapacity does not change * Uptime: 10800, last_changed: x, Previous bw: 10000, Current bw: 20001 */ MOCK(rep_hist_bandwidth_assess, mock_rep_hist_bandwidth_assess); setup_full_capture_of_logs(LOG_INFO); check_descriptor_bandwidth_changed(time(NULL) + 6*60*60 + 1); expect_log_msg_containing( "Measured bandwidth has changed; rebuilding descriptor."); UNMOCK(get_uptime); UNMOCK(rep_hist_bandwidth_assess); teardown_capture_of_logs(); /* When uptime is more than 24h */ MOCK(get_uptime, mock_get_uptime_1d); setup_full_capture_of_logs(LOG_INFO); check_descriptor_bandwidth_changed(time(NULL)); expect_log_msg_not_containing( "Measured bandwidth has changed; rebuilding descriptor."); teardown_capture_of_logs(); done: UNMOCK(get_uptime); UNMOCK(router_get_my_routerinfo); UNMOCK(we_are_hibernating); }
static void test_invalid_service_v2(void *arg) { int validate_only = 1, ret; (void) arg; /* Try with a missing port configuration. */ { const char *conf = "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n" "HiddenServiceVersion 2\n"; setup_full_capture_of_logs(LOG_WARN); ret = helper_config_service(conf, validate_only); tt_int_op(ret, OP_EQ, -1); expect_log_msg_containing("with no ports configured."); teardown_capture_of_logs(); } /* Too many introduction points. */ { const char *conf = "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n" "HiddenServiceVersion 2\n" "HiddenServicePort 80\n" "HiddenServiceNumIntroductionPoints 11\n"; /* One too many. */ setup_full_capture_of_logs(LOG_WARN); ret = helper_config_service(conf, validate_only); tt_int_op(ret, OP_EQ, -1); expect_log_msg_containing("HiddenServiceNumIntroductionPoints should " "be between 0 and 10, not 11"); teardown_capture_of_logs(); } /* Too little introduction points. */ { const char *conf = "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n" "HiddenServiceVersion 2\n" "HiddenServicePort 80\n" "HiddenServiceNumIntroductionPoints -1\n"; setup_full_capture_of_logs(LOG_WARN); ret = helper_config_service(conf, validate_only); tt_int_op(ret, OP_EQ, -1); expect_log_msg_containing("HiddenServiceNumIntroductionPoints should " "be between 0 and 10, not -1"); teardown_capture_of_logs(); } /* Bad authorized client type. */ { const char *conf = "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n" "HiddenServiceVersion 2\n" "HiddenServicePort 80\n" "HiddenServiceAuthorizeClient blah alice,bob\n"; /* blah is no good. */ setup_full_capture_of_logs(LOG_WARN); ret = helper_config_service(conf, validate_only); tt_int_op(ret, OP_EQ, -1); expect_log_msg_containing("HiddenServiceAuthorizeClient contains " "unrecognized auth-type"); teardown_capture_of_logs(); } done: ; }
static void test_invalid_service_v3(void *arg) { int validate_only = 1, ret; (void) arg; /* Try with a missing port configuration. */ { const char *conf = "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n" "HiddenServiceVersion 3\n"; setup_full_capture_of_logs(LOG_WARN); ret = helper_config_service(conf, validate_only); tt_int_op(ret, OP_EQ, -1); expect_log_msg_containing("with no ports configured."); teardown_capture_of_logs(); } /* Too many introduction points. */ { const char *conf = "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n" "HiddenServiceVersion 3\n" "HiddenServicePort 80\n" "HiddenServiceNumIntroductionPoints 21\n"; /* One too many. */ setup_full_capture_of_logs(LOG_WARN); ret = helper_config_service(conf, validate_only); tt_int_op(ret, OP_EQ, -1); expect_log_msg_containing("HiddenServiceNumIntroductionPoints must " "be between 3 and 20, not 21."); teardown_capture_of_logs(); } /* Too little introduction points. */ { const char *conf = "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n" "HiddenServiceVersion 3\n" "HiddenServicePort 80\n" "HiddenServiceNumIntroductionPoints 1\n"; setup_full_capture_of_logs(LOG_WARN); ret = helper_config_service(conf, validate_only); tt_int_op(ret, OP_EQ, -1); expect_log_msg_containing("HiddenServiceNumIntroductionPoints must " "be between 3 and 20, not 1."); teardown_capture_of_logs(); } /* v2-specific HiddenServiceAuthorizeClient set. */ { const char *conf = "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n" "HiddenServiceVersion 3\n" "HiddenServiceAuthorizeClient stealth client1\n"; setup_full_capture_of_logs(LOG_WARN); ret = helper_config_service(conf, validate_only); tt_int_op(ret, OP_EQ, -1); expect_log_msg_containing("Hidden service option " "HiddenServiceAuthorizeClient is incompatible " "with version 3 of service in " "/tmp/tor-test-hs-RANDOM/hs1"); teardown_capture_of_logs(); } done: ; }
static void test_invalid_service(void *arg) { int ret; (void) arg; /* Try with a missing port configuration. */ { const char *conf = "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n" "HiddenServiceVersion 1\n"; /* Wrong not supported version. */ setup_full_capture_of_logs(LOG_WARN); ret = helper_config_service(conf, 1); tt_int_op(ret, OP_EQ, -1); expect_log_msg_containing("HiddenServiceVersion must be between 2 and 3"); teardown_capture_of_logs(); } /* Bad value of HiddenServiceAllowUnknownPorts. */ { const char *conf = "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n" "HiddenServiceVersion 2\n" "HiddenServiceAllowUnknownPorts 2\n"; /* Should be 0 or 1. */ setup_full_capture_of_logs(LOG_WARN); ret = helper_config_service(conf, 1); tt_int_op(ret, OP_EQ, -1); expect_log_msg_containing("HiddenServiceAllowUnknownPorts must be " "between 0 and 1, not 2"); teardown_capture_of_logs(); } /* Bad value of HiddenServiceDirGroupReadable */ { const char *conf = "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n" "HiddenServiceVersion 2\n" "HiddenServiceDirGroupReadable 2\n"; /* Should be 0 or 1. */ setup_full_capture_of_logs(LOG_WARN); ret = helper_config_service(conf, 1); tt_int_op(ret, OP_EQ, -1); expect_log_msg_containing("HiddenServiceDirGroupReadable must be " "between 0 and 1, not 2"); teardown_capture_of_logs(); } /* Bad value of HiddenServiceMaxStreamsCloseCircuit */ { const char *conf = "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n" "HiddenServiceVersion 2\n" "HiddenServiceMaxStreamsCloseCircuit 2\n"; /* Should be 0 or 1. */ setup_full_capture_of_logs(LOG_WARN); ret = helper_config_service(conf, 1); tt_int_op(ret, OP_EQ, -1); expect_log_msg_containing("HiddenServiceMaxStreamsCloseCircuit must " "be between 0 and 1, not 2"); teardown_capture_of_logs(); } /* Too much max streams. */ { const char *conf = "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n" "HiddenServiceVersion 2\n" "HiddenServicePort 80\n" "HiddenServiceMaxStreams 65536\n"; /* One too many. */ setup_full_capture_of_logs(LOG_WARN); ret = helper_config_service(conf, 1); tt_int_op(ret, OP_EQ, -1); expect_log_msg_containing("HiddenServiceMaxStreams must be between " "0 and 65535, not 65536"); teardown_capture_of_logs(); } /* Duplicate directory directive. */ { const char *conf = "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n" "HiddenServiceVersion 2\n" "HiddenServicePort 80\n" "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n" "HiddenServiceVersion 2\n" "HiddenServicePort 81\n"; setup_full_capture_of_logs(LOG_WARN); ret = helper_config_service(conf, 1); tt_int_op(ret, OP_EQ, -1); expect_log_msg_containing("Another hidden service is already " "configured for directory"); teardown_capture_of_logs(); } /* Bad port. */ { const char *conf = "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n" "HiddenServiceVersion 2\n" "HiddenServicePort 65536\n"; setup_full_capture_of_logs(LOG_WARN); ret = helper_config_service(conf, 1); tt_int_op(ret, OP_EQ, -1); expect_log_msg_containing("Missing or invalid port"); teardown_capture_of_logs(); } /* Bad target addr:port separation. */ { const char *conf = "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n" "HiddenServiceVersion 2\n" "HiddenServicePort 80 127.0.0.1 8000\n"; setup_full_capture_of_logs(LOG_WARN); ret = helper_config_service(conf, 1); tt_int_op(ret, OP_EQ, -1); expect_log_msg_containing("HiddenServicePort parse error: " "invalid port mapping"); teardown_capture_of_logs(); } /* Out of order directives. */ { const char *conf = "HiddenServiceVersion 2\n" "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n" "HiddenServicePort 80\n"; setup_full_capture_of_logs(LOG_WARN); ret = helper_config_service(conf, 1); tt_int_op(ret, OP_EQ, -1); expect_log_msg_containing("HiddenServiceVersion with no preceding " "HiddenServiceDir directive"); teardown_capture_of_logs(); } done: ; }
/** 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(); }