Merge branch 'bug23817_tests_032' into maint-0.3.2
This commit is contained in:
commit
9c17a6d28b
|
@ -1012,48 +1012,6 @@ directory_must_use_begindir(const or_options_t *options)
|
||||||
return !public_server_mode(options);
|
return !public_server_mode(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct directory_request_t {
|
|
||||||
/**
|
|
||||||
* These fields specify which directory we're contacting. Routerstatus,
|
|
||||||
* if present, overrides the other fields.
|
|
||||||
*
|
|
||||||
* @{ */
|
|
||||||
tor_addr_port_t or_addr_port;
|
|
||||||
tor_addr_port_t dir_addr_port;
|
|
||||||
char digest[DIGEST_LEN];
|
|
||||||
|
|
||||||
const routerstatus_t *routerstatus;
|
|
||||||
/** @} */
|
|
||||||
/** One of DIR_PURPOSE_* other than DIR_PURPOSE_SERVER. Describes what
|
|
||||||
* kind of operation we'll be doing (upload/download), and of what kind
|
|
||||||
* of document. */
|
|
||||||
uint8_t dir_purpose;
|
|
||||||
/** One of ROUTER_PURPOSE_*; used for uploads and downloads of routerinfo
|
|
||||||
* and extrainfo docs. */
|
|
||||||
uint8_t router_purpose;
|
|
||||||
/** Enum: determines whether to anonymize, and whether to use dirport or
|
|
||||||
* orport. */
|
|
||||||
dir_indirection_t indirection;
|
|
||||||
/** Alias to the variable part of the URL for this request */
|
|
||||||
const char *resource;
|
|
||||||
/** Alias to the payload to upload (if any) */
|
|
||||||
const char *payload;
|
|
||||||
/** Number of bytes to upload from payload</b> */
|
|
||||||
size_t payload_len;
|
|
||||||
/** Value to send in an if-modified-since header, or 0 for none. */
|
|
||||||
time_t if_modified_since;
|
|
||||||
/** Hidden-service-specific information v2. */
|
|
||||||
const rend_data_t *rend_query;
|
|
||||||
/** Extra headers to append to the request */
|
|
||||||
config_line_t *additional_headers;
|
|
||||||
/** Hidden-service-specific information for v3+. */
|
|
||||||
const hs_ident_dir_conn_t *hs_ident;
|
|
||||||
/** Used internally to directory.c: gets informed when the attempt to
|
|
||||||
* connect to the directory succeeds or fails, if that attempt bears on the
|
|
||||||
* directory's usability as a directory guard. */
|
|
||||||
circuit_guard_state_t *guard_state;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Evaluate the situation and decide if we should use an encrypted
|
/** Evaluate the situation and decide if we should use an encrypted
|
||||||
* "begindir-style" connection for this directory request.
|
* "begindir-style" connection for this directory request.
|
||||||
* 0) If there is no DirPort, yes.
|
* 0) If there is no DirPort, yes.
|
||||||
|
|
|
@ -183,6 +183,48 @@ typedef struct response_handler_args_t {
|
||||||
const char *headers;
|
const char *headers;
|
||||||
} response_handler_args_t;
|
} response_handler_args_t;
|
||||||
|
|
||||||
|
struct directory_request_t {
|
||||||
|
/**
|
||||||
|
* These fields specify which directory we're contacting. Routerstatus,
|
||||||
|
* if present, overrides the other fields.
|
||||||
|
*
|
||||||
|
* @{ */
|
||||||
|
tor_addr_port_t or_addr_port;
|
||||||
|
tor_addr_port_t dir_addr_port;
|
||||||
|
char digest[DIGEST_LEN];
|
||||||
|
|
||||||
|
const routerstatus_t *routerstatus;
|
||||||
|
/** @} */
|
||||||
|
/** One of DIR_PURPOSE_* other than DIR_PURPOSE_SERVER. Describes what
|
||||||
|
* kind of operation we'll be doing (upload/download), and of what kind
|
||||||
|
* of document. */
|
||||||
|
uint8_t dir_purpose;
|
||||||
|
/** One of ROUTER_PURPOSE_*; used for uploads and downloads of routerinfo
|
||||||
|
* and extrainfo docs. */
|
||||||
|
uint8_t router_purpose;
|
||||||
|
/** Enum: determines whether to anonymize, and whether to use dirport or
|
||||||
|
* orport. */
|
||||||
|
dir_indirection_t indirection;
|
||||||
|
/** Alias to the variable part of the URL for this request */
|
||||||
|
const char *resource;
|
||||||
|
/** Alias to the payload to upload (if any) */
|
||||||
|
const char *payload;
|
||||||
|
/** Number of bytes to upload from payload</b> */
|
||||||
|
size_t payload_len;
|
||||||
|
/** Value to send in an if-modified-since header, or 0 for none. */
|
||||||
|
time_t if_modified_since;
|
||||||
|
/** Hidden-service-specific information v2. */
|
||||||
|
const rend_data_t *rend_query;
|
||||||
|
/** Extra headers to append to the request */
|
||||||
|
config_line_t *additional_headers;
|
||||||
|
/** Hidden-service-specific information for v3+. */
|
||||||
|
const hs_ident_dir_conn_t *hs_ident;
|
||||||
|
/** Used internally to directory.c: gets informed when the attempt to
|
||||||
|
* connect to the directory succeeds or fails, if that attempt bears on the
|
||||||
|
* directory's usability as a directory guard. */
|
||||||
|
struct circuit_guard_state_t *guard_state;
|
||||||
|
};
|
||||||
|
|
||||||
struct get_handler_args_t;
|
struct get_handler_args_t;
|
||||||
STATIC int handle_get_hs_descriptor_v3(dir_connection_t *conn,
|
STATIC int handle_get_hs_descriptor_v3(dir_connection_t *conn,
|
||||||
const struct get_handler_args_t *args);
|
const struct get_handler_args_t *args);
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#define STATEFILE_PRIVATE
|
#define STATEFILE_PRIVATE
|
||||||
#define ENTRYNODES_PRIVATE
|
#define ENTRYNODES_PRIVATE
|
||||||
#define ROUTERLIST_PRIVATE
|
#define ROUTERLIST_PRIVATE
|
||||||
|
#define DIRECTORY_PRIVATE
|
||||||
|
|
||||||
#include "or.h"
|
#include "or.h"
|
||||||
#include "test.h"
|
#include "test.h"
|
||||||
|
@ -15,6 +16,7 @@
|
||||||
#include "circuitlist.h"
|
#include "circuitlist.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "confparse.h"
|
#include "confparse.h"
|
||||||
|
#include "directory.h"
|
||||||
#include "entrynodes.h"
|
#include "entrynodes.h"
|
||||||
#include "nodelist.h"
|
#include "nodelist.h"
|
||||||
#include "networkstatus.h"
|
#include "networkstatus.h"
|
||||||
|
@ -129,6 +131,14 @@ big_fake_network_setup(const struct testcase_t *testcase)
|
||||||
n->rs->has_bandwidth = 1;
|
n->rs->has_bandwidth = 1;
|
||||||
n->rs->bandwidth_kb = 30;
|
n->rs->bandwidth_kb = 30;
|
||||||
|
|
||||||
|
/* Make a random nickname for each node */
|
||||||
|
{
|
||||||
|
char nickname_binary[8];
|
||||||
|
crypto_rand(nickname_binary, sizeof(nickname_binary));
|
||||||
|
base64_encode(n->rs->nickname, sizeof(n->rs->nickname),
|
||||||
|
nickname_binary, sizeof(nickname_binary), 0);
|
||||||
|
}
|
||||||
|
|
||||||
/* Call half of the nodes a possible guard. */
|
/* Call half of the nodes a possible guard. */
|
||||||
if (i % 2 == 0) {
|
if (i % 2 == 0) {
|
||||||
n->is_possible_guard = 1;
|
n->is_possible_guard = 1;
|
||||||
|
@ -1719,6 +1729,7 @@ test_entry_guard_select_for_circuit_no_confirmed(void *arg)
|
||||||
/* Simpler cases: no gaurds are confirmed yet. */
|
/* Simpler cases: no gaurds are confirmed yet. */
|
||||||
(void)arg;
|
(void)arg;
|
||||||
guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
|
guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
|
||||||
|
entry_guard_restriction_t *rst = NULL;
|
||||||
|
|
||||||
/* simple starting configuration */
|
/* simple starting configuration */
|
||||||
entry_guards_update_primary(gs);
|
entry_guards_update_primary(gs);
|
||||||
|
@ -1800,14 +1811,13 @@ test_entry_guard_select_for_circuit_no_confirmed(void *arg)
|
||||||
tt_ptr_op(g2, OP_EQ, g);
|
tt_ptr_op(g2, OP_EQ, g);
|
||||||
|
|
||||||
/* But if we impose a restriction, we don't get the same guard */
|
/* But if we impose a restriction, we don't get the same guard */
|
||||||
entry_guard_restriction_t rst;
|
rst = guard_create_exit_restriction((uint8_t*)g->identity);
|
||||||
memset(&rst, 0, sizeof(rst));
|
g2 = select_entry_guard_for_circuit(gs, GUARD_USAGE_TRAFFIC, rst, &state);
|
||||||
memcpy(rst.exclude_id, g->identity, DIGEST_LEN);
|
|
||||||
g2 = select_entry_guard_for_circuit(gs, GUARD_USAGE_TRAFFIC, &rst, &state);
|
|
||||||
tt_ptr_op(g2, OP_NE, g);
|
tt_ptr_op(g2, OP_NE, g);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
guard_selection_free(gs);
|
guard_selection_free(gs);
|
||||||
|
entry_guard_restriction_free(rst);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1817,6 +1827,7 @@ test_entry_guard_select_for_circuit_confirmed(void *arg)
|
||||||
guards, we use a confirmed guard. */
|
guards, we use a confirmed guard. */
|
||||||
(void)arg;
|
(void)arg;
|
||||||
int i;
|
int i;
|
||||||
|
entry_guard_restriction_t *rst = NULL;
|
||||||
guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
|
guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
|
||||||
const int N_CONFIRMED = 10;
|
const int N_CONFIRMED = 10;
|
||||||
|
|
||||||
|
@ -1877,10 +1888,8 @@ test_entry_guard_select_for_circuit_confirmed(void *arg)
|
||||||
get_options_mutable()->EnforceDistinctSubnets = 0;
|
get_options_mutable()->EnforceDistinctSubnets = 0;
|
||||||
g = smartlist_get(gs->confirmed_entry_guards,
|
g = smartlist_get(gs->confirmed_entry_guards,
|
||||||
smartlist_len(gs->primary_entry_guards)+2);
|
smartlist_len(gs->primary_entry_guards)+2);
|
||||||
entry_guard_restriction_t rst;
|
rst = guard_create_exit_restriction((uint8_t*)g->identity);
|
||||||
memset(&rst, 0, sizeof(rst));
|
g2 = select_entry_guard_for_circuit(gs, GUARD_USAGE_TRAFFIC, rst, &state);
|
||||||
memcpy(rst.exclude_id, g->identity, DIGEST_LEN);
|
|
||||||
g2 = select_entry_guard_for_circuit(gs, GUARD_USAGE_TRAFFIC, &rst, &state);
|
|
||||||
tt_ptr_op(g2, OP_NE, NULL);
|
tt_ptr_op(g2, OP_NE, NULL);
|
||||||
tt_ptr_op(g2, OP_NE, g);
|
tt_ptr_op(g2, OP_NE, g);
|
||||||
tt_int_op(g2->confirmed_idx, OP_EQ,
|
tt_int_op(g2->confirmed_idx, OP_EQ,
|
||||||
|
@ -1906,13 +1915,13 @@ test_entry_guard_select_for_circuit_confirmed(void *arg)
|
||||||
// Regression test for bug 22753/TROVE-2017-006.
|
// Regression test for bug 22753/TROVE-2017-006.
|
||||||
get_options_mutable()->EnforceDistinctSubnets = 1;
|
get_options_mutable()->EnforceDistinctSubnets = 1;
|
||||||
g = smartlist_get(gs->confirmed_entry_guards, 0);
|
g = smartlist_get(gs->confirmed_entry_guards, 0);
|
||||||
memset(&rst, 0, sizeof(rst));
|
memcpy(rst->exclude_id, g->identity, DIGEST_LEN);
|
||||||
memcpy(rst.exclude_id, g->identity, DIGEST_LEN);
|
g2 = select_entry_guard_for_circuit(gs, GUARD_USAGE_TRAFFIC, rst, &state);
|
||||||
g2 = select_entry_guard_for_circuit(gs, GUARD_USAGE_TRAFFIC, &rst, &state);
|
|
||||||
tt_ptr_op(g2, OP_EQ, NULL);
|
tt_ptr_op(g2, OP_EQ, NULL);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
guard_selection_free(gs);
|
guard_selection_free(gs);
|
||||||
|
entry_guard_restriction_free(rst);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -2493,9 +2502,7 @@ test_entry_guard_upgrade_not_blocked_by_restricted_circ_complete(void *arg)
|
||||||
/* Once more, let circ1 become complete. But this time, we'll claim
|
/* Once more, let circ1 become complete. But this time, we'll claim
|
||||||
* that circ2 was restricted to not use the same guard as circ1. */
|
* that circ2 was restricted to not use the same guard as circ1. */
|
||||||
data->guard2_state->restrictions =
|
data->guard2_state->restrictions =
|
||||||
tor_malloc_zero(sizeof(entry_guard_restriction_t));
|
guard_create_exit_restriction((uint8_t*)data->guard1->identity);
|
||||||
memcpy(data->guard2_state->restrictions->exclude_id,
|
|
||||||
data->guard1->identity, DIGEST_LEN);
|
|
||||||
|
|
||||||
smartlist_t *result = smartlist_new();
|
smartlist_t *result = smartlist_new();
|
||||||
int r;
|
int r;
|
||||||
|
@ -2604,9 +2611,7 @@ test_entry_guard_upgrade_not_blocked_by_restricted_circ_pending(void *arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
data->guard2_state->restrictions =
|
data->guard2_state->restrictions =
|
||||||
tor_malloc_zero(sizeof(entry_guard_restriction_t));
|
guard_create_exit_restriction((uint8_t*)data->guard1->identity);
|
||||||
memcpy(data->guard2_state->restrictions->exclude_id,
|
|
||||||
data->guard1->identity, DIGEST_LEN);
|
|
||||||
|
|
||||||
smartlist_t *result = smartlist_new();
|
smartlist_t *result = smartlist_new();
|
||||||
int r;
|
int r;
|
||||||
|
@ -2674,6 +2679,112 @@ test_enty_guard_should_expire_waiting(void *arg)
|
||||||
tor_free(fake_state);
|
tor_free(fake_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mock_directory_initiate_request(directory_request_t *req)
|
||||||
|
{
|
||||||
|
if (req->guard_state) {
|
||||||
|
circuit_guard_state_free(req->guard_state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static networkstatus_t *mock_ns_val = NULL;
|
||||||
|
static networkstatus_t *
|
||||||
|
mock_ns_get_by_flavor(consensus_flavor_t f)
|
||||||
|
{
|
||||||
|
(void)f;
|
||||||
|
return mock_ns_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Test that when we fetch microdescriptors we skip guards that have
|
||||||
|
* previously failed to serve us needed microdescriptors. */
|
||||||
|
static void
|
||||||
|
test_entry_guard_outdated_dirserver_exclusion(void *arg)
|
||||||
|
{
|
||||||
|
int retval;
|
||||||
|
response_handler_args_t *args = NULL;
|
||||||
|
dir_connection_t *conn = NULL;
|
||||||
|
(void) arg;
|
||||||
|
|
||||||
|
/* Test prep: Make a new guard selection */
|
||||||
|
guard_selection_t *gs = get_guard_selection_by_name("default",
|
||||||
|
GS_TYPE_NORMAL, 1);
|
||||||
|
|
||||||
|
/* ... we want to use entry guards */
|
||||||
|
or_options_t *options = get_options_mutable();
|
||||||
|
options->UseEntryGuards = 1;
|
||||||
|
options->UseBridges = 0;
|
||||||
|
|
||||||
|
/* ... prepare some md digests we want to download in the future */
|
||||||
|
smartlist_t *digests = smartlist_new();
|
||||||
|
const char *prose = "unhurried and wise, we perceive.";
|
||||||
|
for (int i = 0; i < 20; i++) {
|
||||||
|
smartlist_add(digests, (char*)prose);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ... now mock some functions */
|
||||||
|
mock_ns_val = tor_malloc_zero(sizeof(networkstatus_t));
|
||||||
|
MOCK(networkstatus_get_latest_consensus_by_flavor, mock_ns_get_by_flavor);
|
||||||
|
MOCK(directory_initiate_request, mock_directory_initiate_request);
|
||||||
|
|
||||||
|
/* Test logic:
|
||||||
|
* 0. Create a proper guard set and primary guard list.
|
||||||
|
* 1. Pretend to fail microdescriptor fetches from all the primary guards.
|
||||||
|
* 2. Order another microdescriptor fetch and make sure that primary guards
|
||||||
|
* get skipped since they failed previous fetches.
|
||||||
|
*/
|
||||||
|
|
||||||
|
{ /* Setup primary guard list */
|
||||||
|
int i;
|
||||||
|
entry_guards_update_primary(gs);
|
||||||
|
for (i = 0; i < DFLT_N_PRIMARY_GUARDS; ++i) {
|
||||||
|
entry_guard_t *guard = smartlist_get(gs->sampled_entry_guards, i);
|
||||||
|
make_guard_confirmed(gs, guard);
|
||||||
|
}
|
||||||
|
entry_guards_update_primary(gs);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
/* Fail microdesc fetches with all the primary guards */
|
||||||
|
args = tor_malloc_zero(sizeof(response_handler_args_t));
|
||||||
|
args->status_code = 404;
|
||||||
|
args->reason = NULL;
|
||||||
|
args->body = NULL;
|
||||||
|
args->body_len = 0;
|
||||||
|
|
||||||
|
conn = tor_malloc_zero(sizeof(dir_connection_t));
|
||||||
|
conn->requested_resource = tor_strdup("d/jlinblackorigami");
|
||||||
|
conn->base_.purpose = DIR_PURPOSE_FETCH_MICRODESC;
|
||||||
|
|
||||||
|
/* Pretend to fail fetches with all primary guards */
|
||||||
|
SMARTLIST_FOREACH_BEGIN(gs->primary_entry_guards,const entry_guard_t *,g) {
|
||||||
|
memcpy(conn->identity_digest, g->identity, DIGEST_LEN);
|
||||||
|
|
||||||
|
retval = handle_response_fetch_microdesc(conn, args);
|
||||||
|
tt_int_op(retval, OP_EQ, 0);
|
||||||
|
} SMARTLIST_FOREACH_END(g);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
/* Now order the final md download */
|
||||||
|
setup_full_capture_of_logs(LOG_INFO);
|
||||||
|
initiate_descriptor_downloads(NULL, DIR_PURPOSE_FETCH_MICRODESC,
|
||||||
|
digests, 3, 7, 0);
|
||||||
|
|
||||||
|
/* ... and check that because we failed to fetch microdescs from all our
|
||||||
|
* primaries, we didnt end up selecting a primary for fetching dir info */
|
||||||
|
expect_log_msg_containing("No primary or confirmed guards available.");
|
||||||
|
teardown_capture_of_logs();
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
smartlist_free(digests);
|
||||||
|
tor_free(args);
|
||||||
|
if (conn) {
|
||||||
|
tor_free(conn->requested_resource);
|
||||||
|
tor_free(conn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static const struct testcase_setup_t big_fake_network = {
|
static const struct testcase_setup_t big_fake_network = {
|
||||||
big_fake_network_setup, big_fake_network_cleanup
|
big_fake_network_setup, big_fake_network_cleanup
|
||||||
};
|
};
|
||||||
|
@ -2734,6 +2845,7 @@ struct testcase_t entrynodes_tests[] = {
|
||||||
BFN_TEST(select_for_circuit_highlevel_primary_retry),
|
BFN_TEST(select_for_circuit_highlevel_primary_retry),
|
||||||
BFN_TEST(select_and_cancel),
|
BFN_TEST(select_and_cancel),
|
||||||
BFN_TEST(drop_guards),
|
BFN_TEST(drop_guards),
|
||||||
|
BFN_TEST(outdated_dirserver_exclusion),
|
||||||
|
|
||||||
UPGRADE_TEST(upgrade_a_circuit, "c1-done c2-done"),
|
UPGRADE_TEST(upgrade_a_circuit, "c1-done c2-done"),
|
||||||
UPGRADE_TEST(upgrade_blocked_by_live_primary_guards, "c1-done c2-done"),
|
UPGRADE_TEST(upgrade_blocked_by_live_primary_guards, "c1-done c2-done"),
|
||||||
|
|
Loading…
Reference in New Issue