diff --git a/src/feature/hs/.may_include b/src/feature/hs/.may_include index 424c745c12..11c5ffbb14 100644 --- a/src/feature/hs/.may_include +++ b/src/feature/hs/.may_include @@ -1 +1,2 @@ *.h +*.inc diff --git a/src/feature/hs/hs_config.c b/src/feature/hs/hs_config.c index f38e3655db..0f2cbbd588 100644 --- a/src/feature/hs/hs_config.c +++ b/src/feature/hs/hs_config.c @@ -31,8 +31,63 @@ #include "feature/rend/rendclient.h" #include "feature/rend/rendservice.h" #include "lib/encoding/confline.h" +#include "lib/conf/confdecl.h" +#include "lib/confmgt/confmgt.h" + +#include "feature/hs/hs_opts_st.h" #include "app/config/or_options_st.h" +/* Declare the table mapping hs options to hs_opts_t */ +#define CONF_CONTEXT TABLE +#include "feature/hs/hs_options.inc" +#undef CONF_CONTEXT + +/** Magic number for hs_opts_t. */ +#define HS_OPTS_MAGIC 0x6f6e796e + +static const config_format_t hs_opts_fmt = { + .size = sizeof(hs_opts_t), + .magic = { "hs_opts_t", + HS_OPTS_MAGIC, + offsetof(hs_opts_t, magic) }, + .vars = hs_opts_t_vars, +}; + +/** Global configuration manager to handle HS sections*/ +static config_mgr_t *hs_opts_mgr = NULL; + +/** + * Return a configuration manager for the hs_opts_t configuration type. + **/ +static const config_mgr_t * +get_hs_opts_mgr(void) +{ + if (PREDICT_UNLIKELY(hs_opts_mgr == NULL)) { + hs_opts_mgr = config_mgr_new(&hs_opts_fmt); + config_mgr_freeze(hs_opts_mgr); + } + return hs_opts_mgr; +} + +/** + * Allocate, initialize, and return a new hs_opts_t. + **/ +static hs_opts_t * +hs_opts_new(void) +{ + const config_mgr_t *mgr = get_hs_opts_mgr(); + hs_opts_t *r = config_new(mgr); + tor_assert(r); + config_init(mgr, r); + return r; +} + +/** + * Free an hs_opts_t. + **/ +#define hs_opts_free(opts) \ + config_free(get_hs_opts_mgr(), (opts)) + /** Using the given list of services, stage them into our global state. Every * service version are handled. This function can remove entries in the given * service_list. @@ -607,11 +662,13 @@ config_generic_service(const config_line_t *line, * the service to the given list and return 0. On error, nothing is added to * the list and a negative value is returned. */ static int -config_service(const config_line_t *line, const or_options_t *options, +config_service(config_line_t *line, const or_options_t *options, smartlist_t *service_list) { int ret; hs_service_t *service = NULL; + hs_opts_t *hs_opts = NULL; + char *msg = NULL; tor_assert(line); tor_assert(options); @@ -620,6 +677,22 @@ config_service(const config_line_t *line, const or_options_t *options, /* We have a new hidden service. */ service = hs_service_new(options); + /* Try to validate and parse the configuration lines into 'hs_opts' */ + hs_opts = hs_opts_new(); + ret = config_assign(get_hs_opts_mgr(), hs_opts, line, 0, &msg); + if (ret < 0) { + log_warn(LD_REND, "Can't parse configuration for onion service: %s", msg); + goto err; + } + tor_assert_nonfatal(msg == NULL); + validation_status_t vs = config_validate(get_hs_opts_mgr(), NULL, + hs_opts, &msg); + if (vs < 0) { + log_warn(LD_REND, "Bad configuration for onion service: %s", msg); + goto err; + } + tor_assert_nonfatal(msg == NULL); + /* We'll configure that service as a generic one and then pass it to a * specific function according to the configured version number. */ if (config_generic_service(line, options, service) < 0) { @@ -679,11 +752,14 @@ config_service(const config_line_t *line, const or_options_t *options, /* Passes, add it to the given list. */ smartlist_add(service_list, service); + hs_opts_free(hs_opts); return 0; err: hs_service_free(service); + hs_opts_free(hs_opts); + tor_free(msg); return -1; } @@ -780,3 +856,12 @@ hs_config_client_auth_all(const or_options_t *options, int validate_only) done: return ret; } + +/** + * Free all resources held by the hs_config.c module. + **/ +void +hs_config_free_all(void) +{ + config_mgr_free(hs_opts_mgr); +} diff --git a/src/feature/hs/hs_config.h b/src/feature/hs/hs_config.h index 5694cf1e9b..c60b4fbb5d 100644 --- a/src/feature/hs/hs_config.h +++ b/src/feature/hs/hs_config.h @@ -30,5 +30,6 @@ int hs_config_service_all(const or_options_t *options, int validate_only); int hs_config_client_auth_all(const or_options_t *options, int validate_only); -#endif /* !defined(TOR_HS_CONFIG_H) */ +void hs_config_free_all(void); +#endif /* !defined(TOR_HS_CONFIG_H) */ diff --git a/src/feature/hs/hs_options.inc b/src/feature/hs/hs_options.inc new file mode 100644 index 0000000000..c3566f4461 --- /dev/null +++ b/src/feature/hs/hs_options.inc @@ -0,0 +1,35 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2019, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file dirauth_options.inc + * @brief Declare configuration options for a single hidden service. + * + * Note that this options file behaves differently from most, since it + * is not used directly by the options manager. Instead, it is applied to + * a group of hidden service options starting with a HiddenServiceDir and + * extending up to the next HiddenServiceDir. + **/ + +/** Holds configuration for a single hidden service. */ +BEGIN_CONF_STRUCT(hs_opts_t) + +CONF_VAR(HiddenServiceDir, FILENAME, 0, NULL) +CONF_VAR(HiddenServiceDirGroupReadable, BOOL, 0, "0") +CONF_VAR(HiddenServicePort, STRING, 0, NULL) +CONF_VAR(HiddenServiceVersion, POSINT, 0, "3") +CONF_VAR(HiddenServiceAuthorizeClient, STRING, 0, NULL) +CONF_VAR(HiddenServiceAllowUnknownPorts, BOOL, 0, "0") +CONF_VAR(HiddenServiceMaxStreams, POSINT, 0, "0") +CONF_VAR(HiddenServiceMaxStreamsCloseCircuit, BOOL, 0, "0") +CONF_VAR(HiddenServiceNumIntroductionPoints, POSINT, 0, "3") +CONF_VAR(HiddenServiceExportCircuitID, STRING, 0, NULL) +CONF_VAR(HiddenServiceEnableIntroDoSDefense, BOOL, 0, "0") +CONF_VAR(HiddenServiceEnableIntroDoSRatePerSec, POSINT, 0, "25") +CONF_VAR(HiddenServiceEnableIntroDoSBurstPerSec, POSINT, 0, "200") +CONF_VAR(HiddenServiceOnionBalanceInstance, BOOL, 0, "0") + +END_CONF_STRUCT(hs_opts_t) diff --git a/src/feature/hs/hs_opts_st.h b/src/feature/hs/hs_opts_st.h new file mode 100644 index 0000000000..f6ee0f3cfa --- /dev/null +++ b/src/feature/hs/hs_opts_st.h @@ -0,0 +1,30 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2020, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * @file dirauth_options_st.h + * @brief Structure hs_opts_t to hold options for a single hidden service. + **/ + +#ifndef TOR_FEATURE_HS_HS_OPTS_ST_H +#define TOR_FEATURE_HS_HS_OPTS_ST_H + +#include "lib/conf/confdecl.h" +#define CONF_CONTEXT STRUCT +#include "feature/hs/hs_options.inc" +#undef CONF_CONTEXT + +/** + * An hs_opts_t holds the parsed options for a single HS configuration + * section. + * + * This name ends with 'opts' instead of 'options' to signal that it is not + * handled directly by the or_options_t configuration manager, but that + * first we partition the "HiddenService*" options by section. + **/ +typedef struct hs_opts_t hs_opts_t; + +#endif diff --git a/src/feature/hs/hs_service.c b/src/feature/hs/hs_service.c index 8b51b770a9..8c30b56b04 100644 --- a/src/feature/hs/hs_service.c +++ b/src/feature/hs/hs_service.c @@ -4112,6 +4112,7 @@ hs_service_free_all(void) { rend_service_free_all(); service_free_all(); + hs_config_free_all(); } #ifdef TOR_UNIT_TESTS diff --git a/src/feature/hs/include.am b/src/feature/hs/include.am index f83907c76b..af1dc65585 100644 --- a/src/feature/hs/include.am +++ b/src/feature/hs/include.am @@ -32,6 +32,8 @@ noinst_HEADERS += \ src/feature/hs/hs_ident.h \ src/feature/hs/hs_intropoint.h \ src/feature/hs/hs_ob.h \ + src/feature/hs/hs_opts_st.h \ + src/feature/hs/hs_options.inc \ src/feature/hs/hs_service.h \ src/feature/hs/hs_stats.h \ src/feature/hs/hsdir_index_st.h