aboutsummaryrefslogtreecommitdiff
path: root/src/test/test_hs_client.c
diff options
context:
space:
mode:
authorDavid Goulet <dgoulet@torproject.org>2018-09-19 09:55:57 -0400
committerDavid Goulet <dgoulet@torproject.org>2018-09-19 11:11:57 -0400
commitcb81a69f90c82c2c2a5b41b80eadf50be5e8193d (patch)
treeca86fb5945dc10092a3a6727a6f5617b39ae2b44 /src/test/test_hs_client.c
parentf4f809fe3dc45ce72b4ccfb891eb715a8b330675 (diff)
downloadtor-cb81a69f90c82c2c2a5b41b80eadf50be5e8193d.tar.gz
tor-cb81a69f90c82c2c2a5b41b80eadf50be5e8193d.zip
test: hs-v3 desc has arrived unit test
That unit test makes sure we don't have pending SOCK request if the descriptor turns out to be unusable. Part of #27410. Signed-off-by: David Goulet <dgoulet@torproject.org>
Diffstat (limited to 'src/test/test_hs_client.c')
-rw-r--r--src/test/test_hs_client.c117
1 files changed, 117 insertions, 0 deletions
diff --git a/src/test/test_hs_client.c b/src/test/test_hs_client.c
index c91e82ed4a..a115997c7f 100644
--- a/src/test/test_hs_client.c
+++ b/src/test/test_hs_client.c
@@ -523,6 +523,9 @@ mock_connection_mark_unattached_ap_(entry_connection_t *conn, int endreason,
(void) line;
(void) file;
conn->edge_.end_reason = endreason;
+ /* This function ultimately will flag this so make sure we do also in the
+ * MOCK one so we can assess closed connections vs open ones. */
+ conn->edge_.base_.marked_for_close = 1;
}
static void
@@ -771,6 +774,117 @@ test_config_client_authorization(void *arg)
UNMOCK(check_private_dir);
}
+static entry_connection_t *
+helper_build_socks_connection(const ed25519_public_key_t *service_pk,
+ int conn_state)
+{
+ entry_connection_t *socks = entry_connection_new(CONN_TYPE_AP, AF_INET);
+ ENTRY_TO_EDGE_CONN(socks)->hs_ident = hs_ident_edge_conn_new(service_pk);
+ TO_CONN(ENTRY_TO_EDGE_CONN(socks))->state = conn_state;
+ smartlist_add(get_connection_array(), &socks->edge_.base_);
+ return socks;
+}
+
+static void
+test_desc_has_arrived_cleanup(void *arg)
+{
+ /* The goal of this test is to make sure we clean up everything in between
+ * two descriptors from the same .onion. Because intro points can change
+ * from one descriptor to another, once we received a new descriptor, we
+ * need to cleanup the remaining circuits so they aren't used or selected
+ * when establishing a connection with the newly stored descriptor.
+ *
+ * This test was created because of #27410. */
+
+ int ret;
+ char *desc_str = NULL;
+ hs_descriptor_t *desc = NULL;
+ const hs_descriptor_t *cached_desc;
+ ed25519_keypair_t signing_kp;
+ entry_connection_t *socks1 = NULL, *socks2 = NULL;
+ hs_ident_dir_conn_t hs_dir_ident;
+
+ (void) arg;
+
+ hs_init();
+
+ MOCK(networkstatus_get_live_consensus,
+ mock_networkstatus_get_live_consensus);
+ MOCK(connection_mark_unattached_ap_,
+ mock_connection_mark_unattached_ap_);
+ MOCK(router_have_minimum_dir_info,
+ mock_router_have_minimum_dir_info_true);
+
+ /* Set consensus time before our time so the cache lookup can always
+ * validate that the entry is not expired. */
+ parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC", &mock_ns.valid_after);
+ parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC", &mock_ns.fresh_until);
+ parse_rfc1123_time("Sat, 26 Oct 1985 16:00:00 UTC", &mock_ns.valid_until);
+
+ /* Build a descriptor for a specific .onion. */
+ ret = ed25519_keypair_generate(&signing_kp, 0);
+ tt_int_op(ret, OP_EQ, 0);
+ desc = hs_helper_build_hs_desc_with_ip(&signing_kp);
+ tt_assert(desc);
+ ret = hs_desc_encode_descriptor(desc, &signing_kp, NULL, &desc_str);
+ tt_int_op(ret, OP_EQ, 0);
+
+ /* Store in the client cache. */
+ ret = hs_cache_store_as_client(desc_str, &signing_kp.pubkey);
+ tt_int_op(ret, OP_EQ, 0);
+ cached_desc = hs_cache_lookup_as_client(&signing_kp.pubkey);
+ tt_assert(cached_desc);
+ hs_helper_desc_equal(desc, cached_desc);
+
+ /* Create two SOCKS connection for the same .onion both in the waiting for a
+ * descriptor state. */
+ socks1 = helper_build_socks_connection(&signing_kp.pubkey,
+ AP_CONN_STATE_RENDDESC_WAIT);
+ tt_assert(socks1);
+ socks2 = helper_build_socks_connection(&signing_kp.pubkey,
+ AP_CONN_STATE_RENDDESC_WAIT);
+ tt_assert(socks2);
+
+ /* Now, we'll make the intro points in the current descriptor unusable so
+ * the hs_client_desc_has_arrived() will take the right code path that we
+ * want to test that is the fetched descriptor has bad intro points. */
+ SMARTLIST_FOREACH_BEGIN(desc->encrypted_data.intro_points,
+ hs_desc_intro_point_t *, ip) {
+ hs_cache_client_intro_state_note(&signing_kp.pubkey,
+ &ip->auth_key_cert->signed_key,
+ INTRO_POINT_FAILURE_GENERIC);
+ } SMARTLIST_FOREACH_END(ip);
+
+ /* Simulate that a new descriptor just arrived. We should have both of our
+ * SOCKS connection to be ended with a resolved failed. */
+ hs_ident_dir_conn_init(&signing_kp.pubkey,
+ &desc->plaintext_data.blinded_pubkey, &hs_dir_ident);
+ hs_client_desc_has_arrived(&hs_dir_ident);
+ tt_int_op(socks1->edge_.end_reason, OP_EQ, END_STREAM_REASON_RESOLVEFAILED);
+ /* XXX: MUST work with OP_EQ. */
+ tt_int_op(socks2->edge_.end_reason, OP_EQ, END_STREAM_REASON_RESOLVEFAILED);
+
+ /* Now let say tor cleans up the intro state cache which resets all intro
+ * point failure count. */
+ hs_cache_client_intro_state_purge();
+
+ /* Retrying all SOCKS which should basically do nothing since we don't have
+ * any pending SOCKS connection in AP_CONN_STATE_RENDDESC_WAIT state. */
+ /* XXX: BUG() is triggered here, shouldn't if socks2 wasn't alive. */
+ retry_all_socks_conn_waiting_for_desc();
+
+ done:
+ connection_free_minimal(ENTRY_TO_CONN(socks1));
+ connection_free_minimal(ENTRY_TO_CONN(socks2));
+ hs_descriptor_free(desc);
+ tor_free(desc_str);
+ hs_free_all();
+
+ UNMOCK(networkstatus_get_live_consensus);
+ UNMOCK(connection_mark_unattached_ap_);
+ UNMOCK(router_have_minimum_dir_info);
+}
+
struct testcase_t hs_client_tests[] = {
{ "e2e_rend_circuit_setup_legacy", test_e2e_rend_circuit_setup_legacy,
TT_FORK, NULL, NULL },
@@ -786,5 +900,8 @@ struct testcase_t hs_client_tests[] = {
NULL, NULL },
{ "config_client_authorization", test_config_client_authorization,
TT_FORK, NULL, NULL },
+ { "desc_has_arrived_cleanup", test_desc_has_arrived_cleanup,
+ TT_FORK, NULL, NULL },
+
END_OF_TESTCASES
};