summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2017-11-17 09:58:12 -0500
committerNick Mathewson <nickm@torproject.org>2017-11-17 09:58:12 -0500
commit9c17a6d28b4acf044f408a0c7211e051e238c797 (patch)
treeb317bbdeb56ccd111d2276d6c10ff4d35011ae02
parent9fbc835f10e9fba6a9b0c6643a41aee9c8aa05c2 (diff)
parent3a5ca47d8f0b97da80199c7787b81c28c9247bb3 (diff)
downloadtor-9c17a6d28b4acf044f408a0c7211e051e238c797.tar.gz
tor-9c17a6d28b4acf044f408a0c7211e051e238c797.zip
Merge branch 'bug23817_tests_032' into maint-0.3.2
-rw-r--r--src/or/directory.c42
-rw-r--r--src/or/directory.h42
-rw-r--r--src/test/test_entrynodes.c146
3 files changed, 171 insertions, 59 deletions
diff --git a/src/or/directory.c b/src/or/directory.c
index 43a03a2fd9..66bdef2361 100644
--- a/src/or/directory.c
+++ b/src/or/directory.c
@@ -1012,48 +1012,6 @@ directory_must_use_begindir(const or_options_t *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
* "begindir-style" connection for this directory request.
* 0) If there is no DirPort, yes.
diff --git a/src/or/directory.h b/src/or/directory.h
index b57b7b544b..5e6a91d3e7 100644
--- a/src/or/directory.h
+++ b/src/or/directory.h
@@ -183,6 +183,48 @@ typedef struct response_handler_args_t {
const char *headers;
} 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;
STATIC int handle_get_hs_descriptor_v3(dir_connection_t *conn,
const struct get_handler_args_t *args);
diff --git a/src/test/test_entrynodes.c b/src/test/test_entrynodes.c
index f9d981953d..43cc394888 100644
--- a/src/test/test_entrynodes.c
+++ b/src/test/test_entrynodes.c
@@ -7,6 +7,7 @@
#define STATEFILE_PRIVATE
#define ENTRYNODES_PRIVATE
#define ROUTERLIST_PRIVATE
+#define DIRECTORY_PRIVATE
#include "or.h"
#include "test.h"
@@ -15,6 +16,7 @@
#include "circuitlist.h"
#include "config.h"
#include "confparse.h"
+#include "directory.h"
#include "entrynodes.h"
#include "nodelist.h"
#include "networkstatus.h"
@@ -129,6 +131,14 @@ big_fake_network_setup(const struct testcase_t *testcase)
n->rs->has_bandwidth = 1;
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. */
if (i % 2 == 0) {
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. */
(void)arg;
guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
+ entry_guard_restriction_t *rst = NULL;
/* simple starting configuration */
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);
/* But if we impose a restriction, we don't get the same guard */
- entry_guard_restriction_t rst;
- memset(&rst, 0, sizeof(rst));
- memcpy(rst.exclude_id, g->identity, DIGEST_LEN);
- g2 = select_entry_guard_for_circuit(gs, GUARD_USAGE_TRAFFIC, &rst, &state);
+ rst = guard_create_exit_restriction((uint8_t*)g->identity);
+ g2 = select_entry_guard_for_circuit(gs, GUARD_USAGE_TRAFFIC, rst, &state);
tt_ptr_op(g2, OP_NE, g);
done:
guard_selection_free(gs);
+ entry_guard_restriction_free(rst);
}
static void
@@ -1817,6 +1827,7 @@ test_entry_guard_select_for_circuit_confirmed(void *arg)
guards, we use a confirmed guard. */
(void)arg;
int i;
+ entry_guard_restriction_t *rst = NULL;
guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
const int N_CONFIRMED = 10;
@@ -1877,10 +1888,8 @@ test_entry_guard_select_for_circuit_confirmed(void *arg)
get_options_mutable()->EnforceDistinctSubnets = 0;
g = smartlist_get(gs->confirmed_entry_guards,
smartlist_len(gs->primary_entry_guards)+2);
- entry_guard_restriction_t rst;
- memset(&rst, 0, sizeof(rst));
- memcpy(rst.exclude_id, g->identity, DIGEST_LEN);
- g2 = select_entry_guard_for_circuit(gs, GUARD_USAGE_TRAFFIC, &rst, &state);
+ rst = guard_create_exit_restriction((uint8_t*)g->identity);
+ 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, g);
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.
get_options_mutable()->EnforceDistinctSubnets = 1;
g = smartlist_get(gs->confirmed_entry_guards, 0);
- memset(&rst, 0, sizeof(rst));
- memcpy(rst.exclude_id, g->identity, DIGEST_LEN);
- 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_EQ, NULL);
done:
guard_selection_free(gs);
+ entry_guard_restriction_free(rst);
}
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
* that circ2 was restricted to not use the same guard as circ1. */
data->guard2_state->restrictions =
- tor_malloc_zero(sizeof(entry_guard_restriction_t));
- memcpy(data->guard2_state->restrictions->exclude_id,
- data->guard1->identity, DIGEST_LEN);
+ guard_create_exit_restriction((uint8_t*)data->guard1->identity);
smartlist_t *result = smartlist_new();
int r;
@@ -2604,9 +2611,7 @@ test_entry_guard_upgrade_not_blocked_by_restricted_circ_pending(void *arg)
}
data->guard2_state->restrictions =
- tor_malloc_zero(sizeof(entry_guard_restriction_t));
- memcpy(data->guard2_state->restrictions->exclude_id,
- data->guard1->identity, DIGEST_LEN);
+ guard_create_exit_restriction((uint8_t*)data->guard1->identity);
smartlist_t *result = smartlist_new();
int r;
@@ -2674,6 +2679,112 @@ test_enty_guard_should_expire_waiting(void *arg)
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 = {
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_and_cancel),
BFN_TEST(drop_guards),
+ BFN_TEST(outdated_dirserver_exclusion),
UPGRADE_TEST(upgrade_a_circuit, "c1-done c2-done"),
UPGRADE_TEST(upgrade_blocked_by_live_primary_guards, "c1-done c2-done"),