#define CONFIG_PRIVATE
#define HS_SERVICE_PRIVATE
#include "test/test.h"
#include "test/test_helpers.h"
#include "test/log_test_helpers.h"
#include "test/resolve_test_helpers.h"
#include "app/config/config.h"
#include "feature/hs/hs_common.h"
#include "feature/hs/hs_config.h"
#include "feature/hs/hs_service.h"
#include "feature/rend/rendservice.h"
static int
helper_config_service(const char *conf, int validate_only)
{
int ret = 0;
or_options_t *options = NULL;
tt_assert(conf);
options = helper_parse_options(conf);
tt_assert(options);
ret = hs_config_service_all(options, validate_only);
done:
or_options_free(options);
return ret;
}
static void
test_invalid_service(void *arg)
{
int ret;
(void) arg;
{
const char *conf =
"HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
"HiddenServiceVersion 1\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 must be between 2 and 3");
teardown_capture_of_logs();
}
{
const char *conf =
"HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
"HiddenServiceVersion 2\n"
"HiddenServiceAllowUnknownPorts 2\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("Could not parse "
"HiddenServiceAllowUnknownPorts: Unrecognized "
"value 2. Allowed values are 0 and 1.");
teardown_capture_of_logs();
}
{
const char *conf =
"HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
"HiddenServiceVersion 2\n"
"HiddenServiceDirGroupReadable 2\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("Could not parse "
"HiddenServiceDirGroupReadable: "
"Unrecognized value 2.");
teardown_capture_of_logs();
}
{
const char *conf =
"HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
"HiddenServiceVersion 2\n"
"HiddenServiceMaxStreamsCloseCircuit 2\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("Could not parse "
"HiddenServiceMaxStreamsCloseCircuit: "
"Unrecognized value 2");
teardown_capture_of_logs();
}
{
const char *conf =
"HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
"HiddenServiceVersion 2\n"
"HiddenServicePort 80\n"
"HiddenServiceMaxStreams 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("HiddenServiceMaxStreams must be between "
"0 and 65535, not 65536");
teardown_capture_of_logs();
}
{
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();
}
{
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();
}
{
const char *conf =
"HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
"HiddenServiceVersion 2\n"
"HiddenServicePort 80 127.0.0.1 8000\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("HiddenServicePort parse error: "
"invalid port mapping");
teardown_capture_of_logs();
}
{
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;
{
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)
{
int validate_only = 1, ret;
(void) arg;
{
const char *conf =
"HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
"HiddenServiceVersion 2\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();
}
{
const char *conf =
"HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
"HiddenServiceVersion 2\n"
"HiddenServicePort 80\n"
"HiddenServiceNumIntroductionPoints 11\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 0 and 10, not 11.");
teardown_capture_of_logs();
}
{
const char *conf =
"HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
"HiddenServiceVersion 2\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("Could not parse "
"HiddenServiceNumIntroductionPoints: "
"Integer -1 is malformed or out of bounds.");
teardown_capture_of_logs();
}
{
const char *conf =
"HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
"HiddenServiceVersion 2\n"
"HiddenServicePort 80\n"
"HiddenServiceAuthorizeClient blah alice,bob\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("HiddenServiceAuthorizeClient contains "
"unrecognized auth-type");
teardown_capture_of_logs();
}
done:
;
}
static void
test_valid_service_v2(void *arg)
{
int ret;
(void) arg;
mock_hostname_resolver();
{
const char *conf =
"HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
"HiddenServiceVersion 2\n"
"HiddenServicePort 80\n"
"HiddenServicePort 22 localhost:22\n"
#ifdef HAVE_SYS_UN_H
"HiddenServicePort 42 unix:/path/to/socket\n"
#endif
"HiddenServiceAuthorizeClient basic alice,bob,eve\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);
}
{
const char *conf =
"HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs2\n"
"HiddenServiceVersion 2\n"
"HiddenServicePort 65535\n"
"HiddenServicePort 22 1.1.1.1:22\n"
#ifdef HAVE_SYS_UN_H
"HiddenServicePort 9000 unix:/path/to/socket\n"
#endif
"HiddenServiceAuthorizeClient stealth charlie,romeo\n"
"HiddenServiceAllowUnknownPorts 0\n"
"HiddenServiceMaxStreams 42\n"
"HiddenServiceMaxStreamsCloseCircuit 0\n"
"HiddenServiceDirGroupReadable 1\n"
"HiddenServiceNumIntroductionPoints 8\n";
ret = helper_config_service(conf, 1);
tt_int_op(ret, OP_EQ, 0);
}
done:
unmock_hostname_resolver();
}
static void
test_invalid_service_v3(void *arg)
{
int validate_only = 1, ret;
(void) arg;
{
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();
}
{
const char *conf =
"HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
"HiddenServiceVersion 3\n"
"HiddenServicePort 80\n"
"HiddenServiceNumIntroductionPoints 21\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 21.");
teardown_capture_of_logs();
}
{
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();
}
{
const char *conf =
"HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
"HiddenServiceVersion 3\n"
"HiddenServiceAuthorizeClient stealth client1\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("Hidden service option "
"HiddenServiceAuthorizeClient is incompatible "
"with version 3 of service in "
"/tmp/tor-test-hs-RANDOM/hs1");
teardown_capture_of_logs();
}
done:
;
}
static void
test_valid_service_v3(void *arg)
{
int ret;
(void) arg;
mock_hostname_resolver();
{
const char *conf =
"HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
"HiddenServiceVersion 3\n"
"HiddenServicePort 80\n"
"HiddenServicePort 22 localhost:22\n"
#ifdef HAVE_SYS_UN_H
"HiddenServicePort 42 unix:/path/to/socket\n"
#endif
"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);
}
{
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"
#ifdef HAVE_SYS_UN_H
"HiddenServicePort 9000 unix:/path/to/socket\n"
#endif
"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);
}
{
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:
unmock_hostname_resolver();
}
static void
test_staging_service_v3(void *arg)
{
int ret;
(void) arg;
hs_init();
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"
#ifdef HAVE_SYS_UN_H
"HiddenServicePort 9000 unix:/path/to/socket\n"
#endif
"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);
tt_int_op(get_hs_service_staging_list_size(), OP_EQ, 1);
tt_int_op(rend_num_services(), OP_EQ, 0);
done:
hs_free_all();
}
static void
test_dos_parameters(void *arg)
{
int ret;
(void) arg;
hs_init();
{
const char *conf =
"HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs3\n"
"HiddenServiceVersion 3\n"
"HiddenServicePort 22 1.1.1.1:22\n"
"HiddenServiceEnableIntroDoSDefense 1\n"
"HiddenServiceEnableIntroDoSRatePerSec 42\n"
"HiddenServiceEnableIntroDoSBurstPerSec 87\n";
setup_full_capture_of_logs(LOG_INFO);
ret = helper_config_service(conf, 0);
tt_int_op(ret, OP_EQ, 0);
expect_log_msg_containing("Service INTRO2 DoS defenses rate set to: 42");
expect_log_msg_containing("Service INTRO2 DoS defenses burst set to: 87");
teardown_capture_of_logs();
}
{
const char *conf =
"HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs3\n"
"HiddenServiceVersion 3\n"
"HiddenServicePort 22 1.1.1.1:22\n"
"HiddenServiceEnableIntroDoSDefense 1\n"
"HiddenServiceEnableIntroDoSRatePerSec 137438953472\n"
"HiddenServiceEnableIntroDoSBurstPerSec 87\n";
setup_full_capture_of_logs(LOG_WARN);
ret = helper_config_service(conf, 0);
tt_int_op(ret, OP_EQ, -1);
expect_log_msg_containing("Could not parse "
"HiddenServiceEnableIntroDoSRatePerSec: "
"Integer 137438953472 is malformed or out of "
"bounds.");
teardown_capture_of_logs();
}
{
const char *conf =
"HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs3\n"
"HiddenServiceVersion 3\n"
"HiddenServicePort 22 1.1.1.1:22\n"
"HiddenServiceEnableIntroDoSDefense 1\n"
"HiddenServiceEnableIntroDoSRatePerSec 42\n"
"HiddenServiceEnableIntroDoSBurstPerSec 274877906944\n";
setup_full_capture_of_logs(LOG_WARN);
ret = helper_config_service(conf, 0);
tt_int_op(ret, OP_EQ, -1);
expect_log_msg_containing("Could not parse "
"HiddenServiceEnableIntroDoSBurstPerSec: "
"Integer 274877906944 is malformed or out "
"of bounds.");
teardown_capture_of_logs();
}
{
const char *conf =
"HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs3\n"
"HiddenServiceVersion 3\n"
"HiddenServicePort 22 1.1.1.1:22\n"
"HiddenServiceEnableIntroDoSDefense 1\n"
"HiddenServiceEnableIntroDoSRatePerSec 42\n"
"HiddenServiceEnableIntroDoSBurstPerSec 27\n";
setup_full_capture_of_logs(LOG_WARN);
ret = helper_config_service(conf, 0);
tt_int_op(ret, OP_EQ, -1);
expect_log_msg_containing("Hidden service DoS defenses burst (27) can "
"not be smaller than the rate value (42).");
teardown_capture_of_logs();
}
{
const char *conf =
"HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs3\n"
"HiddenServiceVersion 3\n"
"HiddenServicePort 22 1.1.1.1:22\n"
"HiddenServiceEnableIntroDoSDefense 1\n"
"HiddenServiceEnableIntroDoSRatePerSec -1\n"
"HiddenServiceEnableIntroDoSBurstPerSec 42\n";
setup_full_capture_of_logs(LOG_WARN);
ret = helper_config_service(conf, 0);
tt_int_op(ret, OP_EQ, -1);
expect_log_msg_containing("Could not parse "
"HiddenServiceEnableIntroDoSRatePerSec: "
"Integer -1 is malformed or out of bounds.");
teardown_capture_of_logs();
}
done:
hs_free_all();
}
struct testcase_t hs_config_tests[] = {
{ "invalid_service", test_invalid_service, TT_FORK,
NULL, NULL },
{ "valid_service", test_valid_service, TT_FORK,
NULL, NULL },
{ "invalid_service_v2", test_invalid_service_v2, TT_FORK,
NULL, NULL },
{ "valid_service_v2", test_valid_service_v2, TT_FORK,
NULL, NULL },
{ "invalid_service_v3", test_invalid_service_v3, TT_FORK,
NULL, NULL },
{ "valid_service_v3", test_valid_service_v3, TT_FORK,
NULL, NULL },
{ "staging_service_v3", test_staging_service_v3, TT_FORK,
NULL, NULL },
{ "dos_parameters", test_dos_parameters, TT_FORK,
NULL, NULL },
END_OF_TESTCASES
};