Refactor Single Onion code to improve consistency

* Check consistency between the two single onion torrc options
* Use the more relevant option each time we check for single onion mode
* Clarify log messages
* Clarify comments
* Otherwise, no behaviour change
This commit is contained in:
teor 2016-09-13 17:20:46 +10:00 committed by Nick Mathewson
parent f686fa2ee6
commit 365ca3ca0f
7 changed files with 96 additions and 78 deletions

View File

@ -104,7 +104,7 @@ circuit_build_times_disabled(void)
int config_disabled = !options->LearnCircuitBuildTimeout;
int dirauth_disabled = options->AuthoritativeDir;
int state_disabled = did_last_state_file_write_fail() ? 1 : 0;
/* LearnCircuitBuildTimeout and Tor2webMode/OnionServiceSingleHopMode are
/* LearnCircuitBuildTimeout and Tor2web/Single Onion Services are
* incompatible in two ways:
*
* - LearnCircuitBuildTimeout results in a low CBT, which

View File

@ -1730,17 +1730,17 @@ options_act(const or_options_t *old_options)
* poisoning code checks for existing keys, and refuses to modify their
* directories. */
/* If we use the insecure OnionServiceSingleHopMode, make sure we poison any
/* If we use non-anonymous single onion services, make sure we poison any
new hidden service directories, so that we never accidentally launch the
non-anonymous hidden services thinking they are anonymous. */
if (running_tor && rend_service_allow_non_anonymous_connection(options)) {
if (running_tor && rend_service_non_anonymous_mode_enabled(options)) {
if (options->RendConfigLines && !num_rend_services()) {
log_warn(LD_BUG,"Error: hidden services configured, but not parsed.");
return -1;
}
if (rend_service_poison_new_single_onion_dirs(NULL) < 0) {
log_warn(LD_GENERAL,"Failed to mark new hidden services as Single "
"Onion.");
log_warn(LD_GENERAL,"Failed to mark new hidden services as non-anonymous"
".");
return -1;
}
}
@ -2818,63 +2818,61 @@ warn_about_relative_paths(or_options_t *options)
}
}
/* Validate options related to OnionServiceSingleHopMode.
* Modifies some options that are incompatible with OnionServiceSingleHopMode.
/* Validate options related to single onion services.
* Modifies some options that are incompatible with single onion services.
* On failure returns -1, and sets *msg to an error string.
* Returns 0 on success. */
STATIC int
options_validate_single_onion(or_options_t *options, char **msg)
{
/* You must set OnionServiceNonAnonymousMode to 1 to use
* OnionServiceSingleHopMode */
/* The two single onion service options must have matching values. */
if (options->OnionServiceSingleHopMode &&
!rend_service_non_anonymous_mode_enabled(options)) {
!options->OnionServiceNonAnonymousMode) {
REJECT("OnionServiceSingleHopMode does not provide any server anonymity. "
"It must be used with OnionServiceNonAnonymousMode set to 1.");
}
/* If you have OnionServiceNonAnonymousMode set, you must use
* OnionServiceSingleHopMode. */
if (rend_service_non_anonymous_mode_enabled(options) &&
if (options->OnionServiceNonAnonymousMode &&
!options->OnionServiceSingleHopMode) {
REJECT("OnionServiceNonAnonymousMode does not provide any server "
"anonymity. It must be used with OnionServiceSingleHopMode set to "
"1.");
}
/* Now that we've checked that the two options are consistent, we can safely
* call the rend_service_* functions that abstract these options. */
/* If you run an anonymous client with an active Single Onion service, the
* client loses anonymity. */
const int client_port_set = (options->SocksPort_set ||
options->TransPort_set ||
options->NATDPort_set ||
options->DNSPort_set);
if (options->OnionServiceSingleHopMode && client_port_set &&
if (rend_service_non_anonymous_mode_enabled(options) && client_port_set &&
!options->Tor2webMode) {
REJECT("OnionServiceSingleHopMode is incompatible with using Tor as an "
REJECT("OnionServiceNonAnonymousMode is incompatible with using Tor as an "
"anonymous client. Please set Socks/Trans/NATD/DNSPort to 0, or "
"OnionServiceSingleHopMode to 0, or use the non-anonymous "
"OnionServiceNonAnonymousMode to 0, or use the non-anonymous "
"Tor2webMode.");
}
/* If you run a hidden service in non-anonymous mode, the hidden service
* loses anonymity, even if SOCKSPort / Tor2web mode isn't used. */
if (!options->OnionServiceSingleHopMode && options->RendConfigLines
&& options->Tor2webMode) {
if (!rend_service_non_anonymous_mode_enabled(options) &&
options->RendConfigLines && options->Tor2webMode) {
REJECT("Non-anonymous (Tor2web) mode is incompatible with using Tor as a "
"hidden service. Please remove all HiddenServiceDir lines, or use "
"a version of tor compiled without --enable-tor2web-mode, or use "
"the non-anonymous OnionServiceSingleHopMode.");
" OnionServiceNonAnonymousMode.");
}
if (options->OnionServiceSingleHopMode
if (rend_service_allow_non_anonymous_connection(options)
&& options->UseEntryGuards) {
/* Single Onion services do not (and should not) use entry guards
* in any meaningful way. Further, Single Onions causes the hidden
* service code to do things which break the path bias
/* Single Onion services only use entry guards when uploading descriptors,
* all other connections are one-hop. Further, Single Onions causes the
* hidden service code to do things which break the path bias
* detector, and it's far easier to turn off entry guards (and
* thus the path bias detector with it) than to figure out how to
* make a piece of code which cannot possibly help Single Onions,
* compatible with OnionServiceSingleHopMode.
* make path bias compatible with single onions.
*/
log_notice(LD_CONFIG,
"OnionServiceSingleHopMode is enabled; disabling "
@ -2882,12 +2880,12 @@ options_validate_single_onion(or_options_t *options, char **msg)
options->UseEntryGuards = 0;
}
/* Check if existing hidden service keys were created with a different
* setting of OnionServiceNonAnonymousMode, and refuse to launch if they
/* Check if existing hidden service keys were created in a different
* single onion service mode, and refuse to launch if they
* have. We'll poison new keys in options_act() just before we create them.
*/
if (rend_service_list_verify_single_onion_poison(NULL, options) < 0) {
log_warn(LD_GENERAL, "We are configured with OnionServiceSingleHopMode "
log_warn(LD_GENERAL, "We are configured with OnionServiceNonAnonymousMode "
"%d, but one or more hidden service keys were created in %s "
"mode. This is not allowed.",
rend_service_non_anonymous_mode_enabled(options) ? 1 : 0,
@ -3427,7 +3425,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
if (!(options->UseEntryGuards) &&
(options->RendConfigLines != NULL) &&
!rend_service_non_anonymous_mode_enabled(options)) {
!rend_service_allow_non_anonymous_connection(options)) {
log_warn(LD_CONFIG,
"UseEntryGuards is disabled, but you have configured one or more "
"hidden services on this Tor instance. Your hidden services "
@ -3450,15 +3448,15 @@ options_validate(or_options_t *old_options, or_options_t *options,
return -1;
}
/* OnionServiceSingleHopMode: one hop between the onion service server and
* intro and rendezvous points */
if (options->OnionServiceSingleHopMode) {
/* Single Onion Services: non-anonymous hidden services */
if (rend_service_non_anonymous_mode_enabled(options)) {
log_warn(LD_CONFIG,
"OnionServiceSingleHopMode is set. Every hidden service on this "
"tor instance is NON-ANONYMOUS. If OnionServiceSingleHopMode is "
"disabled, Tor will refuse to launch hidden services from the "
"same directories, to protect against config errors. This "
"setting is for experimental use only.");
"OnionServiceNonAnonymousNode is set. Every hidden service on "
"this tor instance is NON-ANONYMOUS. If "
"the OnionServiceNonAnonymousMode option is changed, Tor will "
"refuse to launch hidden services from the same directories, to "
"protect your anonymity against config errors. This setting is "
"for experimental use only.");
}
if (!options->LearnCircuitBuildTimeout && options->CircuitBuildTimeout &&

View File

@ -4249,7 +4249,7 @@ handle_control_add_onion(control_connection_t *conn,
int max_streams = 0;
int max_streams_close_circuit = 0;
rend_auth_type_t auth_type = REND_NO_AUTH;
/* Default to anonymous if no flag is given */
/* Default to adding an anonymous hidden service if no flag is given */
int non_anonymous = 0;
for (size_t i = 1; i < arg_len; i++) {
static const char *port_prefix = "Port=";
@ -4288,10 +4288,9 @@ handle_control_add_onion(control_connection_t *conn,
* exceeded.
* * 'BasicAuth' - Client authorization using the 'basic' method.
* * 'NonAnonymous' - Add a non-anonymous Single Onion Service. If this
* flag is present, OnionServiceSingleHopMode and
* OnionServiceNonAnonymousMode must both be 1. If
* this flag is absent, both these options must be
* 0.
* flag is present, tor must be in non-anonymous
* hidden service mode. If this flag is absent,
* tor must be in anonymous hidden service mode.
*/
static const char *discard_flag = "DiscardPK";
static const char *detach_flag = "Detach";
@ -4388,15 +4387,17 @@ handle_control_add_onion(control_connection_t *conn,
smartlist_len(auth_clients) > 16)) {
connection_printf_to_buf(conn, "512 Too many auth clients\r\n");
goto out;
} else if (non_anonymous != rend_service_allow_non_anonymous_connection(
} else if (non_anonymous != rend_service_non_anonymous_mode_enabled(
get_options())) {
/* If we failed, and non-anonymous is set, Tor must be in anonymous mode.
/* If we failed, and the non-anonymous flag is set, Tor must be in
* anonymous hidden service mode.
* The error message changes based on the current Tor config:
* 512 Tor is in anonymous onion mode
* 512 Tor is in non-anonymous onion mode
* 512 Tor is in anonymous hidden service mode
* 512 Tor is in non-anonymous hidden service mode
* (I've deliberately written them out in full here to aid searchability.)
*/
connection_printf_to_buf(conn, "512 Tor is in %sanonymous onion mode\r\n",
connection_printf_to_buf(conn, "512 Tor is in %sanonymous hidden service "
"mode\r\n",
non_anonymous ? "" : "non-");
goto out;
}

View File

@ -3706,8 +3706,7 @@ typedef struct {
* rendezvous points. (Onion service descriptors are still posted using
* 3-hop paths, to avoid onion service directories blocking the service.)
* This option makes every hidden service instance hosted by
* this tor instance a Single Onion Service. One-hop circuits make Single
* Onion servers easily locatable, but clients remain location-anonymous.
* this tor instance a Single Onion Service.
* OnionServiceSingleHopMode requires OnionServiceNonAnonymousMode to be set
* to 1.
* Use rend_service_allow_non_anonymous_connection() or
@ -3716,8 +3715,8 @@ typedef struct {
int OnionServiceSingleHopMode;
/* Makes hidden service clients and servers non-anonymous on this tor
* instance. Allows the non-anonymous OnionServiceSingleHopMode. Enables
* direct connections in the hidden service protocol.
* Use rend_service_non_anonymous_mode() instead of using this option
* non-anonymous behaviour in the hidden service protocol.
* Use rend_service_non_anonymous_mode_enabled() instead of using this option
* directly.
*/
int OnionServiceNonAnonymousMode;

View File

@ -1097,11 +1097,11 @@ rend_non_anonymous_mode_enabled(const or_options_t *options)
/* Make sure that tor only builds one-hop circuits when they would not
* compromise user anonymity.
*
* One-hop circuits are permitted in Tor2webMode or OnionServiceSingleHopMode.
* One-hop circuits are permitted in Tor2web or Single Onion modes.
*
* Tor2webMode and OnionServiceSingleHopMode are also allowed to make
* multi-hop circuits. For example, single onion HSDir circuits are 3-hop to
* prevent denial of service.
* Tor2web or Single Onion modes are also allowed to make multi-hop circuits.
* For example, single onion HSDir circuits are 3-hop to prevent denial of
* service.
*/
void
assert_circ_anonymity_ok(origin_circuit_t *circ,

View File

@ -1025,10 +1025,10 @@ rend_service_private_key_exists(const rend_service_t *service)
/** Check the single onion service poison state of all existing hidden service
* directories:
* - If each service is poisoned, and we are in OnionServiceSingleHopMode,
* - If each service is poisoned, and we are in Single Onion Mode,
* return 0,
* - If each service is not poisoned, and we are not in Single Onion Mode,
* return 0,
* - If each service is not poisoned, and we are not in
* OnionServiceSingleHopMode, return 0,
* - Otherwise, the poison state is invalid, and a service that was created in
* one mode is being used in the other, return -1.
* Hidden service directories without keys are not checked for consistency.
@ -1054,7 +1054,7 @@ rend_service_list_verify_single_onion_poison(const smartlist_t *service_list,
int consistent = 1;
SMARTLIST_FOREACH_BEGIN(s_list, const rend_service_t *, s) {
if (service_is_single_onion_poisoned(s) !=
rend_service_allow_non_anonymous_connection(options) &&
rend_service_non_anonymous_mode_enabled(options) &&
rend_service_private_key_exists(s)) {
consistent = 0;
}
@ -1063,25 +1063,25 @@ rend_service_list_verify_single_onion_poison(const smartlist_t *service_list,
return consistent ? 0 : -1;
}
/*** Helper for rend_service_poison_new_single_onion_dirs(). When in single
* onion mode, add a file to this hidden service directory that marks it as a
* single onion hidden service. Returns 0 when a directory is successfully
* poisoned, or if it is already poisoned. Returns -1 on a failure to read
* the directory or write the poison file, or if there is an existing private
* key file in the directory. (The service should have been poisoned when the
* key was created.) */
/*** Helper for rend_service_poison_new_single_onion_dirs(). Add a file to
* this hidden service directory that marks it as a single onion service.
* Tor must be in single onion mode before calling this function.
* Returns 0 when a directory is successfully poisoned, or if it is already
* poisoned. Returns -1 on a failure to read the directory or write the poison
* file, or if there is an existing private key file in the directory. (The
* service should have been poisoned when the key was created.) */
static int
poison_new_single_onion_hidden_service_dir(const rend_service_t *service)
{
/* We must only poison directories if we're in Single Onion mode */
tor_assert(rend_service_allow_non_anonymous_connection(get_options()));
tor_assert(rend_service_non_anonymous_mode_enabled(get_options()));
int fd;
int retval = -1;
char *poison_fname = NULL;
if (!service->directory) {
log_info(LD_REND, "Ephemeral HS started in OnionServiceSingleHopMode.");
log_info(LD_REND, "Ephemeral HS started in non-anonymous mode.");
return 0;
}
@ -1126,7 +1126,7 @@ poison_new_single_onion_hidden_service_dir(const rend_service_t *service)
return retval;
}
/** We just got launched in OnionServiceSingleHopMode. That's a non-anoymous
/** We just got launched in Single Onion Mode. That's a non-anoymous
* mode for hidden services; hence we should mark all new hidden service
* directories appropriately so that they are never launched as
* location-private hidden services again. (New directories don't have private
@ -1138,7 +1138,7 @@ int
rend_service_poison_new_single_onion_dirs(const smartlist_t *service_list)
{
/* We must only poison directories if we're in Single Onion mode */
tor_assert(rend_service_allow_non_anonymous_connection(get_options()));
tor_assert(rend_service_non_anonymous_mode_enabled(get_options()));
const smartlist_t *s_list;
/* If no special service list is provided, then just use the global one. */
@ -4179,12 +4179,25 @@ rend_service_set_connection_addr_port(edge_connection_t *conn,
return -2;
}
/* Are OnionServiceSingleHopMode and OnionServiceNonAnonymousMode consistent?
*/
static int
rend_service_non_anonymous_mode_consistent(const or_options_t *options)
{
/* !! is used to make these options boolean */
return (!! options->OnionServiceSingleHopMode ==
!! options->OnionServiceNonAnonymousMode);
}
/* Do the options allow onion services to make direct (non-anonymous)
* connections to introduction or rendezvous points?
* Must only be called after options_validate_single_onion() has successfully
* checked onion service option consistency.
* Returns true if tor is in OnionServiceSingleHopMode. */
int
rend_service_allow_non_anonymous_connection(const or_options_t *options)
{
tor_assert(rend_service_non_anonymous_mode_consistent(options));
return options->OnionServiceSingleHopMode ? 1 : 0;
}
@ -4192,17 +4205,24 @@ rend_service_allow_non_anonymous_connection(const or_options_t *options)
* service?
* Single Onion Services prioritise availability over hiding their
* startup time, as their IP address is publicly discoverable anyway.
* Returns true if tor is in OnionServiceSingleHopMode. */
* Must only be called after options_validate_single_onion() has successfully
* checked onion service option consistency.
* Returns true if tor is in non-anonymous hidden service mode. */
int
rend_service_reveal_startup_time(const or_options_t *options)
{
return rend_service_allow_non_anonymous_connection(options);
tor_assert(rend_service_non_anonymous_mode_consistent(options));
return rend_service_non_anonymous_mode_enabled(options);
}
/* Is non-anonymous mode enabled using the OnionServiceNonAnonymousMode
* config option? */
* config option?
* Must only be called after options_validate_single_onion() has successfully
* checked onion service option consistency.
*/
int
rend_service_non_anonymous_mode_enabled(const or_options_t *options)
{
tor_assert(rend_service_non_anonymous_mode_consistent(options));
return options->OnionServiceNonAnonymousMode ? 1 : 0;
}

View File

@ -2813,10 +2813,10 @@ test_options_validate__single_onion(void *ignored)
);
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "OnionServiceSingleHopMode is incompatible with using "
"Tor as an anonymous client. Please set Socks/Trans/NATD/DNSPort "
"to 0, or OnionServiceSingleHopMode to 0, or use the "
"non-anonymous Tor2webMode.");
tt_str_op(msg, OP_EQ, "OnionServiceNonAnonymousMode is incompatible with "
"using Tor as an anonymous client. Please set "
"Socks/Trans/NATD/DNSPort to 0, or OnionServiceNonAnonymousMode "
"to 0, or use the non-anonymous Tor2webMode.");
tor_free(msg);
free_options_test_data(tdata);