Loading src/or/rendservice.c +1 −1 Original line number Diff line number Diff line Loading @@ -545,7 +545,7 @@ rend_service_check_dir_and_add(smartlist_t *service_list, /* If this is a reload and there were hidden services configured before, * keep the introduction points that are still needed and close the * other ones. */ static void STATIC void prune_services_on_reload(smartlist_t *old_service_list, smartlist_t *new_service_list) { Loading src/or/rendservice.h +3 −0 Original line number Diff line number Diff line Loading @@ -132,6 +132,9 @@ STATIC int rend_service_poison_new_single_onion_dir( STATIC ssize_t encode_establish_intro_cell_legacy(char *cell_body_out, crypto_pk_t *intro_key, char *rend_circ_nonce); STATIC void prune_services_on_reload(smartlist_t *old_service_list, smartlist_t *new_service_list); #endif int num_rend_services(void); Loading src/test/test_hs.c +123 −0 Original line number Diff line number Diff line Loading @@ -787,6 +787,126 @@ test_single_onion_poisoning(void *arg) tor_free(mock_options->DataDirectory); } static rend_service_t * helper_create_rend_service(const char *path) { rend_service_t *s = tor_malloc_zero(sizeof(rend_service_t)); s->ports = smartlist_new(); s->intro_nodes = smartlist_new(); s->expiring_nodes = smartlist_new(); if (path) { s->directory = tor_strdup(path); } return s; } static void test_prune_services_on_reload(void *arg) { smartlist_t *new = smartlist_new(), *old = smartlist_new(); /* Non ephemeral service. */ rend_service_t *s1 = helper_create_rend_service("SomePath"); /* Create a non ephemeral service with the _same_ path as so we can test the * transfer of introduction point between the same services on reload. */ rend_service_t *s2 = helper_create_rend_service(s1->directory); /* Ephemeral service (directory is NULL). */ rend_service_t *e1 = helper_create_rend_service(NULL); rend_service_t *e2 = helper_create_rend_service(NULL); (void) arg; { /* Add both services to the old list. */ smartlist_add(old, s1); smartlist_add(old, e1); /* Only put the non ephemeral in the new list. */ smartlist_add(new, s1); prune_services_on_reload(old, new); /* We expect that the ephemeral one is in the new list but removed from * the old one. */ tt_int_op(smartlist_len(old), OP_EQ, 1); tt_assert(smartlist_get(old, 0) == s1); tt_int_op(smartlist_len(new), OP_EQ, 2); tt_assert(smartlist_get(new, 0) == s1); tt_assert(smartlist_get(new, 1) == e1); /* Cleanup for next test. */ smartlist_clear(new); smartlist_clear(old); } { /* This test will make sure that only the ephemeral service is kept if the * new list is empty. The old list should contain only the non ephemeral * one. */ smartlist_add(old, s1); smartlist_add(old, e1); prune_services_on_reload(old, new); tt_int_op(smartlist_len(old), OP_EQ, 1); tt_assert(smartlist_get(old, 0) == s1); tt_int_op(smartlist_len(new), OP_EQ, 1); tt_assert(smartlist_get(new, 0) == e1); /* Cleanup for next test. */ smartlist_clear(new); smartlist_clear(old); } { /* This test makes sure that the new list stays the same even from the old * list being completely different. */ smartlist_add(new, s1); smartlist_add(new, e1); prune_services_on_reload(old, new); tt_int_op(smartlist_len(old), OP_EQ, 0); tt_int_op(smartlist_len(new), OP_EQ, 2); tt_assert(smartlist_get(new, 0) == s1); tt_assert(smartlist_get(new, 1) == e1); /* Cleanup for next test. */ smartlist_clear(new); } { rend_intro_point_t ip1; /* This IP should be found in the s2 service after pruning. */ smartlist_add(s1->intro_nodes, &ip1); /* Setup our list. */ smartlist_add(old, s1); smartlist_add(new, s2); prune_services_on_reload(old, new); tt_int_op(smartlist_len(old), OP_EQ, 1); /* Intro nodes have been moved to the s2 in theory so it must be empty. */ tt_int_op(smartlist_len(s1->intro_nodes), OP_EQ, 0); tt_int_op(smartlist_len(new), OP_EQ, 1); rend_service_t *elem = smartlist_get(new, 0); tt_assert(elem); tt_assert(elem == s2); tt_int_op(smartlist_len(elem->intro_nodes), OP_EQ, 1); tt_assert(smartlist_get(elem->intro_nodes, 0) == &ip1); smartlist_clear(s1->intro_nodes); smartlist_clear(s2->intro_nodes); /* Cleanup for next test. */ smartlist_clear(new); smartlist_clear(old); } { /* Test two ephemeral services. */ smartlist_add(old, e1); smartlist_add(old, e2); prune_services_on_reload(old, new); /* Check if they've all been transfered. */ tt_int_op(smartlist_len(old), OP_EQ, 0); tt_int_op(smartlist_len(new), OP_EQ, 2); } done: rend_service_free(s1); rend_service_free(s2); rend_service_free(e1); rend_service_free(e2); smartlist_free(new); smartlist_free(old); } struct testcase_t hs_tests[] = { { "hs_rend_data", test_hs_rend_data, TT_FORK, NULL, NULL }, Loading @@ -807,6 +927,9 @@ struct testcase_t hs_tests[] = { TT_FORK, &passthrough_setup, (void*)(CREATE_HS_DIR2) }, { "single_onion_poisoning_create_dir_both", test_single_onion_poisoning, TT_FORK, &passthrough_setup, (void*)(CREATE_HS_DIR1 | CREATE_HS_DIR2) }, { "prune_services_on_reload", test_prune_services_on_reload, TT_FORK, NULL, NULL }, END_OF_TESTCASES }; Loading
src/or/rendservice.c +1 −1 Original line number Diff line number Diff line Loading @@ -545,7 +545,7 @@ rend_service_check_dir_and_add(smartlist_t *service_list, /* If this is a reload and there were hidden services configured before, * keep the introduction points that are still needed and close the * other ones. */ static void STATIC void prune_services_on_reload(smartlist_t *old_service_list, smartlist_t *new_service_list) { Loading
src/or/rendservice.h +3 −0 Original line number Diff line number Diff line Loading @@ -132,6 +132,9 @@ STATIC int rend_service_poison_new_single_onion_dir( STATIC ssize_t encode_establish_intro_cell_legacy(char *cell_body_out, crypto_pk_t *intro_key, char *rend_circ_nonce); STATIC void prune_services_on_reload(smartlist_t *old_service_list, smartlist_t *new_service_list); #endif int num_rend_services(void); Loading
src/test/test_hs.c +123 −0 Original line number Diff line number Diff line Loading @@ -787,6 +787,126 @@ test_single_onion_poisoning(void *arg) tor_free(mock_options->DataDirectory); } static rend_service_t * helper_create_rend_service(const char *path) { rend_service_t *s = tor_malloc_zero(sizeof(rend_service_t)); s->ports = smartlist_new(); s->intro_nodes = smartlist_new(); s->expiring_nodes = smartlist_new(); if (path) { s->directory = tor_strdup(path); } return s; } static void test_prune_services_on_reload(void *arg) { smartlist_t *new = smartlist_new(), *old = smartlist_new(); /* Non ephemeral service. */ rend_service_t *s1 = helper_create_rend_service("SomePath"); /* Create a non ephemeral service with the _same_ path as so we can test the * transfer of introduction point between the same services on reload. */ rend_service_t *s2 = helper_create_rend_service(s1->directory); /* Ephemeral service (directory is NULL). */ rend_service_t *e1 = helper_create_rend_service(NULL); rend_service_t *e2 = helper_create_rend_service(NULL); (void) arg; { /* Add both services to the old list. */ smartlist_add(old, s1); smartlist_add(old, e1); /* Only put the non ephemeral in the new list. */ smartlist_add(new, s1); prune_services_on_reload(old, new); /* We expect that the ephemeral one is in the new list but removed from * the old one. */ tt_int_op(smartlist_len(old), OP_EQ, 1); tt_assert(smartlist_get(old, 0) == s1); tt_int_op(smartlist_len(new), OP_EQ, 2); tt_assert(smartlist_get(new, 0) == s1); tt_assert(smartlist_get(new, 1) == e1); /* Cleanup for next test. */ smartlist_clear(new); smartlist_clear(old); } { /* This test will make sure that only the ephemeral service is kept if the * new list is empty. The old list should contain only the non ephemeral * one. */ smartlist_add(old, s1); smartlist_add(old, e1); prune_services_on_reload(old, new); tt_int_op(smartlist_len(old), OP_EQ, 1); tt_assert(smartlist_get(old, 0) == s1); tt_int_op(smartlist_len(new), OP_EQ, 1); tt_assert(smartlist_get(new, 0) == e1); /* Cleanup for next test. */ smartlist_clear(new); smartlist_clear(old); } { /* This test makes sure that the new list stays the same even from the old * list being completely different. */ smartlist_add(new, s1); smartlist_add(new, e1); prune_services_on_reload(old, new); tt_int_op(smartlist_len(old), OP_EQ, 0); tt_int_op(smartlist_len(new), OP_EQ, 2); tt_assert(smartlist_get(new, 0) == s1); tt_assert(smartlist_get(new, 1) == e1); /* Cleanup for next test. */ smartlist_clear(new); } { rend_intro_point_t ip1; /* This IP should be found in the s2 service after pruning. */ smartlist_add(s1->intro_nodes, &ip1); /* Setup our list. */ smartlist_add(old, s1); smartlist_add(new, s2); prune_services_on_reload(old, new); tt_int_op(smartlist_len(old), OP_EQ, 1); /* Intro nodes have been moved to the s2 in theory so it must be empty. */ tt_int_op(smartlist_len(s1->intro_nodes), OP_EQ, 0); tt_int_op(smartlist_len(new), OP_EQ, 1); rend_service_t *elem = smartlist_get(new, 0); tt_assert(elem); tt_assert(elem == s2); tt_int_op(smartlist_len(elem->intro_nodes), OP_EQ, 1); tt_assert(smartlist_get(elem->intro_nodes, 0) == &ip1); smartlist_clear(s1->intro_nodes); smartlist_clear(s2->intro_nodes); /* Cleanup for next test. */ smartlist_clear(new); smartlist_clear(old); } { /* Test two ephemeral services. */ smartlist_add(old, e1); smartlist_add(old, e2); prune_services_on_reload(old, new); /* Check if they've all been transfered. */ tt_int_op(smartlist_len(old), OP_EQ, 0); tt_int_op(smartlist_len(new), OP_EQ, 2); } done: rend_service_free(s1); rend_service_free(s2); rend_service_free(e1); rend_service_free(e2); smartlist_free(new); smartlist_free(old); } struct testcase_t hs_tests[] = { { "hs_rend_data", test_hs_rend_data, TT_FORK, NULL, NULL }, Loading @@ -807,6 +927,9 @@ struct testcase_t hs_tests[] = { TT_FORK, &passthrough_setup, (void*)(CREATE_HS_DIR2) }, { "single_onion_poisoning_create_dir_both", test_single_onion_poisoning, TT_FORK, &passthrough_setup, (void*)(CREATE_HS_DIR1 | CREATE_HS_DIR2) }, { "prune_services_on_reload", test_prune_services_on_reload, TT_FORK, NULL, NULL }, END_OF_TESTCASES };