diff options
Diffstat (limited to 'src/or')
33 files changed, 1186 insertions, 326 deletions
diff --git a/src/or/buffers.c b/src/or/buffers.c index 3198572392..c08da63a0d 100644 --- a/src/or/buffers.c +++ b/src/or/buffers.c @@ -166,9 +166,12 @@ chunk_grow(chunk_t *chunk, size_t sz) /** Return the allocation size we'd like to use to hold <b>target</b> * bytes. */ -static inline size_t +STATIC size_t preferred_chunk_size(size_t target) { + tor_assert(target <= SIZE_T_CEILING - CHUNK_HEADER_LEN); + if (CHUNK_ALLOC_SIZE(target) >= MAX_CHUNK_ALLOC) + return CHUNK_ALLOC_SIZE(target); size_t sz = MIN_CHUNK_ALLOC; while (CHUNK_SIZE_WITH_ALLOC(sz) < target) { sz <<= 1; diff --git a/src/or/buffers.h b/src/or/buffers.h index 275867c70a..52b21d5885 100644 --- a/src/or/buffers.h +++ b/src/or/buffers.h @@ -65,6 +65,7 @@ void assert_buf_ok(buf_t *buf); STATIC int buf_find_string_offset(const buf_t *buf, const char *s, size_t n); STATIC void buf_pullup(buf_t *buf, size_t bytes); void buf_get_first_chunk_data(const buf_t *buf, const char **cp, size_t *sz); +STATIC size_t preferred_chunk_size(size_t target); #define DEBUG_CHUNK_ALLOC /** A single chunk on a buffer. */ diff --git a/src/or/channel.c b/src/or/channel.c index 87fa721089..6a78b21988 100644 --- a/src/or/channel.c +++ b/src/or/channel.c @@ -838,7 +838,7 @@ channel_free(channel_t *chan) } /* Call a free method if there is one */ - if (chan->free) chan->free(chan); + if (chan->free_fn) chan->free_fn(chan); channel_clear_remote_end(chan); @@ -878,7 +878,7 @@ channel_listener_free(channel_listener_t *chan_l) tor_assert(!(chan_l->registered)); /* Call a free method if there is one */ - if (chan_l->free) chan_l->free(chan_l); + if (chan_l->free_fn) chan_l->free_fn(chan_l); /* * We're in CLOSED or ERROR, so the incoming channel queue is already @@ -916,7 +916,7 @@ channel_force_free(channel_t *chan) } /* Call a free method if there is one */ - if (chan->free) chan->free(chan); + if (chan->free_fn) chan->free_fn(chan); channel_clear_remote_end(chan); @@ -958,7 +958,7 @@ channel_listener_force_free(channel_listener_t *chan_l) chan_l); /* Call a free method if there is one */ - if (chan_l->free) chan_l->free(chan_l); + if (chan_l->free_fn) chan_l->free_fn(chan_l); /* * The incoming list just gets emptied and freed; we request close on diff --git a/src/or/channel.h b/src/or/channel.h index 78e1b71014..a711b56d44 100644 --- a/src/or/channel.h +++ b/src/or/channel.h @@ -90,7 +90,7 @@ struct channel_s { /* Methods implemented by the lower layer */ /** Free a channel */ - void (*free)(channel_t *); + void (*free_fn)(channel_t *); /** Close an open channel */ void (*close)(channel_t *); /** Describe the transport subclass for this channel */ @@ -273,7 +273,7 @@ struct channel_listener_s { /* Methods implemented by the lower layer */ /** Free a channel */ - void (*free)(channel_listener_t *); + void (*free_fn)(channel_listener_t *); /** Close an open channel */ void (*close)(channel_listener_t *); /** Describe the transport subclass for this channel */ diff --git a/src/or/channeltls.c b/src/or/channeltls.c index a62f80ef91..9c2411ede8 100644 --- a/src/or/channeltls.c +++ b/src/or/channeltls.c @@ -117,7 +117,7 @@ channel_tls_common_init(channel_tls_t *tlschan) chan->state = CHANNEL_STATE_OPENING; chan->close = channel_tls_close_method; chan->describe_transport = channel_tls_describe_transport_method; - chan->free = channel_tls_free_method; + chan->free_fn = channel_tls_free_method; chan->get_overhead_estimate = channel_tls_get_overhead_estimate_method; chan->get_remote_addr = channel_tls_get_remote_addr_method; chan->get_remote_descr = channel_tls_get_remote_descr_method; diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index 2e7ea2f79a..cc9b184698 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -28,6 +28,7 @@ #include "connection_edge.h" #include "connection_or.h" #include "control.h" +#include "crypto.h" #include "directory.h" #include "entrynodes.h" #include "main.h" @@ -38,14 +39,14 @@ #include "onion_tap.h" #include "onion_fast.h" #include "policies.h" -#include "transports.h" #include "relay.h" +#include "rendcommon.h" #include "rephist.h" #include "router.h" #include "routerlist.h" #include "routerparse.h" #include "routerset.h" -#include "crypto.h" +#include "transports.h" static channel_t * channel_connect_for_circuit(const tor_addr_t *addr, uint16_t port, @@ -855,7 +856,12 @@ circuit_pick_extend_handshake(uint8_t *cell_type_out, /* XXXX030 Remove support for deciding to use TAP. */ /* It is an error to extend if there is no previous node. */ - tor_assert_nonfatal(node_prev); + if (BUG(node_prev == NULL)) { + *cell_type_out = RELAY_COMMAND_EXTEND; + *create_cell_type_out = CELL_CREATE; + return; + } + /* It is an error for a node with a known version to be so old it does not * support ntor. */ tor_assert_nonfatal(routerstatus_version_supports_ntor(node_prev->rs, 1)); @@ -863,16 +869,15 @@ circuit_pick_extend_handshake(uint8_t *cell_type_out, /* Assume relays without tor versions or routerstatuses support ntor. * The authorities enforce ntor support, and assuming and failing is better * than allowing a malicious node to perform a protocol downgrade to TAP. */ - if (node_prev && - *handshake_type_out != ONION_HANDSHAKE_TYPE_TAP && + if (*handshake_type_out != ONION_HANDSHAKE_TYPE_TAP && (node_has_curve25519_onion_key(node_prev) || (routerstatus_version_supports_ntor(node_prev->rs, 1)))) { - *cell_type_out = RELAY_COMMAND_EXTEND2; - *create_cell_type_out = CELL_CREATE2; - } else { - *cell_type_out = RELAY_COMMAND_EXTEND; - *create_cell_type_out = CELL_CREATE; - } + *cell_type_out = RELAY_COMMAND_EXTEND2; + *create_cell_type_out = CELL_CREATE2; + } else { + *cell_type_out = RELAY_COMMAND_EXTEND; + *create_cell_type_out = CELL_CREATE; + } } /** This is the backbone function for building circuits. @@ -1855,13 +1860,32 @@ pick_rendezvous_node(router_crn_flags_t flags) flags |= CRN_ALLOW_INVALID; #ifdef ENABLE_TOR2WEB_MODE + /* We want to connect directly to the node if we can */ + router_crn_flags_t direct_flags = flags; + direct_flags |= CRN_PREF_ADDR; + direct_flags |= CRN_DIRECT_CONN; + /* The user wants us to pick specific RPs. */ if (options->Tor2webRendezvousPoints) { - const node_t *tor2web_rp = pick_tor2web_rendezvous_node(flags, options); + const node_t *tor2web_rp = pick_tor2web_rendezvous_node(direct_flags, + options); if (tor2web_rp) { return tor2web_rp; } - /* Else, if no tor2web RP was found, fall back to choosing a random node */ + } + + /* Else, if no direct, preferred tor2web RP was found, fall back to choosing + * a random direct node */ + const node_t *node = router_choose_random_node(NULL, options->ExcludeNodes, + direct_flags); + /* Return the direct node (if found), or log a message and fall back to an + * indirect connection. */ + if (node) { + return node; + } else { + log_info(LD_REND, + "Unable to find a random rendezvous point that is reachable via " + "a direct connection, falling back to a 3-hop path."); } #endif @@ -1996,7 +2020,9 @@ onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit_ei) cpath_build_state_t *state = circ->build_state; if (state->onehop_tunnel) { - log_debug(LD_CIRC, "Launching a one-hop circuit for dir tunnel."); + log_debug(LD_CIRC, "Launching a one-hop circuit for dir tunnel%s.", + (rend_allow_non_anonymous_connection(get_options()) ? + ", or intro or rendezvous connection" : "")); state->desired_path_len = 1; } else { int r = new_route_len(circ->base_.purpose, exit_ei, nodelist_get_list()); @@ -2543,3 +2569,4 @@ extend_info_has_preferred_onion_key(const extend_info_t* ei) tor_assert(ei); return extend_info_supports_ntor(ei); } + diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c index 3c92baa274..2b3c4169cb 100644 --- a/src/or/circuitlist.c +++ b/src/or/circuitlist.c @@ -1920,8 +1920,14 @@ marked_circuit_free_cells(circuit_t *circ) return; } cell_queue_clear(&circ->n_chan_cells); - if (! CIRCUIT_IS_ORIGIN(circ)) - cell_queue_clear(& TO_OR_CIRCUIT(circ)->p_chan_cells); + if (circ->n_mux) + circuitmux_clear_num_cells(circ->n_mux, circ); + if (! CIRCUIT_IS_ORIGIN(circ)) { + or_circuit_t *orcirc = TO_OR_CIRCUIT(circ); + cell_queue_clear(&orcirc->p_chan_cells); + if (orcirc->p_mux) + circuitmux_clear_num_cells(orcirc->p_mux, circ); + } } static size_t diff --git a/src/or/circuitmux_ewma.c b/src/or/circuitmux_ewma.c index b784a140ac..13836cdcfa 100644 --- a/src/or/circuitmux_ewma.c +++ b/src/or/circuitmux_ewma.c @@ -8,6 +8,8 @@ #define TOR_CIRCUITMUX_EWMA_C_ +#include "orconfig.h" + #include <math.h> #include "or.h" diff --git a/src/or/circuitstats.c b/src/or/circuitstats.c index f4db64ebca..3d64113521 100644 --- a/src/or/circuitstats.c +++ b/src/or/circuitstats.c @@ -21,6 +21,8 @@ #include "control.h" #include "main.h" #include "networkstatus.h" +#include "rendclient.h" +#include "rendservice.h" #include "statefile.h" #undef log @@ -81,12 +83,14 @@ get_circuit_build_timeout_ms(void) /** * This function decides if CBT learning should be disabled. It returns - * true if one or more of the following four conditions are met: + * true if one or more of the following conditions are met: * * 1. If the cbtdisabled consensus parameter is set. * 2. If the torrc option LearnCircuitBuildTimeout is false. * 3. If we are a directory authority * 4. If we fail to write circuit build time history to our state file. + * 5. If we are compiled or configured in Tor2web mode + * 6. If we are configured in Single Onion mode */ int circuit_build_times_disabled(void) @@ -94,14 +98,30 @@ circuit_build_times_disabled(void) if (unit_tests) { return 0; } else { + const or_options_t *options = get_options(); int consensus_disabled = networkstatus_get_param(NULL, "cbtdisabled", 0, 0, 1); - int config_disabled = !get_options()->LearnCircuitBuildTimeout; - int dirauth_disabled = get_options()->AuthoritativeDir; + int config_disabled = !options->LearnCircuitBuildTimeout; + int dirauth_disabled = options->AuthoritativeDir; int state_disabled = did_last_state_file_write_fail() ? 1 : 0; + /* LearnCircuitBuildTimeout and Tor2web/Single Onion Services are + * incompatible in two ways: + * + * - LearnCircuitBuildTimeout results in a low CBT, which + * Single Onion use of one-hop intro and rendezvous circuits lowers + * much further, producing *far* too many timeouts. + * + * - The adaptive CBT code does not update its timeout estimate + * using build times for single-hop circuits. + * + * If we fix both of these issues someday, we should test + * these modes with LearnCircuitBuildTimeout on again. */ + int tor2web_disabled = rend_client_allow_non_anonymous_connection(options); + int single_onion_disabled = rend_service_allow_non_anonymous_connection( + options); if (consensus_disabled || config_disabled || dirauth_disabled || - state_disabled) { + state_disabled || tor2web_disabled || single_onion_disabled) { #if 0 log_debug(LD_CIRC, "CircuitBuildTime learning is disabled. " @@ -469,7 +489,7 @@ circuit_build_times_get_initial_timeout(void) */ if (!unit_tests && get_options()->CircuitBuildTimeout) { timeout = get_options()->CircuitBuildTimeout*1000; - if (get_options()->LearnCircuitBuildTimeout && + if (!circuit_build_times_disabled() && timeout < circuit_build_times_min_timeout()) { log_warn(LD_CIRC, "Config CircuitBuildTimeout too low. Setting to %ds", circuit_build_times_min_timeout()/1000); diff --git a/src/or/config.c b/src/or/config.c index 98b32708c6..18cbe34be3 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -18,6 +18,7 @@ #include "circuitlist.h" #include "circuitmux.h" #include "circuitmux_ewma.h" +#include "circuitstats.h" #include "config.h" #include "connection.h" #include "connection_edge.h" @@ -297,6 +298,8 @@ static config_var_t option_vars_[] = { V(HidServAuth, LINELIST, NULL), V(CloseHSClientCircuitsImmediatelyOnTimeout, BOOL, "0"), V(CloseHSServiceRendCircuitsImmediatelyOnTimeout, BOOL, "0"), + V(HiddenServiceSingleHopMode, BOOL, "0"), + V(HiddenServiceNonAnonymousMode,BOOL, "0"), V(HTTPProxy, STRING, NULL), V(HTTPProxyAuthenticator, STRING, NULL), V(HTTPSProxy, STRING, NULL), @@ -434,7 +437,7 @@ static config_var_t option_vars_[] = { OBSOLETE("TunnelDirConns"), V(UpdateBridgesFromAuthority, BOOL, "0"), V(UseBridges, BOOL, "0"), - V(UseEntryGuards, BOOL, "1"), + VAR("UseEntryGuards", BOOL, UseEntryGuards_option, "1"), V(UseEntryGuardsAsDirGuards, BOOL, "1"), V(UseGuardFraction, AUTOBOOL, "auto"), V(UseMicrodescriptors, AUTOBOOL, "auto"), @@ -1558,10 +1561,10 @@ options_act(const or_options_t *old_options) if (consider_adding_dir_servers(options, old_options) < 0) return -1; -#ifdef NON_ANONYMOUS_MODE_ENABLED - log_warn(LD_GENERAL, "This copy of Tor was compiled to run in a " - "non-anonymous mode. It will provide NO ANONYMITY."); -#endif + if (rend_non_anonymous_mode_enabled(options)) { + log_warn(LD_GENERAL, "This copy of Tor was compiled or configured to run " + "in a non-anonymous mode. It will provide NO ANONYMITY."); + } #ifdef ENABLE_TOR2WEB_MODE /* LCOV_EXCL_START */ @@ -1723,8 +1726,27 @@ options_act(const or_options_t *old_options) monitor_owning_controller_process(options->OwningControllerProcess); + /* We must create new keys after we poison the directories, because our + * poisoning code checks for existing keys, and refuses to modify their + * directories. */ + + /* 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_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 non-anonymous" + "."); + return -1; + } + } + /* reload keys as needed for rendezvous services. */ - if (rend_service_load_all_keys()<0) { + if (rend_service_load_all_keys(NULL)<0) { log_warn(LD_GENERAL,"Error loading rendezvous service keys"); return -1; } @@ -2796,6 +2818,86 @@ warn_about_relative_paths(or_options_t *options) } } +/* 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) +{ + /* The two single onion service options must have matching values. */ + if (options->HiddenServiceSingleHopMode && + !options->HiddenServiceNonAnonymousMode) { + REJECT("HiddenServiceSingleHopMode does not provide any server anonymity. " + "It must be used with HiddenServiceNonAnonymousMode set to 1."); + } + if (options->HiddenServiceNonAnonymousMode && + !options->HiddenServiceSingleHopMode) { + REJECT("HiddenServiceNonAnonymousMode does not provide any server " + "anonymity. It must be used with HiddenServiceSingleHopMode 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 (rend_service_non_anonymous_mode_enabled(options) && client_port_set && + !options->Tor2webMode) { + REJECT("HiddenServiceNonAnonymousMode is incompatible with using Tor as " + "an anonymous client. Please set Socks/Trans/NATD/DNSPort to 0, or " + "HiddenServiceNonAnonymousMode 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 (!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 " + " HiddenServiceNonAnonymousMode."); + } + + if (rend_service_allow_non_anonymous_connection(options) + && options->UseEntryGuards) { + /* 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 path bias compatible with single onions. + */ + log_notice(LD_CONFIG, + "HiddenServiceSingleHopMode is enabled; disabling " + "UseEntryGuards."); + options->UseEntryGuards = 0; + } + + /* 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 " + "HiddenServiceNonAnonymousMode %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, + rend_service_non_anonymous_mode_enabled(options) ? + "an anonymous" : "a non-anonymous" + ); + return -1; + } + + return 0; +} + /** Return 0 if every setting in <b>options</b> is reasonable, is a * permissible transition from <b>old_options</b>, and none of the * testing-only settings differ from <b>default_options</b> unless in @@ -2822,6 +2924,12 @@ options_validate(or_options_t *old_options, or_options_t *options, tor_assert(msg); *msg = NULL; + /* Set UseEntryGuards from the configured value, before we check it below. + * We change UseEntryGuards whenn it's incompatible with other options, + * but leave UseEntryGuards_option with the original value. + * Always use the value of UseEntryGuards, not UseEntryGuards_option. */ + options->UseEntryGuards = options->UseEntryGuards_option; + warn_about_relative_paths(options); if (server_mode(options) && @@ -3197,10 +3305,6 @@ options_validate(or_options_t *old_options, or_options_t *options, if (options->UseBridges && options->EntryNodes) REJECT("You cannot set both UseBridges and EntryNodes."); - if (options->EntryNodes && !options->UseEntryGuards) { - REJECT("If EntryNodes is set, UseEntryGuards must be enabled."); - } - options->MaxMemInQueues = compute_real_max_mem_in_queues(options->MaxMemInQueues_raw, server_mode(options)); @@ -3291,25 +3395,11 @@ options_validate(or_options_t *old_options, or_options_t *options, options->PredictedPortsRelevanceTime = MAX_PREDICTED_CIRCS_RELEVANCE; } -#ifdef ENABLE_TOR2WEB_MODE - if (options->Tor2webMode && options->LearnCircuitBuildTimeout) { - /* LearnCircuitBuildTimeout and Tor2webMode are incompatible in - * two ways: - * - * - LearnCircuitBuildTimeout results in a low CBT, which - * Tor2webMode's use of one-hop rendezvous circuits lowers - * much further, producing *far* too many timeouts. - * - * - The adaptive CBT code does not update its timeout estimate - * using build times for single-hop circuits. - * - * If we fix both of these issues someday, we should test - * Tor2webMode with LearnCircuitBuildTimeout on again. */ - log_notice(LD_CONFIG,"Tor2webMode is enabled; turning " - "LearnCircuitBuildTimeout off."); - options->LearnCircuitBuildTimeout = 0; - } + /* Check the Single Onion Service options */ + if (options_validate_single_onion(options, msg) < 0) + return -1; +#ifdef ENABLE_TOR2WEB_MODE if (options->Tor2webMode && options->UseEntryGuards) { /* tor2web mode clients do not (and should not) use entry guards * in any meaningful way. Further, tor2web mode causes the hidden @@ -3329,8 +3419,13 @@ options_validate(or_options_t *old_options, or_options_t *options, REJECT("Tor2webRendezvousPoints cannot be set without Tor2webMode."); } + if (options->EntryNodes && !options->UseEntryGuards) { + REJECT("If EntryNodes is set, UseEntryGuards must be enabled."); + } + if (!(options->UseEntryGuards) && - (options->RendConfigLines != NULL)) { + (options->RendConfigLines != NULL) && + !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 " @@ -3353,6 +3448,17 @@ options_validate(or_options_t *old_options, or_options_t *options, return -1; } + /* Single Onion Services: non-anonymous hidden services */ + if (rend_service_non_anonymous_mode_enabled(options)) { + log_warn(LD_CONFIG, + "HiddenServiceNonAnonymousMode is set. Every hidden service on " + "this tor instance is NON-ANONYMOUS. If " + "the HiddenServiceNonAnonymousMode 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 && options->CircuitBuildTimeout < RECOMMENDED_MIN_CIRCUIT_BUILD_TIMEOUT) { log_warn(LD_CONFIG, @@ -3364,8 +3470,15 @@ options_validate(or_options_t *old_options, or_options_t *options, RECOMMENDED_MIN_CIRCUIT_BUILD_TIMEOUT ); } else if (!options->LearnCircuitBuildTimeout && !options->CircuitBuildTimeout) { - log_notice(LD_CONFIG, "You disabled LearnCircuitBuildTimeout, but didn't " - "a CircuitBuildTimeout. I'll pick a plausible default."); + int severity = LOG_NOTICE; + /* Be a little quieter if we've deliberately disabled + * LearnCircuitBuildTimeout. */ + if (circuit_build_times_disabled()) { + severity = LOG_INFO; + } + log_fn(severity, LD_CONFIG, "You disabled LearnCircuitBuildTimeout, but " + "didn't specify a CircuitBuildTimeout. I'll pick a plausible " + "default."); } if (options->PathBiasNoticeRate > 1.0) { @@ -4295,6 +4408,19 @@ options_transition_allowed(const or_options_t *old, return -1; } + if (old->HiddenServiceSingleHopMode != new_val->HiddenServiceSingleHopMode) { + *msg = tor_strdup("While Tor is running, changing " + "HiddenServiceSingleHopMode is not allowed."); + return -1; + } + + if (old->HiddenServiceNonAnonymousMode != + new_val->HiddenServiceNonAnonymousMode) { + *msg = tor_strdup("While Tor is running, changing " + "HiddenServiceNonAnonymousMode is not allowed."); + return -1; + } + if (old->DisableDebuggerAttachment && !new_val->DisableDebuggerAttachment) { *msg = tor_strdup("While Tor is running, disabling " @@ -5325,10 +5451,14 @@ bridge_line_free(bridge_line_t *bridge_line) tor_free(bridge_line); } -/** Read the contents of a Bridge line from <b>line</b>. Return 0 - * if the line is well-formed, and -1 if it isn't. If - * <b>validate_only</b> is 0, and the line is well-formed, then add - * the bridge described in the line to our internal bridge list. +/** Parse the contents of a string, <b>line</b>, containing a Bridge line, + * into a bridge_line_t. + * + * Validates that the IP:PORT, fingerprint, and SOCKS arguments (given to the + * Pluggable Transport, if a one was specified) are well-formed. + * + * Returns NULL If the Bridge line could not be validated, and returns a + * bridge_line_t containing the parsed information otherwise. * * Bridge line format: * Bridge [transport] IP:PORT [id-fingerprint] [k=v] [k=v] ... @@ -6054,6 +6184,8 @@ port_cfg_new(size_t namelen) tor_assert(namelen <= SIZE_T_CEILING - sizeof(port_cfg_t) - 1); port_cfg_t *cfg = tor_malloc_zero(sizeof(port_cfg_t) + namelen + 1); cfg->entry_cfg.ipv4_traffic = 1; + cfg->entry_cfg.dns_request = 1; + cfg->entry_cfg.onion_traffic = 1; cfg->entry_cfg.cache_ipv4_answers = 1; cfg->entry_cfg.prefer_ipv6_virtaddr = 1; return cfg; @@ -6324,8 +6456,7 @@ parse_port_config(smartlist_t *out, tor_addr_make_unspec(&cfg->addr); /* Server ports default to 0.0.0.0 */ cfg->server_cfg.no_listen = 1; cfg->server_cfg.bind_ipv4_only = 1; - cfg->entry_cfg.ipv4_traffic = 1; - cfg->entry_cfg.prefer_ipv6_virtaddr = 1; + /* cfg->entry_cfg defaults are already set by port_cfg_new */ smartlist_add(out, cfg); } @@ -6396,9 +6527,11 @@ parse_port_config(smartlist_t *out, char *addrport; uint16_t ptmp=0; int ok; + /* This must be kept in sync with port_cfg_new's defaults */ int no_listen = 0, no_advertise = 0, all_addrs = 0, bind_ipv4_only = 0, bind_ipv6_only = 0, - ipv4_traffic = 1, ipv6_traffic = 0, prefer_ipv6 = 0, + ipv4_traffic = 1, ipv6_traffic = 0, prefer_ipv6 = 0, dns_request = 1, + onion_traffic = 1, cache_ipv4 = 1, use_cached_ipv4 = 0, cache_ipv6 = 0, use_cached_ipv6 = 0, prefer_ipv6_automap = 1, world_writable = 0, group_writable = 0, @@ -6584,6 +6717,24 @@ parse_port_config(smartlist_t *out, } else if (!strcasecmp(elt, "PreferIPv6")) { prefer_ipv6 = ! no; continue; + } else if (!strcasecmp(elt, "DNSRequest")) { + dns_request = ! no; + continue; + } else if (!strcasecmp(elt, "OnionTraffic")) { + onion_traffic = ! no; + continue; + } else if (!strcasecmp(elt, "OnionTrafficOnly")) { + /* Only connect to .onion addresses. Equivalent to + * NoDNSRequest, NoIPv4Traffic, NoIPv6Traffic. The option + * NoOnionTrafficOnly is not supported, it's too confusing. */ + if (no) { + log_warn(LD_CONFIG, "Unsupported %sPort option 'No%s'. Use " + "DNSRequest, IPv4Traffic, and/or IPv6Traffic instead.", + portname, escaped(elt)); + } else { + ipv4_traffic = ipv6_traffic = dns_request = 0; + } + continue; } } if (!strcasecmp(elt, "CacheIPv4DNS")) { @@ -6652,9 +6803,24 @@ parse_port_config(smartlist_t *out, else got_zero_port = 1; - if (ipv4_traffic == 0 && ipv6_traffic == 0) { - log_warn(LD_CONFIG, "You have a %sPort entry with both IPv4 and " - "IPv6 disabled; that won't work.", portname); + if (dns_request == 0 && listener_type == CONN_TYPE_AP_DNS_LISTENER) { + log_warn(LD_CONFIG, "You have a %sPort entry with DNS disabled; that " + "won't work.", portname); + goto err; + } + + if (ipv4_traffic == 0 && ipv6_traffic == 0 && onion_traffic == 0 + && listener_type != CONN_TYPE_AP_DNS_LISTENER) { + log_warn(LD_CONFIG, "You have a %sPort entry with all of IPv4 and " + "IPv6 and .onion disabled; that won't work.", portname); + goto err; + } + + if (dns_request == 1 && ipv4_traffic == 0 && ipv6_traffic == 0 + && listener_type != CONN_TYPE_AP_DNS_LISTENER) { + log_warn(LD_CONFIG, "You have a %sPort entry with DNSRequest enabled, " + "but IPv4 and IPv6 disabled; DNS-based sites won't work.", + portname); goto err; } @@ -6698,6 +6864,8 @@ parse_port_config(smartlist_t *out, cfg->entry_cfg.ipv4_traffic = ipv4_traffic; cfg->entry_cfg.ipv6_traffic = ipv6_traffic; cfg->entry_cfg.prefer_ipv6 = prefer_ipv6; + cfg->entry_cfg.dns_request = dns_request; + cfg->entry_cfg.onion_traffic = onion_traffic; cfg->entry_cfg.cache_ipv4_answers = cache_ipv4; cfg->entry_cfg.cache_ipv6_answers = cache_ipv6; cfg->entry_cfg.use_cached_ipv4_answers = use_cached_ipv4; @@ -6739,14 +6907,17 @@ parse_port_config(smartlist_t *out, } /** Return the number of ports which are actually going to listen with type - * <b>listenertype</b>. Do not count no_listen ports. Do not count unix - * sockets. */ + * <b>listenertype</b>. Do not count no_listen ports. Only count unix + * sockets if count_sockets is true. */ static int -count_real_listeners(const smartlist_t *ports, int listenertype) +count_real_listeners(const smartlist_t *ports, int listenertype, + int count_sockets) { int n = 0; SMARTLIST_FOREACH_BEGIN(ports, port_cfg_t *, port) { - if (port->server_cfg.no_listen || port->is_unix_addr) + if (port->server_cfg.no_listen) + continue; + if (!count_sockets && port->is_unix_addr) continue; if (port->type != listenertype) continue; @@ -6755,9 +6926,8 @@ count_real_listeners(const smartlist_t *ports, int listenertype) return n; } -/** Parse all client port types (Socks, DNS, Trans, NATD) from - * <b>options</b>. On success, set *<b>n_ports_out</b> to the number - * of ports that are listed, update the *Port_set values in +/** Parse all ports from <b>options</b>. On success, set *<b>n_ports_out</b> + * to the number of ports that are listed, update the *Port_set values in * <b>options</b>, and return 0. On failure, set *<b>msg</b> to a * description of the problem and return -1. * @@ -6883,21 +7053,22 @@ parse_ports(or_options_t *options, int validate_only, /* Update the *Port_set options. The !! here is to force a boolean out of an integer. */ options->ORPort_set = - !! count_real_listeners(ports, CONN_TYPE_OR_LISTENER); + !! count_real_listeners(ports, CONN_TYPE_OR_LISTENER, 0); options->SocksPort_set = - !! count_real_listeners(ports, CONN_TYPE_AP_LISTENER); + !! count_real_listeners(ports, CONN_TYPE_AP_LISTENER, 1); options->TransPort_set = - !! count_real_listeners(ports, CONN_TYPE_AP_TRANS_LISTENER); + !! count_real_listeners(ports, CONN_TYPE_AP_TRANS_LISTENER, 1); options->NATDPort_set = - !! count_real_listeners(ports, CONN_TYPE_AP_NATD_LISTENER); + !! count_real_listeners(ports, CONN_TYPE_AP_NATD_LISTENER, 1); + /* Use options->ControlSocket to test if a control socket is set */ options->ControlPort_set = - !! count_real_listeners(ports, CONN_TYPE_CONTROL_LISTENER); + !! count_real_listeners(ports, CONN_TYPE_CONTROL_LISTENER, 0); options->DirPort_set = - !! count_real_listeners(ports, CONN_TYPE_DIR_LISTENER); + !! count_real_listeners(ports, CONN_TYPE_DIR_LISTENER, 0); options->DNSPort_set = - !! count_real_listeners(ports, CONN_TYPE_AP_DNS_LISTENER); + !! count_real_listeners(ports, CONN_TYPE_AP_DNS_LISTENER, 1); options->ExtORPort_set = - !! count_real_listeners(ports, CONN_TYPE_EXT_OR_LISTENER); + !! count_real_listeners(ports, CONN_TYPE_EXT_OR_LISTENER, 0); if (world_writable_control_socket) { SMARTLIST_FOREACH(ports, port_cfg_t *, p, diff --git a/src/or/config.h b/src/or/config.h index 7db66a31b9..208659acb7 100644 --- a/src/or/config.h +++ b/src/or/config.h @@ -166,6 +166,8 @@ extern struct config_format_t options_format; STATIC port_cfg_t *port_cfg_new(size_t namelen); STATIC void port_cfg_free(port_cfg_t *port); STATIC void or_options_free(or_options_t *options); +STATIC int options_validate_single_onion(or_options_t *options, + char **msg); STATIC int options_validate(or_options_t *old_options, or_options_t *options, or_options_t *default_options, diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index dc6b0930ca..a41dcd5360 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -27,6 +27,7 @@ #include "control.h" #include "dns.h" #include "dnsserv.h" +#include "directory.h" #include "dirserv.h" #include "hibernate.h" #include "main.h" @@ -1227,7 +1228,7 @@ connection_ap_handshake_rewrite(entry_connection_t *conn, } /* Hang on, did we find an answer saying that this is a reverse lookup for - * an internal address? If so, we should reject it if we're condigured to + * an internal address? If so, we should reject it if we're configured to * do so. */ if (options->ClientDNSRejectInternalAddresses) { /* Don't let people try to do a reverse lookup on 10.0.0.1. */ @@ -1466,14 +1467,61 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn, /* If we're running in Tor2webMode, we don't allow anything BUT .onion * addresses. */ if (options->Tor2webMode) { - log_warn(LD_APP, "Refusing to connect to non-hidden-service hostname %s " - "because tor2web mode is enabled.", + log_warn(LD_APP, "Refusing to connect to non-hidden-service hostname " + "or IP address %s because tor2web mode is enabled.", safe_str_client(socks->address)); connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY); return -1; } #endif + /* socks->address is a non-onion hostname or IP address. + * If we can't do any non-onion requests, refuse the connection. + * If we have a hostname but can't do DNS, refuse the connection. + * If we have an IP address, but we can't use that address family, + * refuse the connection. + * + * If we can do DNS requests, and we can use at least one address family, + * then we have to resolve the address first. Then we'll know if it + * resolves to a usable address family. */ + + /* First, check if all non-onion traffic is disabled */ + if (!conn->entry_cfg.dns_request && !conn->entry_cfg.ipv4_traffic + && !conn->entry_cfg.ipv6_traffic) { + log_warn(LD_APP, "Refusing to connect to non-hidden-service hostname " + "or IP address %s because Port has OnionTrafficOnly set (or " + "NoDNSRequest, NoIPv4Traffic, and NoIPv6Traffic).", + safe_str_client(socks->address)); + connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY); + return -1; + } + + /* Then check if we have a hostname or IP address, and whether DNS or + * the IP address family are permitted */ + tor_addr_t dummy_addr; + int socks_family = tor_addr_parse(&dummy_addr, socks->address); + /* family will be -1 for a non-onion hostname that's not an IP */ + if (socks_family == -1 && !conn->entry_cfg.dns_request) { + log_warn(LD_APP, "Refusing to connect to hostname %s " + "because Port has NoDNSRequest set.", + safe_str_client(socks->address)); + connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY); + return -1; + } else if (socks_family == AF_INET && !conn->entry_cfg.ipv4_traffic) { + log_warn(LD_APP, "Refusing to connect to IPv4 address %s because " + "Port has NoIPv4Traffic set.", + safe_str_client(socks->address)); + connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY); + return -1; + } else if (socks_family == AF_INET6 && !conn->entry_cfg.ipv6_traffic) { + log_warn(LD_APP, "Refusing to connect to IPv6 address %s because " + "Port has NoIPv6Traffic set.", + safe_str_client(socks->address)); + connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY); + return -1; + } + /* No else, we've covered all possible returned value. */ + /* See if this is a hostname lookup that we can answer immediately. * (For example, an attempt to look up the IP address for an IP address.) */ @@ -1661,6 +1709,14 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn, /* If we get here, it's a request for a .onion address! */ tor_assert(!automap); + /* If .onion address requests are disabled, refuse the request */ + if (!conn->entry_cfg.onion_traffic) { + log_warn(LD_APP, "Onion address %s requested from a port with .onion " + "disabled", safe_str_client(socks->address)); + connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY); + return -1; + } + /* Check whether it's RESOLVE or RESOLVE_PTR. We don't handle those * for hidden service addresses. */ if (SOCKS_COMMAND_IS_RESOLVE(socks->command)) { @@ -2271,6 +2327,7 @@ connection_ap_handshake_send_begin(entry_connection_t *ap_conn) char payload[CELL_PAYLOAD_SIZE]; int payload_len; int begin_type; + const or_options_t *options = get_options(); origin_circuit_t *circ; edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(ap_conn); connection_t *base_conn = TO_CONN(edge_conn); @@ -2314,10 +2371,31 @@ connection_ap_handshake_send_begin(entry_connection_t *ap_conn) begin_type = ap_conn->use_begindir ? RELAY_COMMAND_BEGIN_DIR : RELAY_COMMAND_BEGIN; + + /* Check that circuits are anonymised, based on their type. */ if (begin_type == RELAY_COMMAND_BEGIN) { -#ifndef NON_ANONYMOUS_MODE_ENABLED - tor_assert(circ->build_state->onehop_tunnel == 0); -#endif + /* This connection is a standard OR connection. + * Make sure its path length is anonymous, or that we're in a + * non-anonymous mode. */ + assert_circ_anonymity_ok(circ, options); + } else if (begin_type == RELAY_COMMAND_BEGIN_DIR) { + /* This connection is a begindir directory connection. + * Look at the linked directory connection to access the directory purpose. + * (This must be non-NULL, because we're doing begindir.) */ + tor_assert(base_conn->linked); + connection_t *linked_dir_conn_base = base_conn->linked_conn; + tor_assert(linked_dir_conn_base); + /* Sensitive directory connections must have an anonymous path length. + * Otherwise, directory connections are typically one-hop. + * This matches the earlier check for directory connection path anonymity + * in directory_initiate_command_rend(). */ + if (is_sensitive_dir_purpose(linked_dir_conn_base->purpose)) { + assert_circ_anonymity_ok(circ, options); + } + } else { + /* This code was written for the two connection types BEGIN and BEGIN_DIR + */ + tor_assert_unreached(); } if (connection_edge_send_command(edge_conn, begin_type, diff --git a/src/or/control.c b/src/or/control.c index 1337af4201..8962075e1e 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -4249,6 +4249,8 @@ 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 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="; static const char *flags_prefix = "Flags="; @@ -4285,11 +4287,16 @@ handle_control_add_onion(control_connection_t *conn, * * 'MaxStreamsCloseCircuit' - Close the circuit if MaxStreams is * exceeded. * * 'BasicAuth' - Client authorization using the 'basic' method. + * * 'NonAnonymous' - Add a non-anonymous Single Onion Service. If this + * 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"; static const char *max_s_close_flag = "MaxStreamsCloseCircuit"; static const char *basicauth_flag = "BasicAuth"; + static const char *non_anonymous_flag = "NonAnonymous"; smartlist_t *flags = smartlist_new(); int bad = 0; @@ -4310,6 +4317,8 @@ handle_control_add_onion(control_connection_t *conn, max_streams_close_circuit = 1; } else if (!strcasecmp(flag, basicauth_flag)) { auth_type = REND_BASIC_AUTH; + } else if (!strcasecmp(flag, non_anonymous_flag)) { + non_anonymous = 1; } else { connection_printf_to_buf(conn, "512 Invalid 'Flags' argument: %s\r\n", @@ -4378,6 +4387,19 @@ 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_non_anonymous_mode_enabled( + get_options())) { + /* 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 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 hidden service " + "mode\r\n", + non_anonymous ? "" : "non-"); + goto out; } /* Parse the "keytype:keyblob" argument. */ diff --git a/src/or/directory.c b/src/or/directory.c index d37b5c2e0f..52b14b9bae 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -1085,7 +1085,7 @@ directory_initiate_command(const tor_addr_t *or_addr, uint16_t or_port, * <b>dir_purpose</b> reveals sensitive information about a Tor * instance's client activities. (Such connections must be performed * through normal three-hop Tor circuits.) */ -static int +int is_sensitive_dir_purpose(uint8_t dir_purpose) { return ((dir_purpose == DIR_PURPOSE_HAS_FETCHED_RENDDESC_V2) || @@ -1140,12 +1140,10 @@ directory_initiate_command_rend(const tor_addr_port_t *or_addr_port, log_debug(LD_DIR, "Initiating %s", dir_conn_purpose_to_string(dir_purpose)); -#ifndef NON_ANONYMOUS_MODE_ENABLED - tor_assert(!(is_sensitive_dir_purpose(dir_purpose) && - !anonymized_connection)); -#else - (void)is_sensitive_dir_purpose; -#endif + if (is_sensitive_dir_purpose(dir_purpose)) { + tor_assert(anonymized_connection || + rend_non_anonymous_mode_enabled(options)); + } /* use encrypted begindir connections for everything except relays * this provides better protection for directory fetches */ diff --git a/src/or/directory.h b/src/or/directory.h index f04e7ab315..9477948aa0 100644 --- a/src/or/directory.h +++ b/src/or/directory.h @@ -132,7 +132,10 @@ int download_status_get_n_failures(const download_status_t *dls); int download_status_get_n_attempts(const download_status_t *dls); time_t download_status_get_next_attempt_at(const download_status_t *dls); +/* Yes, these two functions are confusingly similar. + * Let's sort that out in #20077. */ int purpose_needs_anonymity(uint8_t dir_purpose, uint8_t router_purpose); +int is_sensitive_dir_purpose(uint8_t dir_purpose); #ifdef TOR_UNIT_TESTS /* Used only by directory.c and test_dir.c */ diff --git a/src/or/dirvote.c b/src/or/dirvote.c index 9b41e8f449..8b195f8914 100644 --- a/src/or/dirvote.c +++ b/src/or/dirvote.c @@ -1709,7 +1709,7 @@ networkstatus_compute_consensus(smartlist_t *votes, const char *chosen_protocol_list; const char *chosen_name = NULL; int exitsummary_disagreement = 0; - int is_named = 0, is_unnamed = 0, is_running = 0; + int is_named = 0, is_unnamed = 0, is_running = 0, is_valid = 0; int is_guard = 0, is_exit = 0, is_bad_exit = 0; int naming_conflict = 0; int n_listing = 0; @@ -1867,6 +1867,8 @@ networkstatus_compute_consensus(smartlist_t *votes, is_running = 1; else if (!strcmp(fl, "BadExit")) is_bad_exit = 1; + else if (!strcmp(fl, "Valid")) + is_valid = 1; } } } SMARTLIST_FOREACH_END(fl); @@ -1876,6 +1878,12 @@ networkstatus_compute_consensus(smartlist_t *votes, if (!is_running) continue; + /* Starting with consensus method 24, we don't list servers + * that are not valid in a consensus. See Proposal 272 */ + if (!is_valid && + consensus_method >= MIN_METHOD_FOR_EXCLUDING_INVALID_NODES) + continue; + /* Pick the version. */ if (smartlist_len(versions)) { sort_version_list(versions, 0); diff --git a/src/or/dirvote.h b/src/or/dirvote.h index a6c847ec25..efd233ef5f 100644 --- a/src/or/dirvote.h +++ b/src/or/dirvote.h @@ -55,7 +55,7 @@ #define MIN_SUPPORTED_CONSENSUS_METHOD 13 /** The highest consensus method that we currently support. */ -#define MAX_SUPPORTED_CONSENSUS_METHOD 24 +#define MAX_SUPPORTED_CONSENSUS_METHOD 25 /** Lowest consensus method where microdesc consensuses omit any entry * with no microdesc. */ @@ -99,13 +99,17 @@ * value(s). */ #define MIN_METHOD_FOR_SHARED_RANDOM 23 +/** Lowest consensus method where authorities drop all nodes that don't get + * the Valid flag. */ +#define MIN_METHOD_FOR_EXCLUDING_INVALID_NODES 24 + /** Lowest consensus method where authorities vote on required/recommended * protocols. */ -#define MIN_METHOD_FOR_RECOMMENDED_PROTOCOLS 24 +#define MIN_METHOD_FOR_RECOMMENDED_PROTOCOLS 25 /** Lowest consensus method where authorities add protocols to routerstatus * entries. */ -#define MIN_METHOD_FOR_RS_PROTOCOLS 24 +#define MIN_METHOD_FOR_RS_PROTOCOLS 25 /** Default bandwidth to clip unmeasured bandwidths to using method >= * MIN_METHOD_TO_CLIP_UNMEASURED_BW. (This is not a consensus method; do not diff --git a/src/or/dnsserv.c b/src/or/dnsserv.c index 6aab1e2c36..04be3e8a6a 100644 --- a/src/or/dnsserv.c +++ b/src/or/dnsserv.c @@ -136,6 +136,8 @@ evdns_server_callback(struct evdns_server_request *req, void *data_) entry_conn->socks_request->command = SOCKS_COMMAND_RESOLVE_PTR; } + /* This serves our DNS port so enable DNS request by default. */ + entry_conn->entry_cfg.dns_request = 1; if (q->type == EVDNS_TYPE_A || q->type == EVDNS_QTYPE_ALL) { entry_conn->entry_cfg.ipv4_traffic = 1; entry_conn->entry_cfg.ipv6_traffic = 0; diff --git a/src/or/fallback_dirs.inc b/src/or/fallback_dirs.inc index 245110f4aa..f6289199b7 100644 --- a/src/or/fallback_dirs.inc +++ b/src/or/fallback_dirs.inc @@ -30,9 +30,11 @@ URL: https:onionoo.torproject.orguptime?first_seen_days=7-&flag=V2Dir&type=relay " weight=10", "178.62.197.82:80 orport=443 id=0D3EBA17E1C78F1E9900BABDB23861D46FCAF163" " weight=10", -"144.76.14.145:110 orport=143 id=14419131033443AE6E21DA82B0D307F7CAE42BDB" -" ipv6=[2a01:4f8:190:9490::dead]:443" -" weight=10", +/* Fallback was on 0.2.8.6 list, but down for a week before 0.2.9 + * "144.76.14.145:110 orport=143 id=14419131033443AE6E21DA82B0D307F7CAE42BDB" + * " ipv6=[2a01:4f8:190:9490::dead]:443" + * " weight=10", + */ "178.32.216.146:9030 orport=9001 id=17898F9A2EBC7D69DAF87C00A1BD2FABF3C9E1D2" " weight=10", "46.101.151.222:80 orport=443 id=1DBAED235E3957DE1ABD25B4206BE71406FB61F8" @@ -47,8 +49,10 @@ URL: https:onionoo.torproject.orguptime?first_seen_days=7-&flag=V2Dir&type=relay * "51.254.215.121:80 orport=443 id=262B66AD25C79588AD1FC8ED0E966395B47E5C1D" * " weight=10", */ -"194.150.168.79:11112 orport=11111 id=29F1020B94BE25E6BE1AD13E93CE19D2131B487C" -" weight=10", +/* Fallback was on 0.2.8.6 list, but went down before 0.2.9 + * "194.150.168.79:11112 orport=11111 id=29F1020B94BE25E6BE1AD13E93CE19D2131B487C" + * " weight=10", + */ "144.76.26.175:9012 orport=9011 id=2BA2C8E96B2590E1072AECE2BDB5C48921BF8510" " weight=10", "62.210.124.124:9130 orport=9101 id=2EBD117806EE43C3CC885A8F1E4DC60F207E7D3E" @@ -84,8 +88,10 @@ URL: https:onionoo.torproject.orguptime?first_seen_days=7-&flag=V2Dir&type=relay "212.51.134.123:9030 orport=9001 id=50586E25BE067FD1F739998550EDDCB1A14CA5B2" " ipv6=[2a02:168:6e00:0:3a60:77ff:fe9c:8bd1]:9001" " weight=10", -"5.175.233.86:80 orport=443 id=5525D0429BFE5DC4F1B0E9DE47A4CFA169661E33" -" weight=10", +/* Fallback was on 0.2.8.6 list, but changed IPv4 before 0.2.9 + * "5.175.233.86:80 orport=443 id=5525D0429BFE5DC4F1B0E9DE47A4CFA169661E33" + * " weight=10", + */ "94.23.204.175:9030 orport=9001 id=5665A3904C89E22E971305EE8C1997BCA4123C69" " weight=10", "109.163.234.9:80 orport=443 id=5714542DCBEE1DD9864824723638FD44B2122CEA" @@ -107,10 +113,14 @@ URL: https:onionoo.torproject.orguptime?first_seen_days=7-&flag=V2Dir&type=relay " weight=10", "89.187.142.208:80 orport=443 id=64186650FFE4469EBBE52B644AE543864D32F43C" " weight=10", -"144.76.73.140:9030 orport=9001 id=6A640018EABF3DA9BAD9321AA37C2C87BBE1F907" -" weight=10", -"94.126.23.174:9030 orport=9001 id=6FC6F08270D565BE89B7C819DD8E2D487397C073" -" weight=10", +/* Fallback was on 0.2.8.6 list, but operator opted-out before 0.2.9 + * "144.76.73.140:9030 orport=9001 id=6A640018EABF3DA9BAD9321AA37C2C87BBE1F907" + * " weight=10", + */ +/* Fallback was on 0.2.8.6 list, but went down before 0.2.9 + * "94.126.23.174:9030 orport=9001 id=6FC6F08270D565BE89B7C819DD8E2D487397C073" + * " weight=10", + */ "176.31.191.26:9030 orport=9001 id=7350AB9ED7568F22745198359373C04AC783C37C" " weight=10", "46.101.237.246:9030 orport=9001 id=75F1992FD3F403E9C082A5815EB5D12934CDF46C" @@ -240,13 +250,17 @@ URL: https:onionoo.torproject.orguptime?first_seen_days=7-&flag=V2Dir&type=relay " weight=10", "5.34.183.205:80 orport=443 id=DDD7871C1B7FA32CB55061E08869A236E61BDDF8" " weight=10", -"195.191.233.221:80 orport=443 id=DE134FC8E5CC4EC8A5DE66934E70AC9D70267197" -" weight=10", +/* Fallback was on 0.2.8.6 list, but went down before 0.2.9 + * "195.191.233.221:80 orport=443 id=DE134FC8E5CC4EC8A5DE66934E70AC9D70267197" + * " weight=10", + */ "46.252.26.2:45212 orport=49991 id=E589316576A399C511A9781A73DA4545640B479D" " weight=10", -"176.31.180.157:143 orport=22 id=E781F4EC69671B3F1864AE2753E0890351506329" -" ipv6=[2001:41d0:8:eb9d::1]:22" -" weight=10", +/* Fallback was on 0.2.8.6 list, but went down before 0.2.9 + * "176.31.180.157:143 orport=22 id=E781F4EC69671B3F1864AE2753E0890351506329" + * " ipv6=[2001:41d0:8:eb9d::1]:22" + * " weight=10", + */ "131.188.40.188:443 orport=80 id=EBE718E1A49EE229071702964F8DB1F318075FF8" " weight=10", "91.219.236.222:80 orport=443 id=EC413181CEB1C8EDC17608BBB177CD5FD8535E99" @@ -256,8 +270,10 @@ URL: https:onionoo.torproject.orguptime?first_seen_days=7-&flag=V2Dir&type=relay " weight=10", "46.101.143.173:80 orport=443 id=F960DF50F0FD4075AC9B505C1D4FFC8384C490FB" " weight=10", -"195.154.8.111:80 orport=443 id=FCB6695F8F2DC240E974510A4B3A0F2B12AB5B64" -" weight=10", +/* Fallback was on 0.2.8.6 list, but changed IPv4 before 0.2.9 + * "195.154.8.111:80 orport=443 id=FCB6695F8F2DC240E974510A4B3A0F2B12AB5B64" + * " weight=10", + */ "192.187.124.98:9030 orport=9001 id=FD1871854BFC06D7B02F10742073069F0528B5CC" " weight=10", "193.11.164.243:9030 orport=9001 id=FFA72BD683BC2FCF988356E6BEC1E490F313FB07" diff --git a/src/or/hibernate.c b/src/or/hibernate.c index 209aae01cf..7e25306234 100644 --- a/src/or/hibernate.c +++ b/src/or/hibernate.c @@ -692,7 +692,7 @@ read_bandwidth_usage(void) int res; res = unlink(fname); - if (res != 0) { + if (res != 0 && errno != ENOENT) { log_warn(LD_FS, "Failed to unlink %s: %s", fname, strerror(errno)); diff --git a/src/or/main.c b/src/or/main.c index c70fa82627..013e301aff 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -2834,11 +2834,6 @@ tor_init(int argc, char *argv[]) "Expect more bugs than usual."); } -#ifdef NON_ANONYMOUS_MODE_ENABLED - log_warn(LD_GENERAL, "This copy of Tor was compiled to run in a " - "non-anonymous mode. It will provide NO ANONYMITY."); -#endif - if (network_init()<0) { log_err(LD_BUG,"Error initializing network; exiting."); return -1; @@ -2850,15 +2845,18 @@ tor_init(int argc, char *argv[]) return -1; } + /* The options are now initialised */ + const or_options_t *options = get_options(); + #ifndef _WIN32 if (geteuid()==0) log_warn(LD_GENERAL,"You are running Tor as root. You don't need to, " "and you probably shouldn't."); #endif - if (crypto_global_init(get_options()->HardwareAccel, - get_options()->AccelName, - get_options()->AccelDir)) { + if (crypto_global_init(options->HardwareAccel, + options->AccelName, + options->AccelDir)) { log_err(LD_BUG, "Unable to initialize OpenSSL. Exiting."); return -1; } diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c index f113777be1..dd8d5789e3 100644 --- a/src/or/networkstatus.c +++ b/src/or/networkstatus.c @@ -1819,7 +1819,9 @@ networkstatus_set_current_consensus(const char *consensus, if (r != 1 && dl_certs) authority_certs_fetch_missing(c, now, source_dir); - if (flav == usable_consensus_flavor()) { + const int is_usable_flavor = flav == usable_consensus_flavor(); + + if (is_usable_flavor) { notify_control_networkstatus_changed(current_consensus, c); } if (flav == FLAV_NS) { @@ -1862,20 +1864,12 @@ networkstatus_set_current_consensus(const char *consensus, } } - /* Reset the failure count only if this consensus is actually valid. */ - if (c->valid_after <= now && now <= c->valid_until) { - download_status_reset(&consensus_dl_status[flav]); - } else { - if (!from_cache) - download_status_failed(&consensus_dl_status[flav], 0); - } + if (is_usable_flavor) { + nodelist_set_consensus(c); - if (flav == usable_consensus_flavor()) { /* XXXXNM Microdescs: needs a non-ns variant. ???? NM*/ update_consensus_networkstatus_fetch_time(now); - nodelist_set_consensus(current_consensus); - dirvote_recalculate_timing(options, now); routerstatus_list_update_named_server_map(); @@ -1899,6 +1893,14 @@ networkstatus_set_current_consensus(const char *consensus, current_consensus); } + /* Reset the failure count only if this consensus is actually valid. */ + if (c->valid_after <= now && now <= c->valid_until) { + download_status_reset(&consensus_dl_status[flav]); + } else { + if (!from_cache) + download_status_failed(&consensus_dl_status[flav], 0); + } + if (directory_caches_dir_info(options)) { dirserv_set_cached_consensus_networkstatus(consensus, flavor, diff --git a/src/or/or.h b/src/or/or.h index 7c7163f035..66717792b4 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -1151,6 +1151,8 @@ typedef struct entry_port_cfg_t { unsigned int ipv4_traffic : 1; unsigned int ipv6_traffic : 1; unsigned int prefer_ipv6 : 1; + unsigned int dns_request : 1; + unsigned int onion_traffic : 1; /** For a socks listener: should we cache IPv4/IPv6 DNS information that * exit nodes tell us? @@ -3618,9 +3620,13 @@ typedef struct { /** @name port booleans * - * Derived booleans: True iff there is a non-listener port on an AF_INET or - * AF_INET6 address of the given type configured in one of the _lines - * options above. + * Derived booleans: For server ports and ControlPort, true iff there is a + * non-listener port on an AF_INET or AF_INET6 address of the given type + * configured in one of the _lines options above. + * For client ports, also true if there is a unix socket configured. + * If you are checking for client ports, you may want to use: + * SocksPort_set || TransPort_set || NATDPort_set || DNSPort_set + * rather than SocksPort_set. * * @{ */ @@ -3711,6 +3717,26 @@ typedef struct { * they reach the normal circuit-build timeout. */ int CloseHSServiceRendCircuitsImmediatelyOnTimeout; + /** Onion Services in HiddenServiceSingleHopMode make one-hop (direct) + * circuits between the onion service server, and the introduction and + * 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. + * HiddenServiceSingleHopMode requires HiddenServiceNonAnonymousMode to be + * set to 1. + * Use rend_service_allow_non_anonymous_connection() or + * rend_service_reveal_startup_time() instead of using this option directly. + */ + int HiddenServiceSingleHopMode; + /* Makes hidden service clients and servers non-anonymous on this tor + * instance. Allows the non-anonymous HiddenServiceSingleHopMode. Enables + * non-anonymous behaviour in the hidden service protocol. + * Use rend_service_non_anonymous_mode_enabled() instead of using this option + * directly. + */ + int HiddenServiceNonAnonymousMode; + int ConnLimit; /**< Demanded minimum number of simultaneous connections. */ int ConnLimit_; /**< Maximum allowed number of simultaneous connections. */ int ConnLimit_high_thresh; /**< start trying to lower socket usage if we @@ -3766,7 +3792,8 @@ typedef struct { * unattached before we fail it? */ int LearnCircuitBuildTimeout; /**< If non-zero, we attempt to learn a value * for CircuitBuildTimeout based on timeout - * history */ + * history. Use circuit_build_times_disabled() + * rather than checking this value directly. */ int CircuitBuildTimeout; /**< Cull non-open circuits that were born at * least this many seconds ago. Used until * adaptive algorithm learns a new value. */ @@ -3952,8 +3979,16 @@ typedef struct { int TokenBucketRefillInterval; char *AccelName; /**< Optional hardware acceleration engine name. */ char *AccelDir; /**< Optional hardware acceleration engine search dir. */ - int UseEntryGuards; /**< Boolean: Do we try to enter from a smallish number - * of fixed nodes? */ + + /** Boolean: Do we try to enter from a smallish number + * of fixed nodes? */ + int UseEntryGuards_option; + /** Internal variable to remember whether we're actually acting on + * UseEntryGuards_option -- when we're a non-anonymous Tor2web client or + * Single Onion Service, it is alwasy false, otherwise we use the value of + * UseEntryGuards_option. */ + int UseEntryGuards; + int NumEntryGuards; /**< How many entry guards do we try to establish? */ int UseEntryGuardsAsDirGuards; /** Boolean: Do we try to get directory info * from a smallish number of fixed nodes? */ @@ -5066,7 +5101,8 @@ typedef struct rend_encoded_v2_service_descriptor_t { * the service side) and in rend_service_descriptor_t (on both the * client and service side). */ typedef struct rend_intro_point_t { - extend_info_t *extend_info; /**< Extend info of this introduction point. */ + extend_info_t *extend_info; /**< Extend info for connecting to this + * introduction point via a multi-hop path. */ crypto_pk_t *intro_key; /**< Introduction key that replaces the service * key, if this descriptor is V2. */ diff --git a/src/or/policies.c b/src/or/policies.c index 07f256f5cc..44a46d2fe2 100644 --- a/src/or/policies.c +++ b/src/or/policies.c @@ -2119,8 +2119,10 @@ exit_policy_is_general_exit_helper(smartlist_t *policy, int port) if (subnet_status[i] != 0) continue; /* We already reject some part of this /8 */ tor_addr_from_ipv4h(&addr, i<<24); - if (tor_addr_is_internal(&addr, 0)) + if (tor_addr_is_internal(&addr, 0) && + !get_options()->DirAllowPrivateAddresses) { continue; /* Local or non-routable addresses */ + } if (p->policy_type == ADDR_POLICY_ACCEPT) { if (p->maskbits > 8) continue; /* Narrower than a /8. */ diff --git a/src/or/relay.c b/src/or/relay.c index 38096ad1bb..1794215378 100644 --- a/src/or/relay.c +++ b/src/or/relay.c @@ -2454,7 +2454,7 @@ update_circuit_on_cmux_(circuit_t *circ, cell_direction_t direction, /* Cmux sanity check */ if (! circuitmux_is_circuit_attached(cmux, circ)) { - log_warn(LD_BUG, "called on non-attachd circuit from %s:%d", + log_warn(LD_BUG, "called on non-attached circuit from %s:%d", file, lineno); return; } @@ -2613,6 +2613,15 @@ channel_flush_from_first_active_circuit, (channel_t *chan, int max)) } /* Circuitmux told us this was active, so it should have cells */ + if (/*BUG(*/ queue->n == 0 /*)*/) { + log_warn(LD_BUG, "Found a supposedly active circuit with no cells " + "to send. Trying to recover."); + circuitmux_set_num_cells(cmux, circ, 0); + if (! circ->marked_for_close) + circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL); + continue; + } + tor_assert(queue->n > 0); /* diff --git a/src/or/rendclient.c b/src/or/rendclient.c index 3a742fec0a..a93bc94a9c 100644 --- a/src/or/rendclient.c +++ b/src/or/rendclient.c @@ -134,6 +134,7 @@ int rend_client_send_introduction(origin_circuit_t *introcirc, origin_circuit_t *rendcirc) { + const or_options_t *options = get_options(); size_t payload_len; int r, v3_shift = 0; char payload[RELAY_PAYLOAD_SIZE]; @@ -150,10 +151,8 @@ rend_client_send_introduction(origin_circuit_t *introcirc, tor_assert(rendcirc->rend_data); tor_assert(!rend_cmp_service_ids(introcirc->rend_data->onion_address, rendcirc->rend_data->onion_address)); -#ifndef NON_ANONYMOUS_MODE_ENABLED - tor_assert(!(introcirc->build_state->onehop_tunnel)); - tor_assert(!(rendcirc->build_state->onehop_tunnel)); -#endif + assert_circ_anonymity_ok(introcirc, options); + assert_circ_anonymity_ok(rendcirc, options); r = rend_cache_lookup_entry(introcirc->rend_data->onion_address, -1, &entry); @@ -387,6 +386,7 @@ int rend_client_introduction_acked(origin_circuit_t *circ, const uint8_t *request, size_t request_len) { + const or_options_t *options = get_options(); origin_circuit_t *rendcirc; (void) request; // XXXX Use this. @@ -398,10 +398,9 @@ rend_client_introduction_acked(origin_circuit_t *circ, return -1; } + tor_assert(circ->build_state); tor_assert(circ->build_state->chosen_exit); -#ifndef NON_ANONYMOUS_MODE_ENABLED - tor_assert(!(circ->build_state->onehop_tunnel)); -#endif + assert_circ_anonymity_ok(circ, options); tor_assert(circ->rend_data); /* For path bias: This circuit was used successfully. Valid @@ -416,9 +415,7 @@ rend_client_introduction_acked(origin_circuit_t *circ, log_info(LD_REND,"Received ack. Telling rend circ..."); rendcirc = circuit_get_ready_rend_circ_by_rend_data(circ->rend_data); if (rendcirc) { /* remember the ack */ -#ifndef NON_ANONYMOUS_MODE_ENABLED - tor_assert(!(rendcirc->build_state->onehop_tunnel)); -#endif + assert_circ_anonymity_ok(rendcirc, options); circuit_change_purpose(TO_CIRCUIT(rendcirc), CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED); /* Set timestamp_dirty, because circuit_expire_building expects @@ -1373,40 +1370,15 @@ rend_client_get_random_intro_impl(const rend_cache_entry_t *entry, smartlist_del(usable_nodes, i); goto again; } - /* Do we need to look up the router or is the extend info complete? */ + /* All version 2 HS descriptors come with a TAP onion key. + * Clients used to try to get the TAP onion key from the consensus, but this + * meant that hidden services could discover which consensus clients have. */ if (!extend_info_supports_tap(intro->extend_info)) { - const node_t *node; - extend_info_t *new_extend_info; - if (tor_digest_is_zero(intro->extend_info->identity_digest)) - node = node_get_by_hex_id(intro->extend_info->nickname); - else - node = node_get_by_id(intro->extend_info->identity_digest); - if (!node) { - log_info(LD_REND, "Unknown router with nickname '%s'; trying another.", - intro->extend_info->nickname); - smartlist_del(usable_nodes, i); - goto again; - } -#ifdef ENABLE_TOR2WEB_MODE - new_extend_info = extend_info_from_node(node, options->Tor2webMode); -#else - new_extend_info = extend_info_from_node(node, 0); -#endif - if (!new_extend_info) { - const char *alternate_reason = ""; -#ifdef ENABLE_TOR2WEB_MODE - alternate_reason = ", or we cannot connect directly to it"; -#endif - log_info(LD_REND, "We don't have a descriptor for the intro-point relay " - "'%s'%s; trying another.", - extend_info_describe(intro->extend_info), alternate_reason); - smartlist_del(usable_nodes, i); - goto again; - } else { - extend_info_free(intro->extend_info); - intro->extend_info = new_extend_info; - } - tor_assert(intro->extend_info != NULL); + log_info(LD_REND, "The HS descriptor is missing a TAP onion key for the " + "intro-point relay '%s'; trying another.", + safe_str_client(extend_info_describe(intro->extend_info))); + smartlist_del(usable_nodes, i); + goto again; } /* Check if we should refuse to talk to this router. */ if (strict && @@ -1552,3 +1524,35 @@ rend_parse_service_authorization(const or_options_t *options, return res; } +/* Can Tor client code make direct (non-anonymous) connections to introduction + * or rendezvous points? + * Returns true if tor was compiled with NON_ANONYMOUS_MODE_ENABLED, and is + * configured in Tor2web mode. */ +int +rend_client_allow_non_anonymous_connection(const or_options_t *options) +{ + /* Tor2web support needs to be compiled in to a tor binary. */ +#ifdef NON_ANONYMOUS_MODE_ENABLED + /* Tor2web */ + return options->Tor2webMode ? 1 : 0; +#else + (void)options; + return 0; +#endif +} + +/* At compile-time, was non-anonymous mode enabled via + * NON_ANONYMOUS_MODE_ENABLED ? */ +int +rend_client_non_anonymous_mode_enabled(const or_options_t *options) +{ + (void)options; + /* Tor2web support needs to be compiled in to a tor binary. */ +#ifdef NON_ANONYMOUS_MODE_ENABLED + /* Tor2web */ + return 1; +#else + return 0; +#endif +} + diff --git a/src/or/rendclient.h b/src/or/rendclient.h index e90dac07ab..b8f8c2f871 100644 --- a/src/or/rendclient.h +++ b/src/or/rendclient.h @@ -51,5 +51,8 @@ rend_service_authorization_t *rend_client_lookup_service_authorization( const char *onion_address); void rend_service_authorization_free_all(void); +int rend_client_allow_non_anonymous_connection(const or_options_t *options); +int rend_client_non_anonymous_mode_enabled(const or_options_t *options); + #endif diff --git a/src/or/rendcommon.c b/src/or/rendcommon.c index 01b0766cf0..d9d39b1f19 100644 --- a/src/or/rendcommon.c +++ b/src/or/rendcommon.c @@ -1067,3 +1067,52 @@ rend_auth_decode_cookie(const char *cookie_in, uint8_t *cookie_out, return res; } +/* Is this a rend client or server that allows direct (non-anonymous) + * connections? + * Clients must be specifically compiled and configured in this mode. + * Onion services can be configured to start in this mode. + * Prefer rend_client_allow_non_anonymous_connection() or + * rend_service_allow_non_anonymous_connection() whenever possible, so that + * checks are specific to Single Onion Services or Tor2web. */ +int +rend_allow_non_anonymous_connection(const or_options_t* options) +{ + return (rend_client_allow_non_anonymous_connection(options) + || rend_service_allow_non_anonymous_connection(options)); +} + +/* Is this a rend client or server in non-anonymous mode? + * Clients must be specifically compiled in this mode. + * Onion services can be configured to start in this mode. + * Prefer rend_client_non_anonymous_mode_enabled() or + * rend_service_non_anonymous_mode_enabled() whenever possible, so that checks + * are specific to Single Onion Services or Tor2web. */ +int +rend_non_anonymous_mode_enabled(const or_options_t *options) +{ + return (rend_client_non_anonymous_mode_enabled(options) + || rend_service_non_anonymous_mode_enabled(options)); +} + +/* Make sure that tor only builds one-hop circuits when they would not + * compromise user anonymity. + * + * One-hop circuits are permitted in Tor2web or Single Onion modes. + * + * 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, + const or_options_t *options) +{ + tor_assert(options); + tor_assert(circ); + tor_assert(circ->build_state); + + if (circ->build_state->onehop_tunnel) { + tor_assert(rend_allow_non_anonymous_connection(options)); + } +} + diff --git a/src/or/rendcommon.h b/src/or/rendcommon.h index 88cf512f4a..090e6f25e0 100644 --- a/src/or/rendcommon.h +++ b/src/or/rendcommon.h @@ -77,5 +77,11 @@ int rend_auth_decode_cookie(const char *cookie_in, rend_auth_type_t *auth_type_out, char **err_msg_out); +int rend_allow_non_anonymous_connection(const or_options_t* options); +int rend_non_anonymous_mode_enabled(const or_options_t *options); + +void assert_circ_anonymity_ok(origin_circuit_t *circ, + const or_options_t *options); + #endif diff --git a/src/or/rendservice.c b/src/or/rendservice.c index 4ad35059f1..114a56b74e 100644 --- a/src/or/rendservice.c +++ b/src/or/rendservice.c @@ -20,6 +20,7 @@ #include "main.h" #include "networkstatus.h" #include "nodelist.h" +#include "policies.h" #include "rendclient.h" #include "rendcommon.h" #include "rendservice.h" @@ -107,59 +108,13 @@ struct rend_service_port_config_s { * rendezvous point before giving up? */ #define MAX_REND_TIMEOUT 30 -/** Represents a single hidden service running at this OP. */ -typedef struct rend_service_t { - /* Fields specified in config file */ - char *directory; /**< where in the filesystem it stores it. Will be NULL if - * this service is ephemeral. */ - int dir_group_readable; /**< if 1, allow group read - permissions on directory */ - smartlist_t *ports; /**< List of rend_service_port_config_t */ - rend_auth_type_t auth_type; /**< Client authorization type or 0 if no client - * authorization is performed. */ - smartlist_t *clients; /**< List of rend_authorized_client_t's of - * clients that may access our service. Can be NULL - * if no client authorization is performed. */ - /* Other fields */ - crypto_pk_t *private_key; /**< Permanent hidden-service key. */ - char service_id[REND_SERVICE_ID_LEN_BASE32+1]; /**< Onion address without - * '.onion' */ - char pk_digest[DIGEST_LEN]; /**< Hash of permanent hidden-service key. */ - smartlist_t *intro_nodes; /**< List of rend_intro_point_t's we have, - * or are trying to establish. */ - /** List of rend_intro_point_t that are expiring. They are removed once - * the new descriptor is successfully uploaded. A node in this list CAN - * NOT appear in the intro_nodes list. */ - smartlist_t *expiring_nodes; - time_t intro_period_started; /**< Start of the current period to build - * introduction points. */ - int n_intro_circuits_launched; /**< Count of intro circuits we have - * established in this period. */ - unsigned int n_intro_points_wanted; /**< Number of intro points this - * service wants to have open. */ - rend_service_descriptor_t *desc; /**< Current hidden service descriptor. */ - time_t desc_is_dirty; /**< Time at which changes to the hidden service - * descriptor content occurred, or 0 if it's - * up-to-date. */ - time_t next_upload_time; /**< Scheduled next hidden service descriptor - * upload time. */ - /** Replay cache for Diffie-Hellman values of INTRODUCE2 cells, to - * detect repeats. Clients may send INTRODUCE1 cells for the same - * rendezvous point through two or more different introduction points; - * when they do, this keeps us from launching multiple simultaneous attempts - * to connect to the same rend point. */ - replaycache_t *accepted_intro_dh_parts; - /** If true, we don't close circuits for making requests to unsupported - * ports. */ - int allow_unknown_ports; - /** The maximum number of simultanious streams-per-circuit that are allowed - * to be established, or 0 if no limit is set. - */ - int max_streams_per_circuit; - /** If true, we close circuits that exceed the max_streams_per_circuit - * limit. */ - int max_streams_close_circuit; -} rend_service_t; +/* Hidden service directory file names: + * new file names should be added to rend_service_add_filenames_to_list() + * for sandboxing purposes. */ +static const char *private_key_fname = "private_key"; +static const char *hostname_fname = "hostname"; +static const char *client_keys_fname = "client_keys"; +static const char *sos_poison_fname = "onion_service_non_anonymous"; /** Returns a escaped string representation of the service, <b>s</b>. */ @@ -206,16 +161,18 @@ rend_authorized_client_strmap_item_free(void *authorized_client) /** Release the storage held by <b>service</b>. */ -static void +STATIC void rend_service_free(rend_service_t *service) { if (!service) return; tor_free(service->directory); - SMARTLIST_FOREACH(service->ports, rend_service_port_config_t*, p, - rend_service_port_config_free(p)); - smartlist_free(service->ports); + if (service->ports) { + SMARTLIST_FOREACH(service->ports, rend_service_port_config_t*, p, + rend_service_port_config_free(p)); + smartlist_free(service->ports); + } if (service->private_key) crypto_pk_free(service->private_key); if (service->intro_nodes) { @@ -508,7 +465,7 @@ rend_config_services(const or_options_t *options, int validate_only) if (!strcasecmp(line->key, "HiddenServiceDir")) { if (service) { /* register the one we just finished parsing */ if (validate_only) - rend_service_free(service); + rend_service_free(service); else rend_add_service(service); } @@ -1001,13 +958,235 @@ rend_service_update_descriptor(rend_service_t *service) } } +/* Allocate and return a string containing the path to file_name in + * service->directory. Asserts that service has a directory. + * This function will never return NULL. + * The caller must free this path. */ +static char * +rend_service_path(const rend_service_t *service, const char *file_name) +{ + char *file_path = NULL; + + tor_assert(service->directory); + + /* Can never fail: asserts rather than leaving file_path NULL. */ + tor_asprintf(&file_path, "%s%s%s", + service->directory, PATH_SEPARATOR, file_name); + + return file_path; +} + +/* Allocate and return a string containing the path to the single onion + * service poison file in service->directory. Asserts that service has a + * directory. + * The caller must free this path. */ +STATIC char * +rend_service_sos_poison_path(const rend_service_t *service) +{ + return rend_service_path(service, sos_poison_fname); +} + +/** Return True if hidden services <b>service> has been poisoned by single + * onion mode. */ +static int +service_is_single_onion_poisoned(const rend_service_t *service) +{ + char *poison_fname = NULL; + file_status_t fstatus; + + if (!service->directory) { + return 0; + } + + poison_fname = rend_service_sos_poison_path(service); + + fstatus = file_status(poison_fname); + tor_free(poison_fname); + + /* If this fname is occupied, the hidden service has been poisoned. */ + if (fstatus == FN_FILE || fstatus == FN_EMPTY) { + return 1; + } + + return 0; +} + +/* Return 1 if the private key file for service exists and has a non-zero size, + * and 0 otherwise. */ +static int +rend_service_private_key_exists(const rend_service_t *service) +{ + char *private_key_path = rend_service_path(service, private_key_fname); + const file_status_t private_key_status = file_status(private_key_path); + tor_free(private_key_path); + /* Only non-empty regular private key files could have been used before. */ + return private_key_status == FN_FILE; +} + +/** Check the single onion service poison state of all existing hidden service + * directories: + * - 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, + * - 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. + * When their keys are created, they will be poisoned (if needed). + * If a <b>service_list</b> is provided, treat it + * as the list of hidden services (used in unittests). */ +int +rend_service_list_verify_single_onion_poison(const smartlist_t *service_list, + const or_options_t *options) +{ + const smartlist_t *s_list; + /* If no special service list is provided, then just use the global one. */ + if (!service_list) { + if (!rend_service_list) { /* No global HS list. Nothing to see here. */ + return 0; + } + + s_list = rend_service_list; + } else { + s_list = service_list; + } + + int consistent = 1; + SMARTLIST_FOREACH_BEGIN(s_list, const rend_service_t *, s) { + if (service_is_single_onion_poisoned(s) != + rend_service_non_anonymous_mode_enabled(options) && + rend_service_private_key_exists(s)) { + consistent = 0; + } + } SMARTLIST_FOREACH_END(s); + + return consistent ? 0 : -1; +} + +/*** 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_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 non-anonymous mode."); + return 0; + } + + /* Make sure we're only poisoning new hidden service directories */ + if (rend_service_private_key_exists(service)) { + log_warn(LD_BUG, "Tried to single onion poison a service directory after " + "the private key was created."); + return -1; + } + + poison_fname = rend_service_sos_poison_path(service); + + switch (file_status(poison_fname)) { + case FN_DIR: + case FN_ERROR: + log_warn(LD_FS, "Can't read single onion poison file \"%s\"", + poison_fname); + goto done; + case FN_FILE: /* single onion poison file already exists. NOP. */ + case FN_EMPTY: /* single onion poison file already exists. NOP. */ + log_debug(LD_FS, "Tried to re-poison a single onion poisoned file \"%s\"", + poison_fname); + break; + case FN_NOENT: + fd = tor_open_cloexec(poison_fname, O_RDWR|O_CREAT|O_TRUNC, 0600); + if (fd < 0) { + log_warn(LD_FS, "Could not create single onion poison file %s", + poison_fname); + goto done; + } + close(fd); + break; + default: + tor_assert(0); + } + + retval = 0; + + done: + tor_free(poison_fname); + + return retval; +} + +/** 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 + * key files.) + * If a <b>service_list</b> is provided, treat it as the list of hidden + * services (used in unittests). + * Return 0 on success, -1 on fail. */ +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_non_anonymous_mode_enabled(get_options())); + + const smartlist_t *s_list; + /* If no special service list is provided, then just use the global one. */ + if (!service_list) { + if (!rend_service_list) { /* No global HS list. Nothing to see here. */ + return 0; + } + + s_list = rend_service_list; + } else { + s_list = service_list; + } + + SMARTLIST_FOREACH_BEGIN(s_list, const rend_service_t *, s) { + if (!rend_service_private_key_exists(s)) { + if (poison_new_single_onion_hidden_service_dir(s) < 0) { + return -1; + } + } + } SMARTLIST_FOREACH_END(s); + + /* The keys for these services are linked to the server IP address */ + log_notice(LD_REND, "The configured onion service directories have been " + "used in single onion mode. They can not be used for anonymous " + "hidden services."); + + return 0; +} + /** Load and/or generate private keys for all hidden services, possibly - * including keys for client authorization. Return 0 on success, -1 on - * failure. */ + * including keys for client authorization. + * If a <b>service_list</b> is provided, treat it as the list of hidden + * services (used in unittests). Otherwise, require that rend_service_list is + * not NULL. + * Return 0 on success, -1 on failure. */ int -rend_service_load_all_keys(void) +rend_service_load_all_keys(const smartlist_t *service_list) { - SMARTLIST_FOREACH_BEGIN(rend_service_list, rend_service_t *, s) { + const smartlist_t *s_list; + /* If no special service list is provided, then just use the global one. */ + if (!service_list) { + tor_assert(rend_service_list); + s_list = rend_service_list; + } else { + s_list = service_list; + } + + SMARTLIST_FOREACH_BEGIN(s_list, rend_service_t *, s) { if (s->private_key) continue; log_info(LD_REND, "Loading hidden-service keys from \"%s\"", @@ -1027,12 +1206,10 @@ rend_service_add_filenames_to_list(smartlist_t *lst, const rend_service_t *s) tor_assert(lst); tor_assert(s); tor_assert(s->directory); - smartlist_add_asprintf(lst, "%s"PATH_SEPARATOR"private_key", - s->directory); - smartlist_add_asprintf(lst, "%s"PATH_SEPARATOR"hostname", - s->directory); - smartlist_add_asprintf(lst, "%s"PATH_SEPARATOR"client_keys", - s->directory); + smartlist_add(lst, rend_service_path(s, private_key_fname)); + smartlist_add(lst, rend_service_path(s, hostname_fname)); + smartlist_add(lst, rend_service_path(s, client_keys_fname)); + smartlist_add(lst, rend_service_sos_poison_path(s)); } /** Add to <b>open_lst</b> every filename used by a configured hidden service, @@ -1076,7 +1253,7 @@ rend_service_derive_key_digests(struct rend_service_t *s) static int rend_service_load_keys(rend_service_t *s) { - char fname[512]; + char *fname = NULL; char buf[128]; cpd_check_t check_opts = CPD_CREATE; @@ -1085,7 +1262,7 @@ rend_service_load_keys(rend_service_t *s) } /* Check/create directory */ if (check_private_dir(s->directory, check_opts, get_options()->User) < 0) { - return -1; + goto err; } #ifndef _WIN32 if (s->dir_group_readable) { @@ -1097,34 +1274,23 @@ rend_service_load_keys(rend_service_t *s) #endif /* Load key */ - if (strlcpy(fname,s->directory,sizeof(fname)) >= sizeof(fname) || - strlcat(fname,PATH_SEPARATOR"private_key",sizeof(fname)) - >= sizeof(fname)) { - log_warn(LD_CONFIG, "Directory name too long to store key file: \"%s\".", - s->directory); - return -1; - } + fname = rend_service_path(s, private_key_fname); s->private_key = init_key_from_file(fname, 1, LOG_ERR, 0); + if (!s->private_key) - return -1; + goto err; if (rend_service_derive_key_digests(s) < 0) - return -1; + goto err; + tor_free(fname); /* Create service file */ - if (strlcpy(fname,s->directory,sizeof(fname)) >= sizeof(fname) || - strlcat(fname,PATH_SEPARATOR"hostname",sizeof(fname)) - >= sizeof(fname)) { - log_warn(LD_CONFIG, "Directory name too long to store hostname file:" - " \"%s\".", s->directory); - return -1; - } + fname = rend_service_path(s, hostname_fname); tor_snprintf(buf, sizeof(buf),"%s.onion\n", s->service_id); if (write_str_to_file(fname,buf,0)<0) { log_warn(LD_CONFIG, "Could not write onion address to hostname file."); - memwipe(buf, 0, sizeof(buf)); - return -1; + goto err; } #ifndef _WIN32 if (s->dir_group_readable) { @@ -1135,15 +1301,21 @@ rend_service_load_keys(rend_service_t *s) } #endif - memwipe(buf, 0, sizeof(buf)); - /* If client authorization is configured, load or generate keys. */ if (s->auth_type != REND_NO_AUTH) { - if (rend_service_load_auth_keys(s, fname) < 0) - return -1; + if (rend_service_load_auth_keys(s, fname) < 0) { + goto err; + } } - return 0; + int r = 0; + goto done; + err: + r = -1; + done: + memwipe(buf, 0, sizeof(buf)); + tor_free(fname); + return r; } /** Load and/or generate client authorization keys for the hidden service @@ -1153,7 +1325,7 @@ static int rend_service_load_auth_keys(rend_service_t *s, const char *hfname) { int r = 0; - char cfname[512]; + char *cfname = NULL; char *client_keys_str = NULL; strmap_t *parsed_clients = strmap_new(); FILE *cfile, *hfile; @@ -1163,12 +1335,7 @@ rend_service_load_auth_keys(rend_service_t *s, const char *hfname) char buf[1500]; /* Load client keys and descriptor cookies, if available. */ - if (tor_snprintf(cfname, sizeof(cfname), "%s"PATH_SEPARATOR"client_keys", - s->directory)<0) { - log_warn(LD_CONFIG, "Directory name too long to store client keys " - "file: \"%s\".", s->directory); - goto err; - } + cfname = rend_service_path(s, client_keys_fname); client_keys_str = read_file_to_str(cfname, RFTS_IGNORE_MISSING, NULL); if (client_keys_str) { if (rend_parse_client_keys(parsed_clients, client_keys_str) < 0) { @@ -1322,7 +1489,10 @@ rend_service_load_auth_keys(rend_service_t *s, const char *hfname) } strmap_free(parsed_clients, rend_authorized_client_strmap_item_free); - memwipe(cfname, 0, sizeof(cfname)); + if (cfname) { + memwipe(cfname, 0, strlen(cfname)); + tor_free(cfname); + } /* Clear stack buffers that held key-derived material. */ memwipe(buf, 0, sizeof(buf)); @@ -1424,6 +1594,31 @@ rend_check_authorization(rend_service_t *service, return 1; } +/* Can this service make a direct connection to ei? + * It must be a single onion service, and the firewall rules must allow ei. */ +static int +rend_service_use_direct_connection(const or_options_t* options, + const extend_info_t* ei) +{ + /* We'll connect directly all reachable addresses, whether preferred or not. + * The prefer_ipv6 argument to fascist_firewall_allows_address_addr is + * ignored, because pref_only is 0. */ + return (rend_service_allow_non_anonymous_connection(options) && + fascist_firewall_allows_address_addr(&ei->addr, ei->port, + FIREWALL_OR_CONNECTION, 0, 0)); +} + +/* Like rend_service_use_direct_connection, but to a node. */ +static int +rend_service_use_direct_connection_node(const or_options_t* options, + const node_t* node) +{ + /* We'll connect directly all reachable addresses, whether preferred or not. + */ + return (rend_service_allow_non_anonymous_connection(options) && + fascist_firewall_allows_node(node, FIREWALL_OR_CONNECTION, 0)); +} + /****** * Handle cells ******/ @@ -1473,9 +1668,7 @@ rend_service_receive_introduction(origin_circuit_t *circuit, goto err; } -#ifndef NON_ANONYMOUS_MODE_ENABLED - tor_assert(!(circuit->build_state->onehop_tunnel)); -#endif + assert_circ_anonymity_ok(circuit, options); tor_assert(circuit->rend_data); /* We'll use this in a bazillion log messages */ @@ -1679,6 +1872,11 @@ rend_service_receive_introduction(origin_circuit_t *circuit, for (i=0;i<MAX_REND_FAILURES;i++) { int flags = CIRCLAUNCH_NEED_CAPACITY | CIRCLAUNCH_IS_INTERNAL; if (circ_needs_uptime) flags |= CIRCLAUNCH_NEED_UPTIME; + /* A Single Onion Service only uses a direct connection if its + * firewall rules permit direct connections to the address. */ + if (rend_service_use_direct_connection(options, rp)) { + flags = flags | CIRCLAUNCH_ONEHOP_TUNNEL; + } launched = circuit_launch_by_extend_info( CIRCUIT_PURPOSE_S_CONNECT_REND, rp, flags); @@ -1791,7 +1989,10 @@ find_rp_for_intro(const rend_intro_cell_t *intro, goto err; } - rp = extend_info_from_node(node, 0); + /* Are we in single onion mode? */ + const int allow_direct = rend_service_allow_non_anonymous_connection( + get_options()); + rp = extend_info_from_node(node, allow_direct); if (!rp) { if (err_msg_out) { tor_asprintf(&err_msg, @@ -1816,6 +2017,10 @@ find_rp_for_intro(const rend_intro_cell_t *intro, goto err; } + /* rp is always set here: extend_info_dup guarantees a non-NULL result, and + * the other cases goto err. */ + tor_assert(rp); + /* Make sure the RP we are being asked to connect to is _not_ a private * address unless it's allowed. Let's avoid to build a circuit to our * second middle node and fail right after when extending to the RP. */ @@ -2590,6 +2795,10 @@ rend_service_relaunch_rendezvous(origin_circuit_t *oldcirc) log_info(LD_REND,"Reattempting rendezvous circuit to '%s'", safe_str(extend_info_describe(oldstate->chosen_exit))); + /* You'd think Single Onion Services would want to retry the rendezvous + * using a direct connection. But if it's blocked by a firewall, or the + * service is IPv6-only, or the rend point avoiding becoming a one-hop + * proxy, we need a 3-hop connection. */ newcirc = circuit_launch_by_extend_info(CIRCUIT_PURPOSE_S_CONNECT_REND, oldstate->chosen_exit, CIRCLAUNCH_NEED_CAPACITY|CIRCLAUNCH_IS_INTERNAL); @@ -2618,26 +2827,72 @@ rend_service_launch_establish_intro(rend_service_t *service, rend_intro_point_t *intro) { origin_circuit_t *launched; + int flags = CIRCLAUNCH_NEED_UPTIME|CIRCLAUNCH_IS_INTERNAL; + const or_options_t *options = get_options(); + extend_info_t *launch_ei = intro->extend_info; + extend_info_t *direct_ei = NULL; + + /* Are we in single onion mode? */ + if (rend_service_allow_non_anonymous_connection(options)) { + /* Do we have a descriptor for the node? + * We've either just chosen it from the consensus, or we've just reviewed + * our intro points to see which ones are still valid, and deleted the ones + * that aren't in the consensus any more. */ + const node_t *node = node_get_by_id(launch_ei->identity_digest); + if (BUG(!node)) { + /* The service has kept an intro point after it went missing from the + * consensus. If we did anything else here, it would be a consensus + * distinguisher. Which are less of an issue for single onion services, + * but still a bug. */ + return -1; + } + /* Can we connect to the node directly? If so, replace launch_ei + * (a multi-hop extend_info) with one suitable for direct connection. */ + if (rend_service_use_direct_connection_node(options, node)) { + direct_ei = extend_info_from_node(node, 1); + if (BUG(!direct_ei)) { + /* rend_service_use_direct_connection_node and extend_info_from_node + * disagree about which addresses on this node are permitted. This + * should never happen. Avoiding the connection is a safe response. */ + return -1; + } + flags = flags | CIRCLAUNCH_ONEHOP_TUNNEL; + launch_ei = direct_ei; + } + } + /* launch_ei is either intro->extend_info, or has been replaced with a valid + * extend_info for single onion service direct connection. */ + tor_assert(launch_ei); + /* We must have the same intro when making a direct connection. */ + tor_assert(tor_memeq(intro->extend_info->identity_digest, + launch_ei->identity_digest, + DIGEST_LEN)); log_info(LD_REND, - "Launching circuit to introduction point %s for service %s", + "Launching circuit to introduction point %s%s%s for service %s", safe_str_client(extend_info_describe(intro->extend_info)), + direct_ei ? " via direct address " : "", + direct_ei ? safe_str_client(extend_info_describe(direct_ei)) : "", service->service_id); rep_hist_note_used_internal(time(NULL), 1, 0); ++service->n_intro_circuits_launched; launched = circuit_launch_by_extend_info(CIRCUIT_PURPOSE_S_ESTABLISH_INTRO, - intro->extend_info, - CIRCLAUNCH_NEED_UPTIME|CIRCLAUNCH_IS_INTERNAL); + launch_ei, flags); if (!launched) { log_info(LD_REND, - "Can't launch circuit to establish introduction at %s.", - safe_str_client(extend_info_describe(intro->extend_info))); + "Can't launch circuit to establish introduction at %s%s%s.", + safe_str_client(extend_info_describe(intro->extend_info)), + direct_ei ? " via direct address " : "", + direct_ei ? safe_str_client(extend_info_describe(direct_ei)) : "" + ); + extend_info_free(direct_ei); return -1; } - /* We must have the same exit node even if cannibalized. */ + /* We must have the same exit node even if cannibalized or direct connection. + */ tor_assert(tor_memeq(intro->extend_info->identity_digest, launched->build_state->chosen_exit->identity_digest, DIGEST_LEN)); @@ -2648,6 +2903,7 @@ rend_service_launch_establish_intro(rend_service_t *service, launched->intro_key = crypto_pk_dup_key(intro->intro_key); if (launched->base_.state == CIRCUIT_STATE_OPEN) rend_service_intro_has_opened(launched); + extend_info_free(direct_ei); return 0; } @@ -2703,9 +2959,7 @@ rend_service_intro_has_opened(origin_circuit_t *circuit) int reason = END_CIRC_REASON_TORPROTOCOL; tor_assert(circuit->base_.purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO); -#ifndef NON_ANONYMOUS_MODE_ENABLED - tor_assert(!(circuit->build_state->onehop_tunnel)); -#endif + assert_circ_anonymity_ok(circuit, get_options()); tor_assert(circuit->cpath); tor_assert(circuit->rend_data); @@ -2772,6 +3026,7 @@ rend_service_intro_has_opened(origin_circuit_t *circuit) log_info(LD_REND, "Established circuit %u as introduction point for service %s", (unsigned)circuit->base_.n_circ_id, serviceid); + circuit_log_path(LOG_INFO, LD_REND, circuit); /* Use the intro key instead of the service key in ESTABLISH_INTRO. */ crypto_pk_t *intro_key = circuit->intro_key; @@ -2901,9 +3156,7 @@ rend_service_rendezvous_has_opened(origin_circuit_t *circuit) tor_assert(circuit->base_.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND); tor_assert(circuit->cpath); tor_assert(circuit->build_state); -#ifndef NON_ANONYMOUS_MODE_ENABLED - tor_assert(!(circuit->build_state->onehop_tunnel)); -#endif + assert_circ_anonymity_ok(circuit, get_options()); tor_assert(circuit->rend_data); /* Declare the circuit dirty to avoid reuse, and for path-bias */ @@ -2923,6 +3176,7 @@ rend_service_rendezvous_has_opened(origin_circuit_t *circuit) "Done building circuit %u to rendezvous with " "cookie %s for service %s", (unsigned)circuit->base_.n_circ_id, hexcookie, serviceid); + circuit_log_path(LOG_INFO, LD_REND, circuit); /* Clear the 'in-progress HS circ has timed out' flag for * consistency with what happens on the client side; this line has @@ -3489,6 +3743,9 @@ rend_consider_services_intro_points(void) int i; time_t now; const or_options_t *options = get_options(); + /* Are we in single onion mode? */ + const int allow_direct = rend_service_allow_non_anonymous_connection( + get_options()); /* List of nodes we need to _exclude_ when choosing a new node to * establish an intro point to. */ smartlist_t *exclude_nodes; @@ -3584,8 +3841,24 @@ rend_consider_services_intro_points(void) router_crn_flags_t flags = CRN_NEED_UPTIME|CRN_NEED_DESC; if (get_options()->AllowInvalid_ & ALLOW_INVALID_INTRODUCTION) flags |= CRN_ALLOW_INVALID; + router_crn_flags_t direct_flags = flags; + direct_flags |= CRN_PREF_ADDR; + direct_flags |= CRN_DIRECT_CONN; + node = router_choose_random_node(exclude_nodes, - options->ExcludeNodes, flags); + options->ExcludeNodes, + allow_direct ? direct_flags : flags); + /* If we are in single onion mode, retry node selection for a 3-hop + * path */ + if (allow_direct && !node) { + log_info(LD_REND, + "Unable to find an intro point that we can connect to " + "directly for %s, falling back to a 3-hop path.", + safe_str_client(service->service_id)); + node = router_choose_random_node(exclude_nodes, + options->ExcludeNodes, flags); + } + if (!node) { log_warn(LD_REND, "We only have %d introduction points established for %s; " @@ -3595,10 +3868,13 @@ rend_consider_services_intro_points(void) n_intro_points_to_open); break; } - /* Add the choosen node to the exclusion list in order to avoid to - * pick it again in the next iteration. */ + /* Add the choosen node to the exclusion list in order to avoid picking + * it again in the next iteration. */ smartlist_add(exclude_nodes, (void*)node); intro = tor_malloc_zero(sizeof(rend_intro_point_t)); + /* extend_info is for clients, so we want the multi-hop primary ORPort, + * even if we are a single onion service and intend to connect to it + * directly ourselves. */ intro->extend_info = extend_info_from_node(node, 0); intro->intro_key = crypto_pk_new(); const int fail = crypto_pk_generate_key(intro->intro_key); @@ -3644,8 +3920,9 @@ rend_consider_services_upload(time_t now) { int i; rend_service_t *service; - int rendpostperiod = get_options()->RendPostPeriod; - int rendinitialpostdelay = (get_options()->TestingTorNetwork ? + const or_options_t *options = get_options(); + int rendpostperiod = options->RendPostPeriod; + int rendinitialpostdelay = (options->TestingTorNetwork ? MIN_REND_INITIAL_POST_DELAY_TESTING : MIN_REND_INITIAL_POST_DELAY); @@ -3656,6 +3933,12 @@ rend_consider_services_upload(time_t now) * the descriptor is stable before being published. See comment below. */ service->next_upload_time = now + rendinitialpostdelay + crypto_rand_int(2*rendpostperiod); + /* Single Onion Services prioritise availability over hiding their + * startup time, as their IP address is publicly discoverable anyway. + */ + if (rend_service_reveal_startup_time(options)) { + service->next_upload_time = now + rendinitialpostdelay; + } } /* Does every introduction points have been established? */ unsigned int intro_points_ready = @@ -3896,11 +4179,51 @@ rend_service_set_connection_addr_port(edge_connection_t *conn, return -2; } -/* Stub that should be replaced with the #17178 version of the function - * when merging. */ +/* Are HiddenServiceSingleHopMode and HiddenServiceNonAnonymousMode consistent? + */ +static int +rend_service_non_anonymous_mode_consistent(const or_options_t *options) +{ + /* !! is used to make these options boolean */ + return (!! options->HiddenServiceSingleHopMode == + !! options->HiddenServiceNonAnonymousMode); +} + +/* 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 HiddenServiceSingleHopMode. */ int -rend_service_allow_direct_connection(const or_options_t *options) +rend_service_allow_non_anonymous_connection(const or_options_t *options) { - (void)options; - return 0; + tor_assert(rend_service_non_anonymous_mode_consistent(options)); + return options->HiddenServiceSingleHopMode ? 1 : 0; } + +/* Do the options allow us to reveal the exact startup time of the onion + * service? + * Single Onion Services prioritise availability over hiding their + * startup time, as their IP address is publicly discoverable anyway. + * 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) +{ + tor_assert(rend_service_non_anonymous_mode_consistent(options)); + return rend_service_non_anonymous_mode_enabled(options); +} + +/* Is non-anonymous mode enabled using the HiddenServiceNonAnonymousMode + * 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->HiddenServiceNonAnonymousMode ? 1 : 0; +} + diff --git a/src/or/rendservice.h b/src/or/rendservice.h index 1622086a99..630191e8b7 100644 --- a/src/or/rendservice.h +++ b/src/or/rendservice.h @@ -63,11 +63,68 @@ struct rend_intro_cell_s { uint8_t dh[DH_KEY_LEN]; }; +/** Represents a single hidden service running at this OP. */ +typedef struct rend_service_t { + /* Fields specified in config file */ + char *directory; /**< where in the filesystem it stores it. Will be NULL if + * this service is ephemeral. */ + int dir_group_readable; /**< if 1, allow group read + permissions on directory */ + smartlist_t *ports; /**< List of rend_service_port_config_t */ + rend_auth_type_t auth_type; /**< Client authorization type or 0 if no client + * authorization is performed. */ + smartlist_t *clients; /**< List of rend_authorized_client_t's of + * clients that may access our service. Can be NULL + * if no client authorization is performed. */ + /* Other fields */ + crypto_pk_t *private_key; /**< Permanent hidden-service key. */ + char service_id[REND_SERVICE_ID_LEN_BASE32+1]; /**< Onion address without + * '.onion' */ + char pk_digest[DIGEST_LEN]; /**< Hash of permanent hidden-service key. */ + smartlist_t *intro_nodes; /**< List of rend_intro_point_t's we have, + * or are trying to establish. */ + /** List of rend_intro_point_t that are expiring. They are removed once + * the new descriptor is successfully uploaded. A node in this list CAN + * NOT appear in the intro_nodes list. */ + smartlist_t *expiring_nodes; + time_t intro_period_started; /**< Start of the current period to build + * introduction points. */ + int n_intro_circuits_launched; /**< Count of intro circuits we have + * established in this period. */ + unsigned int n_intro_points_wanted; /**< Number of intro points this + * service wants to have open. */ + rend_service_descriptor_t *desc; /**< Current hidden service descriptor. */ + time_t desc_is_dirty; /**< Time at which changes to the hidden service + * descriptor content occurred, or 0 if it's + * up-to-date. */ + time_t next_upload_time; /**< Scheduled next hidden service descriptor + * upload time. */ + /** Replay cache for Diffie-Hellman values of INTRODUCE2 cells, to + * detect repeats. Clients may send INTRODUCE1 cells for the same + * rendezvous point through two or more different introduction points; + * when they do, this keeps us from launching multiple simultaneous attempts + * to connect to the same rend point. */ + replaycache_t *accepted_intro_dh_parts; + /** If true, we don't close circuits for making requests to unsupported + * ports. */ + int allow_unknown_ports; + /** The maximum number of simultanious streams-per-circuit that are allowed + * to be established, or 0 if no limit is set. + */ + int max_streams_per_circuit; + /** If true, we close circuits that exceed the max_streams_per_circuit + * limit. */ + int max_streams_close_circuit; +} rend_service_t; + +STATIC void rend_service_free(rend_service_t *service); +STATIC char *rend_service_sos_poison_path(const rend_service_t *service); + #endif int num_rend_services(void); int rend_config_services(const or_options_t *options, int validate_only); -int rend_service_load_all_keys(void); +int rend_service_load_all_keys(const smartlist_t *service_list); void rend_services_add_filenames_to_lists(smartlist_t *open_lst, smartlist_t *stat_lst); void rend_consider_services_intro_points(void); @@ -108,6 +165,11 @@ void rend_service_port_config_free(rend_service_port_config_t *p); void rend_authorized_client_free(rend_authorized_client_t *client); +int rend_service_list_verify_single_onion_poison( + const smartlist_t *service_list, + const or_options_t *options); +int rend_service_poison_new_single_onion_dirs(const smartlist_t *service_list); + /** Return value from rend_service_add_ephemeral. */ typedef enum { RSAE_BADAUTH = -5, /**< Invalid auth_type/auth_clients */ @@ -131,7 +193,9 @@ void directory_post_to_hs_dir(rend_service_descriptor_t *renddesc, const char *service_id, int seconds_valid); void rend_service_desc_has_uploaded(const rend_data_t *rend_data); -int rend_service_allow_direct_connection(const or_options_t *options); +int rend_service_allow_non_anonymous_connection(const or_options_t *options); +int rend_service_reveal_startup_time(const or_options_t *options); +int rend_service_non_anonymous_mode_enabled(const or_options_t *options); #endif diff --git a/src/or/router.c b/src/or/router.c index 1449b57619..a74a2a9a3b 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -453,7 +453,8 @@ init_key_from_file(const char *fname, int generate, int severity, goto error; } } else { - log_info(LD_GENERAL, "No key found in \"%s\"", fname); + tor_log(severity, LD_GENERAL, "No key found in \"%s\"", fname); + goto error; } return prkey; case FN_FILE: @@ -561,7 +562,7 @@ load_authority_keyset(int legacy, crypto_pk_t **key_out, fname = get_datadir_fname2("keys", legacy ? "legacy_signing_key" : "authority_signing_key"); - signing_key = init_key_from_file(fname, 0, LOG_INFO, 0); + signing_key = init_key_from_file(fname, 0, LOG_ERR, 0); if (!signing_key) { log_warn(LD_DIR, "No version 3 directory key found in %s", fname); goto done; diff --git a/src/or/shared_random.c b/src/or/shared_random.c index 19564f5924..5f6b03f1ba 100644 --- a/src/or/shared_random.c +++ b/src/or/shared_random.c @@ -201,7 +201,7 @@ verify_commit_and_reveal(const sr_commit_t *commit) if (fast_memneq(received_hashed_reveal, commit->hashed_reveal, sizeof(received_hashed_reveal))) { log_warn(LD_BUG, "SR: Received reveal value from authority %s " - "does't match the commit value.", + "doesn't match the commit value.", sr_commit_get_rsa_fpr(commit)); goto invalid; } @@ -578,8 +578,8 @@ commit_is_authoritative(const sr_commit_t *commit, tor_assert(commit); tor_assert(voter_key); - return !memcmp(commit->rsa_identity, voter_key, - sizeof(commit->rsa_identity)); + return fast_memeq(commit->rsa_identity, voter_key, + sizeof(commit->rsa_identity)); } /* Decide if the newly received <b>commit</b> should be kept depending on |