From 418059dd96f5f427eceffff1daeb2a2f6c4adbeb Mon Sep 17 00:00:00 2001 From: David Goulet Date: Tue, 17 Jan 2017 12:09:54 -0500 Subject: [PATCH] test: Add v3 service config and registration test This tests our hs_config.c API to properly load v3 services and register them to the global map. It does NOT test the service object validity, that will be the hs service unit test later on. At this commit, we have 100% code coverage of hs_config.c. Signed-off-by: David Goulet --- src/or/hs_service.c | 20 ++ src/or/hs_service.h | 11 ++ src/test/test_hs_config.c | 391 ++++++++++++++++++++++++++++++++------ 3 files changed, 366 insertions(+), 56 deletions(-) diff --git a/src/or/hs_service.c b/src/or/hs_service.c index eb58c768bb..854ce9e541 100644 --- a/src/or/hs_service.c +++ b/src/or/hs_service.c @@ -6,6 +6,8 @@ * \brief Implement next generation hidden service functionality **/ +#define HS_SERVICE_PRIVATE + #include "or.h" #include "circuitlist.h" #include "config.h" @@ -786,3 +788,21 @@ generate_establish_intro_cell(const uint8_t *circuit_key_material, return NULL; } +#ifdef TOR_UNIT_TESTS + +/* Return the global service map size. Only used by unit test. */ +STATIC unsigned int +get_hs_service_map_size(void) +{ + return HT_SIZE(hs_service_map); +} + +/* Return the staging list size. Only used by unit test. */ +STATIC int +get_hs_service_staging_list_size(void) +{ + return smartlist_len(hs_service_staging_list); +} + +#endif /* TOR_UNIT_TESTS */ + diff --git a/src/or/hs_service.h b/src/or/hs_service.h index 90606acb1c..cd154d3fe9 100644 --- a/src/or/hs_service.h +++ b/src/or/hs_service.h @@ -224,5 +224,16 @@ ssize_t get_establish_intro_payload(uint8_t *buf, size_t buf_len, const trn_cell_establish_intro_t *cell); +#ifdef HS_SERVICE_PRIVATE + +#ifdef TOR_UNIT_TESTS + +STATIC unsigned int get_hs_service_map_size(void); +STATIC int get_hs_service_staging_list_size(void); + +#endif /* TOR_UNIT_TESTS */ + +#endif /* HS_SERVICE_PRIVATE */ + #endif /* TOR_HS_SERVICE_H */ diff --git a/src/test/test_hs_config.c b/src/test/test_hs_config.c index 18b11948a4..343ce9f2f8 100644 --- a/src/test/test_hs_config.c +++ b/src/test/test_hs_config.c @@ -7,15 +7,20 @@ */ #define CONFIG_PRIVATE +#define HS_SERVICE_PRIVATE #include "test.h" #include "test_helpers.h" #include "log_test_helpers.h" -#include "hs_config.h" + #include "config.h" +#include "hs_common.h" +#include "hs_config.h" +#include "hs_service.h" +#include "rendservice.h" static int -helper_config_service_v2(const char *conf, int validate_only) +helper_config_service(const char *conf, int validate_only) { int ret = 0; or_options_t *options = NULL; @@ -28,6 +33,157 @@ helper_config_service_v2(const char *conf, int validate_only) return ret; } +static void +test_invalid_service(void *arg) +{ + int ret; + + (void) arg; + + /* Try with a missing port configuration. */ + { + const char *conf = + "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n" + "HiddenServiceVersion 1\n"; /* Wrong not supported version. */ + setup_full_capture_of_logs(LOG_WARN); + ret = helper_config_service(conf, 1); + tt_int_op(ret, OP_EQ, -1); + expect_log_msg_containing("HiddenServiceVersion must be between 2 and 3"); + teardown_capture_of_logs(); + } + + /* Bad value of HiddenServiceAllowUnknownPorts. */ + { + const char *conf = + "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n" + "HiddenServiceVersion 2\n" + "HiddenServiceAllowUnknownPorts 2\n"; /* Should be 0 or 1. */ + setup_full_capture_of_logs(LOG_WARN); + ret = helper_config_service(conf, 1); + tt_int_op(ret, OP_EQ, -1); + expect_log_msg_containing("HiddenServiceAllowUnknownPorts must be " + "between 0 and 1, not 2"); + teardown_capture_of_logs(); + } + + /* Bad value of HiddenServiceDirGroupReadable */ + { + const char *conf = + "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n" + "HiddenServiceVersion 2\n" + "HiddenServiceDirGroupReadable 2\n"; /* Should be 0 or 1. */ + setup_full_capture_of_logs(LOG_WARN); + ret = helper_config_service(conf, 1); + tt_int_op(ret, OP_EQ, -1); + expect_log_msg_containing("HiddenServiceDirGroupReadable must be " + "between 0 and 1, not 2"); + teardown_capture_of_logs(); + } + + /* Bad value of HiddenServiceMaxStreamsCloseCircuit */ + { + const char *conf = + "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n" + "HiddenServiceVersion 2\n" + "HiddenServiceMaxStreamsCloseCircuit 2\n"; /* Should be 0 or 1. */ + setup_full_capture_of_logs(LOG_WARN); + ret = helper_config_service(conf, 1); + tt_int_op(ret, OP_EQ, -1); + expect_log_msg_containing("HiddenServiceMaxStreamsCloseCircuit must " + "be between 0 and 1, not 2"); + teardown_capture_of_logs(); + } + + /* Too much max streams. */ + { + const char *conf = + "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n" + "HiddenServiceVersion 2\n" + "HiddenServicePort 80\n" + "HiddenServiceMaxStreams 65536\n"; /* One too many. */ + setup_full_capture_of_logs(LOG_WARN); + ret = helper_config_service(conf, 1); + tt_int_op(ret, OP_EQ, -1); + expect_log_msg_containing("HiddenServiceMaxStreams must be between " + "0 and 65535, not 65536"); + teardown_capture_of_logs(); + } + + /* Duplicate directory directive. */ + { + const char *conf = + "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n" + "HiddenServiceVersion 2\n" + "HiddenServicePort 80\n" + "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n" + "HiddenServiceVersion 2\n" + "HiddenServicePort 81\n"; + setup_full_capture_of_logs(LOG_WARN); + ret = helper_config_service(conf, 1); + tt_int_op(ret, OP_EQ, -1); + expect_log_msg_containing("Another hidden service is already " + "configured for directory"); + teardown_capture_of_logs(); + } + + /* Bad port. */ + { + const char *conf = + "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n" + "HiddenServiceVersion 2\n" + "HiddenServicePort 65536\n"; + setup_full_capture_of_logs(LOG_WARN); + ret = helper_config_service(conf, 1); + tt_int_op(ret, OP_EQ, -1); + expect_log_msg_containing("Missing or invalid port"); + teardown_capture_of_logs(); + } + + /* Out of order directives. */ + { + const char *conf = + "HiddenServiceVersion 2\n" + "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n" + "HiddenServicePort 80\n"; + setup_full_capture_of_logs(LOG_WARN); + ret = helper_config_service(conf, 1); + tt_int_op(ret, OP_EQ, -1); + expect_log_msg_containing("HiddenServiceVersion with no preceding " + "HiddenServiceDir directive"); + teardown_capture_of_logs(); + } + + done: + ; +} + +static void +test_valid_service(void *arg) +{ + int ret; + + (void) arg; + + /* Mix of v2 and v3. Still valid. */ + { + const char *conf = + "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n" + "HiddenServiceVersion 2\n" + "HiddenServicePort 80\n" + "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs2\n" + "HiddenServiceVersion 3\n" + "HiddenServicePort 81\n" + "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs3\n" + "HiddenServiceVersion 2\n" + "HiddenServicePort 82\n"; + ret = helper_config_service(conf, 1); + tt_int_op(ret, OP_EQ, 0); + } + + done: + ; +} + static void test_invalid_service_v2(void *arg) { @@ -41,39 +197,12 @@ test_invalid_service_v2(void *arg) "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n" "HiddenServiceVersion 2\n"; setup_full_capture_of_logs(LOG_WARN); - ret = helper_config_service_v2(conf, validate_only); + ret = helper_config_service(conf, validate_only); tt_int_op(ret, OP_EQ, -1); expect_log_msg_containing("with no ports configured."); teardown_capture_of_logs(); } - /* Out of order directives. */ - { - const char *conf = - "HiddenServiceVersion 2\n" - "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n" - "HiddenServicePort 80\n"; - setup_full_capture_of_logs(LOG_WARN); - ret = helper_config_service_v2(conf, validate_only); - tt_int_op(ret, OP_EQ, -1); - expect_log_msg_containing("HiddenServiceVersion with no preceding " - "HiddenServiceDir directive"); - teardown_capture_of_logs(); - } - - /* Bad port. */ - { - const char *conf = - "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n" - "HiddenServiceVersion 2\n" - "HiddenServicePort 65536\n"; - setup_full_capture_of_logs(LOG_WARN); - ret = helper_config_service_v2(conf, validate_only); - tt_int_op(ret, OP_EQ, -1); - expect_log_msg_containing("Missing or invalid port"); - teardown_capture_of_logs(); - } - /* Too many introduction points. */ { const char *conf = @@ -82,25 +211,25 @@ test_invalid_service_v2(void *arg) "HiddenServicePort 80\n" "HiddenServiceNumIntroductionPoints 11\n"; /* One too many. */ setup_full_capture_of_logs(LOG_WARN); - ret = helper_config_service_v2(conf, validate_only); + ret = helper_config_service(conf, validate_only); tt_int_op(ret, OP_EQ, -1); expect_log_msg_containing("HiddenServiceNumIntroductionPoints should " "be between 0 and 10, not 11"); teardown_capture_of_logs(); } - /* Too much max streams. */ + /* Too little introduction points. */ { const char *conf = "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n" "HiddenServiceVersion 2\n" "HiddenServicePort 80\n" - "HiddenServiceMaxStreams 65536\n"; /* One too many. */ + "HiddenServiceNumIntroductionPoints -1\n"; setup_full_capture_of_logs(LOG_WARN); - ret = helper_config_service_v2(conf, validate_only); + ret = helper_config_service(conf, validate_only); tt_int_op(ret, OP_EQ, -1); - expect_log_msg_containing("HiddenServiceMaxStreams should be between " - "0 and 65535, not 65536"); + expect_log_msg_containing("HiddenServiceNumIntroductionPoints should " + "be between 0 and 10, not -1"); teardown_capture_of_logs(); } @@ -112,30 +241,13 @@ test_invalid_service_v2(void *arg) "HiddenServicePort 80\n" "HiddenServiceAuthorizeClient blah alice,bob\n"; /* blah is no good. */ setup_full_capture_of_logs(LOG_WARN); - ret = helper_config_service_v2(conf, validate_only); + ret = helper_config_service(conf, validate_only); tt_int_op(ret, OP_EQ, -1); expect_log_msg_containing("HiddenServiceAuthorizeClient contains " "unrecognized auth-type"); teardown_capture_of_logs(); } - /* Duplicate directory directive. */ - { - const char *conf = - "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n" - "HiddenServiceVersion 2\n" - "HiddenServicePort 80\n" - "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n" - "HiddenServiceVersion 2\n" - "HiddenServicePort 81\n"; - setup_full_capture_of_logs(LOG_WARN); - ret = helper_config_service_v2(conf, validate_only); - tt_int_op(ret, OP_EQ, -1); - expect_log_msg_containing("Another hidden service is already " - "configured for directory"); - teardown_capture_of_logs(); - } - done: ; } @@ -161,7 +273,7 @@ test_valid_service_v2(void *arg) "HiddenServiceMaxStreamsCloseCircuit 0\n" "HiddenServiceDirGroupReadable 1\n" "HiddenServiceNumIntroductionPoints 7\n"; - ret = helper_config_service_v2(conf, 1); + ret = helper_config_service(conf, 1); tt_int_op(ret, OP_EQ, 0); } @@ -179,7 +291,7 @@ test_valid_service_v2(void *arg) "HiddenServiceMaxStreamsCloseCircuit 0\n" "HiddenServiceDirGroupReadable 1\n" "HiddenServiceNumIntroductionPoints 8\n"; - ret = helper_config_service_v2(conf, 1); + ret = helper_config_service(conf, 1); tt_int_op(ret, OP_EQ, 0); } @@ -187,12 +299,179 @@ test_valid_service_v2(void *arg) ; } +static void +test_invalid_service_v3(void *arg) +{ + int validate_only = 1, ret; + + (void) arg; + + /* Try with a missing port configuration. */ + { + const char *conf = + "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n" + "HiddenServiceVersion 3\n"; + setup_full_capture_of_logs(LOG_WARN); + ret = helper_config_service(conf, validate_only); + tt_int_op(ret, OP_EQ, -1); + expect_log_msg_containing("with no ports configured."); + teardown_capture_of_logs(); + } + + /* Too many introduction points. */ + { + const char *conf = + "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n" + "HiddenServiceVersion 3\n" + "HiddenServicePort 80\n" + "HiddenServiceNumIntroductionPoints 21\n"; /* One too many. */ + setup_full_capture_of_logs(LOG_WARN); + ret = helper_config_service(conf, validate_only); + tt_int_op(ret, OP_EQ, -1); + expect_log_msg_containing("HiddenServiceNumIntroductionPoints must " + "be between 3 and 20, not 21."); + teardown_capture_of_logs(); + } + + /* Too little introduction points. */ + { + const char *conf = + "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n" + "HiddenServiceVersion 3\n" + "HiddenServicePort 80\n" + "HiddenServiceNumIntroductionPoints 1\n"; + setup_full_capture_of_logs(LOG_WARN); + ret = helper_config_service(conf, validate_only); + tt_int_op(ret, OP_EQ, -1); + expect_log_msg_containing("HiddenServiceNumIntroductionPoints must " + "be between 3 and 20, not 1."); + teardown_capture_of_logs(); + } + + done: + ; +} + +static void +test_valid_service_v3(void *arg) +{ + int ret; + + (void) arg; + + /* Valid complex configuration. */ + { + const char *conf = + "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n" + "HiddenServiceVersion 3\n" + "HiddenServicePort 80\n" + "HiddenServicePort 22 localhost:22\n" + "HiddenServicePort 42 unix:/path/to/socket\n" + "HiddenServiceAllowUnknownPorts 1\n" + "HiddenServiceMaxStreams 42\n" + "HiddenServiceMaxStreamsCloseCircuit 0\n" + "HiddenServiceDirGroupReadable 1\n" + "HiddenServiceNumIntroductionPoints 7\n"; + ret = helper_config_service(conf, 1); + tt_int_op(ret, OP_EQ, 0); + } + + /* Valid complex configuration. */ + { + const char *conf = + "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs2\n" + "HiddenServiceVersion 3\n" + "HiddenServicePort 65535\n" + "HiddenServicePort 22 1.1.1.1:22\n" + "HiddenServicePort 9000 unix:/path/to/socket\n" + "HiddenServiceAllowUnknownPorts 0\n" + "HiddenServiceMaxStreams 42\n" + "HiddenServiceMaxStreamsCloseCircuit 0\n" + "HiddenServiceDirGroupReadable 1\n" + "HiddenServiceNumIntroductionPoints 20\n"; + ret = helper_config_service(conf, 1); + tt_int_op(ret, OP_EQ, 0); + } + + /* Mix of v2 and v3. Still valid. */ + { + const char *conf = + "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n" + "HiddenServiceVersion 2\n" + "HiddenServicePort 80\n" + "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs2\n" + "HiddenServiceVersion 3\n" + "HiddenServicePort 81\n" + "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs3\n" + "HiddenServiceVersion 2\n" + "HiddenServicePort 82\n"; + ret = helper_config_service(conf, 1); + tt_int_op(ret, OP_EQ, 0); + } + + done: + ; +} + +static void +test_staging_service_v3(void *arg) +{ + int ret; + + (void) arg; + + /* We don't validate a service object, this is the service test that are in + * charge of doing so. We just check for the stable state after + * registration. */ + + hs_init(); + + /* Time for a valid v3 service that should get staged. */ + const char *conf = + "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs2\n" + "HiddenServiceVersion 3\n" + "HiddenServicePort 65535\n" + "HiddenServicePort 22 1.1.1.1:22\n" + "HiddenServicePort 9000 unix:/path/to/socket\n" + "HiddenServiceAllowUnknownPorts 0\n" + "HiddenServiceMaxStreams 42\n" + "HiddenServiceMaxStreamsCloseCircuit 0\n" + "HiddenServiceDirGroupReadable 1\n" + "HiddenServiceNumIntroductionPoints 20\n"; + ret = helper_config_service(conf, 0); + tt_int_op(ret, OP_EQ, 0); + /* Ok, we have a service in our map! Registration went well. */ + tt_int_op(get_hs_service_staging_list_size(), OP_EQ, 1); + /* Make sure we don't have a magic v2 service out of this. */ + tt_int_op(num_rend_services(), OP_EQ, 0); + + done: + hs_free_all(); +} + struct testcase_t hs_config_tests[] = { + /* Invalid service not specific to any version. */ + { "invalid_service", test_invalid_service, TT_FORK, + NULL, NULL }, + { "valid_service", test_valid_service, TT_FORK, + NULL, NULL }, + + /* Test case only for version 2. */ { "invalid_service_v2", test_invalid_service_v2, TT_FORK, NULL, NULL }, { "valid_service_v2", test_valid_service_v2, TT_FORK, NULL, NULL }, + /* Test case only for version 3. */ + { "invalid_service_v3", test_invalid_service_v3, TT_FORK, + NULL, NULL }, + { "valid_service_v3", test_valid_service_v3, TT_FORK, + NULL, NULL }, + + /* Test service staging. */ + { "staging_service_v3", test_staging_service_v3, TT_FORK, + NULL, NULL }, + END_OF_TESTCASES };