1 /* Copyright (c) 2017, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
6 * \brief Implement hidden service configuration subsystem.
10 * This file has basically one main entry point: hs_config_service_all(). It
11 * takes the torrc options and configure hidden service from it. In validate
12 * mode, nothing is added to the global service list or keys are not generated
15 * A service is configured in two steps. It is first created using the tor
16 * options and then put in a staging list. It will stay there until
17 * hs_service_load_all_keys() is called. That function is responsible to
18 * load/generate the keys for the service in the staging list and if
19 * successful, transfert the service to the main global service list where
20 * at that point it is ready to be used.
22 * Configuration functions are per-version and there is a main generic one for
23 * every option that is common to all version (config_generic_service).
26 #define HS_CONFIG_PRIVATE
28 #include "hs_common.h"
29 #include "hs_config.h"
30 #include "hs_service.h"
31 #include "rendservice.h"
33 /* Using the given list of services, stage them into our global state. Every
34 * service version are handled. This function can remove entries in the given
37 * Staging a service means that we take all services in service_list and we
38 * put them in the staging list (global) which acts as a temporary list that
39 * is used by the service loading key process. In other words, staging a
40 * service puts it in a list to be considered when loading the keys and then
41 * moved to the main global list. */
43 stage_services(smartlist_t
*service_list
)
45 tor_assert(service_list
);
47 /* This is v2 specific. Trigger service pruning which will make sure the
48 * just configured services end up in the main global list. It should only
49 * be done in non validation mode because v2 subsystem handles service
50 * object differently. */
51 rend_service_prune_list();
53 /* Cleanup v2 service from the list, we don't need those object anymore
54 * because we validated them all against the others and we want to stage
55 * only >= v3 service. And remember, v2 has a different object type which is
56 * shadow copied from an hs_service_t type. */
57 SMARTLIST_FOREACH_BEGIN(service_list
, hs_service_t
*, s
) {
58 if (s
->config
.version
== HS_VERSION_TWO
) {
59 SMARTLIST_DEL_CURRENT(service_list
, s
);
62 } SMARTLIST_FOREACH_END(s
);
64 /* This is >= v3 specific. Using the newly configured service list, stage
65 * them into our global state. Every object ownership is lost after. */
66 hs_service_stage_services(service_list
);
69 /* Validate the given service against all service in the given list. If the
70 * service is ephemeral, this function ignores it. Services with the same
71 * directory path aren't allowed and will return an error. If a duplicate is
72 * found, 1 is returned else 0 if none found. */
74 service_is_duplicate_in_list(const smartlist_t
*service_list
,
75 const hs_service_t
*service
)
79 tor_assert(service_list
);
82 /* Ephemeral service don't have a directory configured so no need to check
83 * for a service in the list having the same path. */
84 if (service
->config
.is_ephemeral
) {
88 /* XXX: Validate if we have any service that has the given service dir path.
89 * This has two problems:
91 * a) It's O(n^2), but the same comment from the bottom of
92 * rend_config_services() should apply.
94 * b) We only compare directory paths as strings, so we can't
95 * detect two distinct paths that specify the same directory
96 * (which can arise from symlinks, case-insensitivity, bind
99 * It also can't detect that two separate Tor instances are trying
100 * to use the same HiddenServiceDir; for that, we would need a
101 * lock file. But this is enough to detect a simple mistake that
102 * at least one person has actually made. */
103 SMARTLIST_FOREACH_BEGIN(service_list
, const hs_service_t
*, s
) {
104 if (!strcmp(s
->config
.directory_path
, service
->config
.directory_path
)) {
105 log_warn(LD_REND
, "Another hidden service is already configured "
107 escaped(service
->config
.directory_path
));
111 } SMARTLIST_FOREACH_END(s
);
117 /* Helper function: Given an configuration option name, its value, a minimum
118 * min and a maxium max, parse the value as a uint64_t. On success, ok is set
119 * to 1 and ret is the parsed value. On error, ok is set to 0 and ret must be
120 * ignored. This function logs both on error and success. */
122 helper_parse_uint64(const char *opt
, const char *value
, uint64_t min
,
123 uint64_t max
, int *ok
)
132 ret
= tor_parse_uint64(value
, 10, min
, max
, ok
, NULL
);
134 log_warn(LD_CONFIG
, "%s must be between %" PRIu64
" and %"PRIu64
136 opt
, min
, max
, value
);
139 log_info(LD_CONFIG
, "%s was parsed to %" PRIu64
, opt
, ret
);
144 /* Return true iff the given options starting at line_ for a hidden service
145 * contains at least one invalid option. Each hidden service option don't
146 * apply to all versions so this function can find out. The line_ MUST start
147 * right after the HiddenServiceDir line of this service.
149 * This is mainly for usability so we can inform the user of any invalid
150 * option for the hidden service version instead of silently ignoring. */
152 config_has_invalid_options(const config_line_t
*line_
,
153 const hs_service_t
*service
)
156 const char **optlist
;
157 const config_line_t
*line
;
160 tor_assert(service
->config
.version
<= HS_VERSION_MAX
);
162 /* List of options that a v3 service doesn't support thus must exclude from
163 * its configuration. */
164 const char *opts_exclude_v3
[] = {
165 "HiddenServiceAuthorizeClient",
166 NULL
/* End marker. */
169 /* Defining the size explicitly allows us to take advantage of the compiler
170 * which warns us if we ever bump the max version but forget to grow this
171 * array. The plus one is because we have a version 0 :). */
174 } exclude_lists
[HS_VERSION_MAX
+ 1] = {
178 { opts_exclude_v3
}, /* v3. */
181 optlist
= exclude_lists
[service
->config
.version
].list
;
182 if (optlist
== NULL
) {
183 /* No exclude options to look at for this version. */
186 for (int i
= 0; optlist
[i
]; i
++) {
187 const char *opt
= optlist
[i
];
188 for (line
= line_
; line
; line
= line
->next
) {
189 if (!strcasecmp(line
->key
, "HiddenServiceDir")) {
190 /* We just hit the next hidden service, stop right now. */
193 if (!strcasecmp(line
->key
, opt
)) {
194 log_warn(LD_CONFIG
, "Hidden service option %s is incompatible with "
195 "version %" PRIu32
" of service in %s",
196 opt
, service
->config
.version
,
197 service
->config
.directory_path
);
199 /* Continue the loop so we can find all possible options. */
208 /* Validate service configuration. This is used when loading the configuration
209 * and once we've setup a service object, it's config object is passed to this
210 * function for further validation. This does not validate service key
211 * material. Return 0 if valid else -1 if invalid. */
213 config_validate_service(const hs_service_config_t
*config
)
217 /* Amount of ports validation. */
218 if (!config
->ports
|| smartlist_len(config
->ports
) == 0) {
219 log_warn(LD_CONFIG
, "Hidden service (%s) with no ports configured.",
220 escaped(config
->directory_path
));
230 /* Configuration funcion for a version 3 service. The line_ must be pointing
231 * to the directive directly after a HiddenServiceDir. That way, when hitting
232 * the next HiddenServiceDir line or reaching the end of the list of lines, we
233 * know that we have to stop looking for more options. The given service
234 * object must be already allocated and passed through
235 * config_generic_service() prior to calling this function.
237 * Return 0 on success else a negative value. */
239 config_service_v3(const config_line_t
*line_
,
240 hs_service_config_t
*config
)
243 const char *dup_opt_seen
= NULL
;
244 const config_line_t
*line
;
248 for (line
= line_
; line
; line
= line
->next
) {
250 if (!strcasecmp(line
->key
, "HiddenServiceDir")) {
251 /* We just hit the next hidden service, stop right now. */
254 /* Number of introduction points. */
255 if (!strcasecmp(line
->key
, "HiddenServiceNumIntroductionPoints")) {
256 config
->num_intro_points
=
257 (unsigned int) helper_parse_uint64(line
->key
, line
->value
,
258 NUM_INTRO_POINTS_DEFAULT
,
259 HS_CONFIG_V3_MAX_INTRO_POINTS
,
261 if (!ok
|| have_num_ip
) {
263 dup_opt_seen
= line
->key
;
271 /* We do not load the key material for the service at this stage. This is
272 * done later once tor can confirm that it is in a running state. */
274 /* We are about to return a fully configured service so do one last pass of
275 * validation at it. */
276 if (config_validate_service(config
) < 0) {
283 log_warn(LD_CONFIG
, "Duplicate directive %s.", dup_opt_seen
);
288 /* Configure a service using the given options in line_ and options. This is
289 * called for any service regardless of its version which means that all
290 * directives in this function are generic to any service version. This
291 * function will also check the validity of the service directory path.
293 * The line_ must be pointing to the directive directly after a
294 * HiddenServiceDir. That way, when hitting the next HiddenServiceDir line or
295 * reaching the end of the list of lines, we know that we have to stop looking
298 * Return 0 on success else -1. */
300 config_generic_service(const config_line_t
*line_
,
301 const or_options_t
*options
,
302 hs_service_t
*service
)
305 const config_line_t
*line
;
306 hs_service_config_t
*config
;
307 /* If this is set, we've seen a duplicate of this option. Keep the string
308 * so we can log the directive. */
309 const char *dup_opt_seen
= NULL
;
310 /* These variables will tell us if we ever have duplicate. */
311 int have_version
= 0, have_allow_unknown_ports
= 0;
312 int have_dir_group_read
= 0, have_max_streams
= 0;
313 int have_max_streams_close
= 0;
319 /* Makes thing easier. */
320 config
= &service
->config
;
322 /* The first line starts with HiddenServiceDir so we consider what's next is
323 * the configuration of the service. */
324 for (line
= line_
; line
; line
= line
->next
) {
327 /* This indicate that we have a new service to configure. */
328 if (!strcasecmp(line
->key
, "HiddenServiceDir")) {
329 /* This function only configures one service at a time so if we've
330 * already seen one, stop right now. */
334 /* Ok, we've seen one and we are about to configure it. */
336 config
->directory_path
= tor_strdup(line
->value
);
337 log_info(LD_CONFIG
, "HiddenServiceDir=%s. Configuring...",
338 escaped(config
->directory_path
));
341 if (BUG(!dir_seen
)) {
344 /* Version of the service. */
345 if (!strcasecmp(line
->key
, "HiddenServiceVersion")) {
346 service
->config
.version
=
347 (uint32_t) helper_parse_uint64(line
->key
, line
->value
, HS_VERSION_MIN
,
348 HS_VERSION_MAX
, &ok
);
349 if (!ok
|| have_version
) {
351 dup_opt_seen
= line
->key
;
358 if (!strcasecmp(line
->key
, "HiddenServicePort")) {
359 char *err_msg
= NULL
;
360 /* XXX: Can we rename this? */
361 rend_service_port_config_t
*portcfg
=
362 rend_service_parse_port_config(line
->value
, " ", &err_msg
);
365 log_warn(LD_CONFIG
, "%s", err_msg
);
370 tor_assert(!err_msg
);
371 smartlist_add(config
->ports
, portcfg
);
372 log_info(LD_CONFIG
, "HiddenServicePort=%s for %s",
373 line
->value
, escaped(config
->directory_path
));
376 /* Do we allow unknown ports. */
377 if (!strcasecmp(line
->key
, "HiddenServiceAllowUnknownPorts")) {
378 config
->allow_unknown_ports
=
379 (unsigned int) helper_parse_uint64(line
->key
, line
->value
, 0, 1, &ok
);
380 if (!ok
|| have_allow_unknown_ports
) {
381 if (have_allow_unknown_ports
)
382 dup_opt_seen
= line
->key
;
385 have_allow_unknown_ports
= 1;
388 /* Directory group readable. */
389 if (!strcasecmp(line
->key
, "HiddenServiceDirGroupReadable")) {
390 config
->dir_group_readable
=
391 (unsigned int) helper_parse_uint64(line
->key
, line
->value
, 0, 1, &ok
);
392 if (!ok
|| have_dir_group_read
) {
393 if (have_dir_group_read
)
394 dup_opt_seen
= line
->key
;
397 have_dir_group_read
= 1;
400 /* Maximum streams per circuit. */
401 if (!strcasecmp(line
->key
, "HiddenServiceMaxStreams")) {
402 config
->max_streams_per_rdv_circuit
=
403 helper_parse_uint64(line
->key
, line
->value
, 0,
404 HS_CONFIG_MAX_STREAMS_PER_RDV_CIRCUIT
, &ok
);
405 if (!ok
|| have_max_streams
) {
406 if (have_max_streams
)
407 dup_opt_seen
= line
->key
;
410 have_max_streams
= 1;
413 /* Maximum amount of streams before we close the circuit. */
414 if (!strcasecmp(line
->key
, "HiddenServiceMaxStreamsCloseCircuit")) {
415 config
->max_streams_close_circuit
=
416 (unsigned int) helper_parse_uint64(line
->key
, line
->value
, 0, 1, &ok
);
417 if (!ok
|| have_max_streams_close
) {
418 if (have_max_streams_close
)
419 dup_opt_seen
= line
->key
;
422 have_max_streams_close
= 1;
427 /* Check if we are configured in non anonymous mode meaning every service
428 * becomes a single onion service. */
429 if (rend_service_non_anonymous_mode_enabled(options
)) {
430 config
->is_single_onion
= 1;
431 /* We will add support for IPv6-only v3 single onion services in a future
432 * Tor version. This won't catch "ReachableAddresses reject *4", but that
433 * option doesn't work anyway. */
434 if (options
->ClientUseIPv4
== 0 && config
->version
== HS_VERSION_THREE
) {
435 log_warn(LD_CONFIG
, "IPv6-only v3 single onion services are not "
436 "supported. Set HiddenServiceSingleHopMode 0 and "
437 "HiddenServiceNonAnonymousMode 0, or set ClientUseIPv4 1.");
446 log_warn(LD_CONFIG
, "Duplicate directive %s.", dup_opt_seen
);
451 /* Configure a service using the given line and options. This function will
452 * call the corresponding configuration function for a specific service
453 * version and validate the service against the other ones. On success, add
454 * the service to the given list and return 0. On error, nothing is added to
455 * the list and a negative value is returned. */
457 config_service(const config_line_t
*line
, const or_options_t
*options
,
458 smartlist_t
*service_list
)
461 hs_service_t
*service
= NULL
;
465 tor_assert(service_list
);
467 /* We have a new hidden service. */
468 service
= hs_service_new(options
);
469 /* We'll configure that service as a generic one and then pass it to a
470 * specific function according to the configured version number. */
471 if (config_generic_service(line
, options
, service
) < 0) {
474 tor_assert(service
->config
.version
<= HS_VERSION_MAX
);
475 /* Before we configure the service on a per-version basis, we'll make
476 * sure that this set of options for a service are valid that is for
477 * instance an option only for v2 is not used for v3. */
478 if (config_has_invalid_options(line
->next
, service
)) {
481 /* Check permission on service directory that was just parsed. And this must
482 * be done regardless of the service version. Do not ask for the directory
483 * to be created, this is done when the keys are loaded because we could be
484 * in validation mode right now. */
485 if (hs_check_service_private_dir(options
->User
,
486 service
->config
.directory_path
,
487 service
->config
.dir_group_readable
,
491 /* Different functions are in charge of specific options for a version. We
492 * start just after the service directory line so once we hit another
493 * directory line, the function knows that it has to stop parsing. */
494 switch (service
->config
.version
) {
496 ret
= rend_config_service(line
->next
, options
, &service
->config
);
498 case HS_VERSION_THREE
:
499 ret
= config_service_v3(line
->next
, &service
->config
);
502 /* We do validate before if we support the parsed version. */
503 tor_assert_nonfatal_unreached();
509 /* We'll check if this service can be kept depending on the others
510 * configured previously. */
511 if (service_is_duplicate_in_list(service_list
, service
)) {
514 /* Passes, add it to the given list. */
515 smartlist_add(service_list
, service
);
519 hs_service_free(service
);
523 /* From a set of <b>options</b>, setup every hidden service found. Return 0 on
524 * success or -1 on failure. If <b>validate_only</b> is set, parse, warn and
525 * return as normal, but don't actually change the configured services. */
527 hs_config_service_all(const or_options_t
*options
, int validate_only
)
529 int dir_option_seen
= 0, ret
= -1;
530 const config_line_t
*line
;
531 smartlist_t
*new_service_list
= NULL
;
535 /* Newly configured service are put in that list which is then used for
536 * validation and staging for >= v3. */
537 new_service_list
= smartlist_new();
539 for (line
= options
->RendConfigLines
; line
; line
= line
->next
) {
540 /* Ignore all directives that aren't the start of a service. */
541 if (strcasecmp(line
->key
, "HiddenServiceDir")) {
542 if (!dir_option_seen
) {
543 log_warn(LD_CONFIG
, "%s with no preceding HiddenServiceDir directive",
549 /* Flag that we've seen a directory directive and we'll use it to make
550 * sure that the torrc options ordering is actually valid. */
553 /* Try to configure this service now. On success, it will be added to the
554 * list and validated against the service in that same list. */
555 if (config_service(line
, options
, new_service_list
) < 0) {
560 /* In non validation mode, we'll stage those services we just successfully
561 * configured. Service ownership is transfered from the list to the global
562 * state. If any service is invalid, it will be removed from the list and
563 * freed. All versions are handled in that function. */
564 if (!validate_only
) {
565 stage_services(new_service_list
);
567 /* We've just validated that we were able to build a clean working list of
568 * services. We don't need those objects anymore. */
569 SMARTLIST_FOREACH(new_service_list
, hs_service_t
*, s
,
571 /* For the v2 subsystem, the configuration function adds the service
572 * object to the staging list and it is transferred in the main list
573 * through the prunning process. In validation mode, we thus have to purge
574 * the staging list so it's not kept in memory as valid service. */
575 rend_service_free_staging_list();
578 /* Success. Note that the service list has no ownership of its content. */
583 SMARTLIST_FOREACH(new_service_list
, hs_service_t
*, s
, hs_service_free(s
));
586 smartlist_free(new_service_list
);
587 /* Tor main should call the free all function on error. */