Add a unittest that reveals the offending case of #23862.

This commit is contained in:
George Kadianakis 2017-10-25 19:25:53 +03:00
parent c7a1a987d6
commit 8c8d3b90f7
6 changed files with 122 additions and 7 deletions

View File

@ -2237,8 +2237,6 @@ load_downloaded_routers(const char *body, smartlist_t *which,
return added;
}
static int handle_response_fetch_consensus(dir_connection_t *,
const response_handler_args_t *);
static int handle_response_fetch_certificate(dir_connection_t *,
const response_handler_args_t *);
static int handle_response_fetch_status_vote(dir_connection_t *,
@ -2585,7 +2583,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
* consensus document by checking the consensus, storing it, and marking
* router requests as reachable.
**/
static int
STATIC int
handle_response_fetch_consensus(dir_connection_t *conn,
const response_handler_args_t *args)
{

View File

@ -194,6 +194,9 @@ STATIC void warn_disallowed_anonymous_compression_method(compress_method_t);
STATIC int handle_response_fetch_hsdesc_v3(dir_connection_t *conn,
const response_handler_args_t *args);
STATIC int handle_response_fetch_consensus(dir_connection_t *conn,
const response_handler_args_t *args);
#endif /* defined(DIRECTORY_PRIVATE) */
#ifdef TOR_UNIT_TESTS

View File

@ -2126,9 +2126,9 @@ circuit_guard_state_free(circuit_guard_state_t *state)
/** Allocate and return a new circuit_guard_state_t to track the result
* of using <b>guard</b> for a given operation. */
static circuit_guard_state_t *
circuit_guard_state_new(entry_guard_t *guard, unsigned state,
entry_guard_restriction_t *rst)
MOCK_IMPL(STATIC circuit_guard_state_t *,
circuit_guard_state_new,(entry_guard_t *guard, unsigned state,
entry_guard_restriction_t *rst))
{
circuit_guard_state_t *result;

View File

@ -488,6 +488,10 @@ STATIC entry_guard_t *get_sampled_guard_with_id(guard_selection_t *gs,
MOCK_DECL(STATIC time_t, randomize_time, (time_t now, time_t max_backdate));
MOCK_DECL(STATIC circuit_guard_state_t *,
circuit_guard_state_new,(entry_guard_t *guard, unsigned state,
entry_guard_restriction_t *rst));
STATIC entry_guard_t *entry_guard_add_to_sample(guard_selection_t *gs,
const node_t *node);
STATIC entry_guard_t *entry_guards_expand_sample(guard_selection_t *gs);

View File

@ -1720,7 +1720,7 @@ networkstatus_set_current_consensus(const char *consensus,
{
networkstatus_t *c=NULL;
int r, result = -1;
time_t now = time(NULL);
time_t now = approx_time();
const or_options_t *options = get_options();
char *unverified_fname = NULL, *consensus_fname = NULL;
int flav = networkstatus_parse_flavor_name(flavor);

View File

@ -6,13 +6,17 @@
#include <time.h>
#define DIRVOTE_PRIVATE
#define ENTRYNODES_PRIVATE
#define DIRECTORY_PRIVATE
#define NETWORKSTATUS_PRIVATE
#define CONNECTION_PRIVATE
#define ROUTERLIST_PRIVATE
#define TOR_UNIT_TESTING
#include "or.h"
#include "config.h"
#include "connection.h"
#include "container.h"
#include "control.h"
#include "directory.h"
#include "dirvote.h"
#include "entrynodes.h"
@ -22,10 +26,13 @@
#include "policies.h"
#include "router.h"
#include "routerlist.h"
#include "routerset.h"
#include "routerparse.h"
#include "shared_random.h"
#include "statefile.h"
#include "test.h"
#include "test_dir_common.h"
#include "log_test_helpers.h"
void construct_consensus(char **consensus_text_md);
@ -411,6 +418,107 @@ test_router_pick_directory_server_impl(void *arg)
networkstatus_vote_free(con_md);
}
static or_state_t *dummy_state = NULL;
static or_state_t *
get_or_state_replacement(void)
{
return dummy_state;
}
static void
mock_directory_initiate_request(directory_request_t *req)
{
(void)req;
return;
}
static circuit_guard_state_t *
mock_circuit_guard_state_new(entry_guard_t *guard, unsigned state,
entry_guard_restriction_t *rst)
{
(void) guard;
(void) state;
(void) rst;
return NULL;
}
/** 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();
(void) arg;
/* Initialize the SRV subsystem */
sr_init(0);
/* 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);
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(time(NULL)+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 */
/* BUG #23862 falls back to dirserver list!! */
expect_log_msg_containing("falling back to dirserver list");
done:
tor_free(consensus_text_md);
tor_free(dummy_state);
connection_free_(TO_CONN(conn));
entry_guards_free_all();
teardown_capture_of_logs();
}
static connection_t *mocked_connection = NULL;
/* Mock connection_get_by_type_addr_port_purpose by returning
@ -494,6 +602,8 @@ struct testcase_t routerlist_tests[] = {
NODE(launch_descriptor_downloads, 0),
NODE(router_is_already_dir_fetching, TT_FORK),
ROUTER(pick_directory_server_impl, TT_FORK),
{ "directory_guard_fetch_with_no_dirinfo",
test_directory_guard_fetch_with_no_dirinfo, TT_FORK, NULL, NULL },
END_OF_TESTCASES
};