commit 365ca3ca0f5d9d391a2156436d1a7c620906e23a Author: teor teor2345@gmail.com Date: Tue Sep 13 17:20:46 2016 +1000
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 --- src/or/circuitstats.c | 2 +- src/or/config.c | 72 ++++++++++++++++++++++++------------------------- src/or/control.c | 21 ++++++++------- src/or/or.h | 7 +++-- src/or/rendcommon.c | 8 +++--- src/or/rendservice.c | 56 +++++++++++++++++++++++++------------- src/test/test_options.c | 8 +++--- 7 files changed, 96 insertions(+), 78 deletions(-)
diff --git a/src/or/circuitstats.c b/src/or/circuitstats.c index 296f852..3d64113 100644 --- a/src/or/circuitstats.c +++ b/src/or/circuitstats.c @@ -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 diff --git a/src/or/config.c b/src/or/config.c index 48f1ab9..6d168c4 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -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 && diff --git a/src/or/control.c b/src/or/control.c index 8f3909b..8962075 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -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; } diff --git a/src/or/or.h b/src/or/or.h index 07f94b7..849cd4c 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -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; diff --git a/src/or/rendcommon.c b/src/or/rendcommon.c index 12dd0f4..083efd0 100644 --- a/src/or/rendcommon.c +++ b/src/or/rendcommon.c @@ -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, diff --git a/src/or/rendservice.c b/src/or/rendservice.c index 04894dd..9400b59 100644 --- a/src/or/rendservice.c +++ b/src/or/rendservice.c @@ -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; } diff --git a/src/test/test_options.c b/src/test/test_options.c index cd1821a..f01e137 100644 --- a/src/test/test_options.c +++ b/src/test/test_options.c @@ -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);