summaryrefslogtreecommitdiff
path: root/src/test/test_hs_common.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/test_hs_common.c')
-rw-r--r--src/test/test_hs_common.c395
1 files changed, 372 insertions, 23 deletions
diff --git a/src/test/test_hs_common.c b/src/test/test_hs_common.c
index 2461e7cd6e..b63cb7c946 100644
--- a/src/test/test_hs_common.c
+++ b/src/test/test_hs_common.c
@@ -14,11 +14,14 @@
#include "log_test_helpers.h"
#include "hs_test_helpers.h"
+#include "connection_edge.h"
#include "hs_common.h"
#include "hs_service.h"
#include "config.h"
#include "networkstatus.h"
+#include "directory.h"
#include "nodelist.h"
+#include "statefile.h"
/** Test the validation of HS v3 addresses */
static void
@@ -357,6 +360,37 @@ test_desc_overlap_period_testnet(void *arg)
tor_free(dummy_consensus);
}
+static void
+helper_add_hsdir_to_networkstatus(networkstatus_t *ns,
+ const uint8_t *identity,
+ const uint8_t *curr_hsdir_index,
+ const char *nickname,
+ int is_hsdir)
+{
+ routerstatus_t *rs = tor_malloc_zero(sizeof(routerstatus_t));
+ routerinfo_t *ri = tor_malloc_zero(sizeof(routerinfo_t));
+
+ tor_addr_t ipv4_addr;
+ memcpy(rs->identity_digest, identity, DIGEST_LEN);
+ rs->is_hs_dir = is_hsdir;
+ rs->supports_v3_hsdir = 1;
+ tor_addr_parse(&ipv4_addr, "1.2.3.4");
+ ri->addr = tor_addr_to_ipv4h(&ipv4_addr);
+ ri->nickname = tor_strdup(nickname);
+ ri->protocol_list = tor_strdup("HSDir=1-2 LinkAuth=3");
+ memcpy(ri->cache_info.identity_digest, identity, DIGEST_LEN);
+ tt_assert(nodelist_set_routerinfo(ri, NULL));
+ node_t *node = node_get_mutable_by_id(ri->cache_info.identity_digest);
+ tt_assert(node);
+ node->rs = rs;
+ memcpy(node->hsdir_index->current, curr_hsdir_index,
+ sizeof(node->hsdir_index->current));
+ smartlist_add(ns->routerstatus_list, rs);
+
+ done:
+ ;
+}
+
static networkstatus_t *mock_ns = NULL;
static networkstatus_t *
@@ -389,7 +423,7 @@ test_responsible_hsdirs(void *arg)
time_t now = approx_time();
smartlist_t *responsible_dirs = smartlist_new();
networkstatus_t *ns = NULL;
- routerstatus_t *rs = tor_malloc_zero(sizeof(routerstatus_t));
+ int retval;
(void) arg;
@@ -401,39 +435,217 @@ test_responsible_hsdirs(void *arg)
ns = networkstatus_get_latest_consensus();
{ /* First router: HSdir */
- tor_addr_t ipv4_addr;
- memset(rs->identity_digest, 'A', DIGEST_LEN);
- rs->is_hs_dir = 1;
- rs->supports_v3_hsdir = 1;
- routerinfo_t ri;
- memset(&ri, 0 ,sizeof(routerinfo_t));
- tor_addr_parse(&ipv4_addr, "127.0.0.1");
- ri.addr = tor_addr_to_ipv4h(&ipv4_addr);
- ri.nickname = (char *) "fatal";
- ri.protocol_list = (char *) "HSDir=1-2 LinkAuth=3";
- memset(ri.cache_info.identity_digest, 'A', DIGEST_LEN);
- tt_assert(nodelist_set_routerinfo(&ri, NULL));
- node_t *node = node_get_mutable_by_id(ri.cache_info.identity_digest);
- memset(node->hsdir_index->current, 'Z',
- sizeof(node->hsdir_index->current));
- smartlist_add(ns->routerstatus_list, rs);
+ uint8_t identity[DIGEST_LEN];
+ uint8_t curr_hsdir_index[DIGEST256_LEN];
+ char nickname[] = "let_me";
+ memset(identity, 1, sizeof(identity));
+ memset(curr_hsdir_index, 1, sizeof(curr_hsdir_index));
+
+ helper_add_hsdir_to_networkstatus(ns, identity,
+ curr_hsdir_index, nickname, 1);
+ }
+
+ { /* Second HSDir */
+ uint8_t identity[DIGEST_LEN];
+ uint8_t curr_hsdir_index[DIGEST256_LEN];
+ char nickname[] = "show_you";
+ memset(identity, 2, sizeof(identity));
+ memset(curr_hsdir_index, 2, sizeof(curr_hsdir_index));
+
+ helper_add_hsdir_to_networkstatus(ns, identity,
+ curr_hsdir_index, nickname, 1);
+ }
+
+ { /* Third relay but not HSDir */
+ uint8_t identity[DIGEST_LEN];
+ uint8_t curr_hsdir_index[DIGEST256_LEN];
+ char nickname[] = "how_to_dance";
+ memset(identity, 3, sizeof(identity));
+ memset(curr_hsdir_index, 3, sizeof(curr_hsdir_index));
+
+ helper_add_hsdir_to_networkstatus(ns, identity,
+ curr_hsdir_index, nickname, 0);
}
- ed25519_public_key_t blinded_pk;
+ ed25519_keypair_t kp;
+ retval = ed25519_keypair_generate(&kp, 0);
+ tt_int_op(retval, OP_EQ , 0);
+
uint64_t time_period_num = hs_get_time_period_num(now);
- hs_get_responsible_hsdirs(&blinded_pk, time_period_num,
+ hs_get_responsible_hsdirs(&kp.pubkey, time_period_num,
0, 0, responsible_dirs);
- tt_int_op(smartlist_len(responsible_dirs), OP_EQ, 1);
+
+ /* Make sure that we only found 2 responsible HSDirs.
+ * The third relay was not an hsdir! */
+ tt_int_op(smartlist_len(responsible_dirs), OP_EQ, 2);
/** TODO: Build a bigger network and do more tests here */
done:
- routerstatus_free(rs);
+ SMARTLIST_FOREACH(ns->routerstatus_list,
+ routerstatus_t *, rs, routerstatus_free(rs));
smartlist_free(responsible_dirs);
smartlist_clear(ns->routerstatus_list);
networkstatus_vote_free(mock_ns);
}
+static void
+mock_directory_initiate_request(directory_request_t *req)
+{
+ (void)req;
+ return;
+}
+
+static int
+mock_hs_desc_encode_descriptor(const hs_descriptor_t *desc,
+ const ed25519_keypair_t *signing_kp,
+ char **encoded_out)
+{
+ (void)desc;
+ (void)signing_kp;
+
+ tor_asprintf(encoded_out, "lulu");
+ return 0;
+}
+
+static or_state_t dummy_state;
+
+/* Mock function to get fake or state (used for rev counters) */
+static or_state_t *
+get_or_state_replacement(void)
+{
+ return &dummy_state;
+}
+
+static int
+mock_router_have_minimum_dir_info(void)
+{
+ return 1;
+}
+
+/** Test that we correctly detect when the HSDir hash ring changes so that we
+ * reupload our descriptor. */
+static void
+test_desc_reupload_logic(void *arg)
+{
+ networkstatus_t *ns = NULL;
+
+ (void) arg;
+
+ hs_init();
+
+ MOCK(router_have_minimum_dir_info,
+ mock_router_have_minimum_dir_info);
+ MOCK(get_or_state,
+ get_or_state_replacement);
+ MOCK(networkstatus_get_latest_consensus,
+ mock_networkstatus_get_latest_consensus);
+ MOCK(directory_initiate_request,
+ mock_directory_initiate_request);
+ MOCK(hs_desc_encode_descriptor,
+ mock_hs_desc_encode_descriptor);
+
+ ns = networkstatus_get_latest_consensus();
+
+ /** Test logic:
+ * 1) Upload descriptor to HSDirs
+ * CHECK that previous_hsdirs list was populated.
+ * 2) Then call router_dir_info_changed() without an HSDir set change.
+ * CHECK that no reuplod occurs.
+ * 3) Now change the HSDir set, and call dir_info_changed() again.
+ * CHECK that reupload occurs.
+ * 4) Finally call service_desc_schedule_upload().
+ * CHECK that previous_hsdirs list was cleared.
+ **/
+
+ /* Let's start by building our descriptor and service */
+ hs_service_descriptor_t *desc = service_descriptor_new();
+ hs_service_t *service = NULL;
+ char onion_addr[HS_SERVICE_ADDR_LEN_BASE32 + 1];
+ ed25519_public_key_t pubkey;
+ memset(&pubkey, '\x42', sizeof(pubkey));
+ hs_build_address(&pubkey, HS_VERSION_THREE, onion_addr);
+ service = tor_malloc_zero(sizeof(hs_service_t));
+ memcpy(service->onion_address, onion_addr, sizeof(service->onion_address));
+ ed25519_secret_key_generate(&service->keys.identity_sk, 0);
+ ed25519_public_key_generate(&service->keys.identity_pk,
+ &service->keys.identity_sk);
+ service->desc_current = desc;
+ /* Also add service to service map */
+ hs_service_ht *service_map = get_hs_service_map();
+ tt_assert(service_map);
+ tt_int_op(hs_service_get_num_services(), OP_EQ, 0);
+ register_service(service_map, service);
+ tt_int_op(hs_service_get_num_services(), OP_EQ, 1);
+
+ /* Now let's create our hash ring: */
+ { /* First HSDir */
+ uint8_t identity[DIGEST_LEN];
+ uint8_t curr_hsdir_index[DIGEST256_LEN];
+ char nickname[] = "let_me";
+ memset(identity, 1, sizeof(identity));
+ memset(curr_hsdir_index, 1, sizeof(curr_hsdir_index));
+
+ helper_add_hsdir_to_networkstatus(ns, identity,
+ curr_hsdir_index, nickname, 1);
+ }
+
+ { /* Second HSDir */
+ uint8_t identity[DIGEST_LEN];
+ uint8_t curr_hsdir_index[DIGEST256_LEN];
+ char nickname[] = "show_you";
+ memset(identity, 2, sizeof(identity));
+ memset(curr_hsdir_index, 2, sizeof(curr_hsdir_index));
+
+ helper_add_hsdir_to_networkstatus(ns, identity,
+ curr_hsdir_index, nickname, 1);
+ }
+
+ /* Now let's upload our desc to all hsdirs */
+ upload_descriptor_to_all(service, desc, 0);
+ /* Check that previous hsdirs were populated */
+ tt_int_op(smartlist_len(desc->previous_hsdirs), OP_EQ, 2);
+
+ /* Poison next upload time so that we can see if it was changed by
+ * router_dir_info_changed(). No changes in hash ring so far, so the upload
+ * time should stay as is. */
+ desc->next_upload_time = 42;
+ router_dir_info_changed();
+ tt_int_op(desc->next_upload_time, OP_EQ, 42);
+
+ /* Now change the HSDir hash ring by adding another node */
+
+ { /* Third HSDir */
+ uint8_t identity[DIGEST_LEN];
+ uint8_t curr_hsdir_index[DIGEST256_LEN];
+ char nickname[] = "how_to_dance";
+ memset(identity, 3, sizeof(identity));
+ memset(curr_hsdir_index, 3, sizeof(curr_hsdir_index));
+
+ helper_add_hsdir_to_networkstatus(ns, identity,
+ curr_hsdir_index, nickname, 1);
+ }
+
+ /* Now call router_dir_info_changed() again and see that it detected the hash
+ ring change and updated the upload time */
+ time_t now = approx_time();
+ tt_assert(now);
+ router_dir_info_changed();
+ tt_int_op(desc->next_upload_time, OP_EQ, now);
+
+ /* Now pretend that the descriptor changed, and order a reupload to all
+ HSDirs. Make sure that the set of previous HSDirs was cleared. */
+ service_desc_schedule_upload(desc, now, 1);
+ tt_int_op(smartlist_len(desc->previous_hsdirs), OP_EQ, 0);
+
+ /* Now reupload again: see that the prev hsdir set got populated again. */
+ upload_descriptor_to_all(service, desc, 0);
+ tt_int_op(smartlist_len(desc->previous_hsdirs), OP_EQ, 3);
+
+ done:
+ hs_free_all();
+}
+
/** Test disaster SRV computation and caching */
static void
test_disaster_srv(void *arg)
@@ -485,6 +697,136 @@ test_disaster_srv(void *arg)
;
}
+/** Test our HS descriptor request tracker by making various requests and
+ * checking whether they get tracked properly. */
+static void
+test_hid_serv_request_tracker(void *arg)
+{
+ (void) arg;
+ time_t retval;
+ routerstatus_t *hsdir = NULL, *hsdir2 = NULL;
+ time_t now = approx_time();
+
+ const char *req_key_str_first =
+ "vd4zb6zesaubtrjvdqcr2w7x7lhw2up4Xnw4526ThUNbL5o1go+EdUuEqlKxHkNbnK41pRzizzs";
+ const char *req_key_str_second =
+ "g53o7iavcd62oihswhr24u6czmqws5kpXnw4526ThUNbL5o1go+EdUuEqlKxHkNbnK41pRzizzs";
+
+ /*************************** basic test *******************************/
+
+ /* Get request tracker and make sure it's empty */
+ strmap_t *request_tracker = get_last_hid_serv_requests();
+ tt_int_op(strmap_size(request_tracker),OP_EQ, 0);
+
+ /* Let's register a hid serv request */
+ hsdir = tor_malloc_zero(sizeof(routerstatus_t));
+ memset(hsdir->identity_digest, 'Z', DIGEST_LEN);
+ retval = hs_lookup_last_hid_serv_request(hsdir, req_key_str_first,
+ now, 1);
+ tt_int_op(retval, OP_EQ, now);
+ tt_int_op(strmap_size(request_tracker),OP_EQ, 1);
+
+ /* Let's lookup a non-existent hidserv request */
+ retval = hs_lookup_last_hid_serv_request(hsdir, req_key_str_second,
+ now+1, 0);
+ tt_int_op(retval, OP_EQ, 0);
+ tt_int_op(strmap_size(request_tracker),OP_EQ, 1);
+
+ /* Let's lookup a real hidserv request */
+ retval = hs_lookup_last_hid_serv_request(hsdir, req_key_str_first,
+ now+2, 0);
+ tt_int_op(retval, OP_EQ, now); /* we got it */
+ tt_int_op(strmap_size(request_tracker),OP_EQ, 1);
+
+ /**********************************************************************/
+
+ /* Let's add another request for the same HS but on a different HSDir. */
+ hsdir2 = tor_malloc_zero(sizeof(routerstatus_t));
+ memset(hsdir->identity_digest, 2, DIGEST_LEN);
+ retval = hs_lookup_last_hid_serv_request(hsdir2, req_key_str_first,
+ now+3, 1);
+ tt_int_op(retval, OP_EQ, now+3);
+ tt_int_op(strmap_size(request_tracker),OP_EQ, 2);
+
+ /* Check that we can clean the first request based on time */
+ hs_clean_last_hid_serv_requests(now+3+REND_HID_SERV_DIR_REQUERY_PERIOD);
+ tt_int_op(strmap_size(request_tracker),OP_EQ, 1);
+ /* Check that it doesn't exist anymore */
+ retval = hs_lookup_last_hid_serv_request(hsdir, req_key_str_first,
+ now+2, 0);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /*************************** deleting entries **************************/
+
+ /* Add another request with very short key */
+ retval = hs_lookup_last_hid_serv_request(hsdir, "l", now, 1);
+
+ /* Try deleting entries with a dummy key. Check that our previous requests
+ * are still there */
+ tor_capture_bugs_(1);
+ hs_purge_hid_serv_from_last_hid_serv_requests("a");
+ tt_int_op(strmap_size(request_tracker),OP_EQ, 2);
+ tor_end_capture_bugs_();
+
+ /* Try another dummy key. Check that requests are still there */
+ {
+ char dummy[2000];
+ memset(dummy, 'Z', 2000);
+ dummy[1999] = '\x00';
+ hs_purge_hid_serv_from_last_hid_serv_requests(dummy);
+ tt_int_op(strmap_size(request_tracker),OP_EQ, 2);
+ }
+
+ /* Another dummy key! */
+ hs_purge_hid_serv_from_last_hid_serv_requests(req_key_str_second);
+ tt_int_op(strmap_size(request_tracker),OP_EQ, 2);
+
+ /* Now actually delete a request! */
+ hs_purge_hid_serv_from_last_hid_serv_requests(req_key_str_first);
+ tt_int_op(strmap_size(request_tracker),OP_EQ, 1);
+
+ /* Purge it all! */
+ hs_purge_last_hid_serv_requests();
+ request_tracker = get_last_hid_serv_requests();
+ tt_int_op(strmap_size(request_tracker),OP_EQ, 0);
+
+ done:
+ tor_free(hsdir);
+ tor_free(hsdir2);
+}
+
+static void
+test_parse_extended_hostname(void *arg)
+{
+ (void) arg;
+
+ char address1[] = "fooaddress.onion";
+ char address2[] = "aaaaaaaaaaaaaaaa.onion";
+ char address3[] = "fooaddress.exit";
+ char address4[] = "www.torproject.org";
+ char address5[] = "foo.abcdefghijklmnop.onion";
+ char address6[] = "foo.bar.abcdefghijklmnop.onion";
+ char address7[] = ".abcdefghijklmnop.onion";
+ char address8[] =
+ "www.p3xnclpu4mu22dwaurjtsybyqk4xfjmcfz6z62yl24uwmhjatiwnlnad.onion";
+
+ tt_assert(BAD_HOSTNAME == parse_extended_hostname(address1));
+ tt_assert(ONION_V2_HOSTNAME == parse_extended_hostname(address2));
+ tt_str_op(address2,OP_EQ, "aaaaaaaaaaaaaaaa");
+ tt_assert(EXIT_HOSTNAME == parse_extended_hostname(address3));
+ tt_assert(NORMAL_HOSTNAME == parse_extended_hostname(address4));
+ tt_assert(ONION_V2_HOSTNAME == parse_extended_hostname(address5));
+ tt_str_op(address5,OP_EQ, "abcdefghijklmnop");
+ tt_assert(ONION_V2_HOSTNAME == parse_extended_hostname(address6));
+ tt_str_op(address6,OP_EQ, "abcdefghijklmnop");
+ tt_assert(BAD_HOSTNAME == parse_extended_hostname(address7));
+ tt_assert(ONION_V3_HOSTNAME == parse_extended_hostname(address8));
+ tt_str_op(address8, OP_EQ,
+ "p3xnclpu4mu22dwaurjtsybyqk4xfjmcfz6z62yl24uwmhjatiwnlnad");
+
+ done: ;
+}
+
struct testcase_t hs_common_tests[] = {
{ "build_address", test_build_address, TT_FORK,
NULL, NULL },
@@ -498,9 +840,16 @@ struct testcase_t hs_common_tests[] = {
NULL, NULL },
{ "desc_overlap_period_testnet", test_desc_overlap_period_testnet, TT_FORK,
NULL, NULL },
- { "desc_responsible_hsdirs", test_responsible_hsdirs, TT_FORK,
+ { "responsible_hsdirs", test_responsible_hsdirs, TT_FORK,
+ NULL, NULL },
+ { "desc_reupload_logic", test_desc_reupload_logic, TT_FORK,
+ NULL, NULL },
+ { "disaster_srv", test_disaster_srv, TT_FORK,
+ NULL, NULL },
+ { "hid_serv_request_tracker", test_hid_serv_request_tracker, TT_FORK,
+ NULL, NULL },
+ { "parse_extended_hostname", test_parse_extended_hostname, TT_FORK,
NULL, NULL },
- { "disaster_srv", test_disaster_srv, TT_FORK, NULL, NULL },
END_OF_TESTCASES
};