Merge branch 'feature-17178-v7-squashed-v2'
This commit is contained in:
commit
9f0cb5af15
|
@ -0,0 +1,6 @@
|
|||
o Minor bug fixes (option parsing):
|
||||
- Count unix sockets when counting client listeners (SOCKS, Trans,
|
||||
NATD, and DNS). This has no user-visible behaviour changes: these
|
||||
options are set once, and never read.
|
||||
Required for correct behaviour in ticket #17178.
|
||||
Fixes bug #19677, patch by teor.
|
|
@ -0,0 +1,30 @@
|
|||
o Major features (onion services):
|
||||
- Add experimental HiddenServiceSingleHopMode and
|
||||
HiddenServiceNonAnonymousMode options. When both are set to 1, every
|
||||
hidden service on a tor instance becomes a non-anonymous Single Onion
|
||||
Service. Single Onions make one-hop (direct) connections to their
|
||||
introduction and renzedvous points. One-hop circuits make Single Onion
|
||||
servers easily locatable, but clients remain location-anonymous.
|
||||
This is compatible with the existing hidden service implementation, and
|
||||
works on the current tor network without any changes to older relays or
|
||||
clients.
|
||||
Implements proposal #260, completes ticket #17178. Patch by teor & asn.
|
||||
o Minor features (Tor2web):
|
||||
- Make Tor2web clients respect ReachableAddresses.
|
||||
This feature was inadvertently enabled in 0.2.8.6, then removed
|
||||
by bugfix #19973 on 0.2.8.7.
|
||||
Implements feature #20034. Patch by teor.
|
||||
o Minor bug fixes (Tor2web):
|
||||
- Prevent Tor2web clients running hidden services, these services are
|
||||
not anonymous due to the one-hop client paths.
|
||||
Fixes bug #19678. Patch by teor.
|
||||
o Minor bug fixes (circuits):
|
||||
- Use CircuitBuildTimeout whenever LearnCircuitBuildTimeout is disabled.
|
||||
Fixes bug #19678 in commit 5b0b51ca3 in 0.2.4.12-alpha. Patch by teor.
|
||||
o Minor bug fixes (options):
|
||||
- Stop changing the configured value of UseEntryGuards on authorities
|
||||
and Tor2web clients.
|
||||
Fixes bug #20074 in commits 51fc6799 in tor-0.1.1.16-rc and
|
||||
acda1735 in tor-0.2.4.3-alpha. Patch by teor.
|
||||
- Check the consistency of UseEntryGuards and EntryNodes more reliably.
|
||||
Fixes bug #20074 in commit 686aaa5c in tor-0.2.4.12-alpha. Patch by teor.
|
|
@ -1199,7 +1199,9 @@ The following options are useful only for clients (that is, if
|
|||
If this option is set to 1, we pick a few long-term entry servers, and try
|
||||
to stick with them. This is desirable because constantly changing servers
|
||||
increases the odds that an adversary who owns some servers will observe a
|
||||
fraction of your paths. (Default: 1)
|
||||
fraction of your paths. Entry Guards can not be used by Directory
|
||||
Authorities, Single Onion Services, and Tor2web clients. In these cases,
|
||||
the this option is ignored. (Default: 1)
|
||||
|
||||
[[UseEntryGuardsAsDirGuards]] **UseEntryGuardsAsDirGuards** **0**|**1**::
|
||||
If this option is set to 1, and UseEntryGuards is also set to 1,
|
||||
|
@ -1440,7 +1442,9 @@ The following options are useful only for clients (that is, if
|
|||
non-hidden-service hostnames through Tor. It **must only** be used when
|
||||
running a tor2web Hidden Service web proxy.
|
||||
To enable this option the compile time flag --enable-tor2web-mode must be
|
||||
specified. (Default: 0)
|
||||
specified. Since Tor2webMode is non-anonymous, you can not run an
|
||||
anonymous Hidden Service on a tor version compiled with Tor2webMode.
|
||||
(Default: 0)
|
||||
|
||||
[[Tor2webRendezvousPoints]] **Tor2webRendezvousPoints** __node__,__node__,__...__::
|
||||
A list of identity fingerprints, nicknames, country codes and
|
||||
|
@ -2392,6 +2396,37 @@ The following options are used to configure a hidden service.
|
|||
Number of introduction points the hidden service will have. You can't
|
||||
have more than 10. (Default: 3)
|
||||
|
||||
[[HiddenServiceSingleHopMode]] **HiddenServiceSingleHopMode** **0**|**1**::
|
||||
**Experimental - Non Anonymous** Hidden Services on a tor instance 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 a tor instance a
|
||||
Single Onion Service. One-hop circuits make Single Onion servers easily
|
||||
locatable, but clients remain location-anonymous. However, the fact that a
|
||||
client is accessing a Single Onion rather than a Hidden Service may be
|
||||
statistically distinguishable.
|
||||
|
||||
**WARNING:** Once a hidden service directory has been used by a tor
|
||||
instance in HiddenServiceSingleHopMode, it can **NEVER** be used again for
|
||||
a hidden service. It is best practice to create a new hidden service
|
||||
directory, key, and address for each new Single Onion Service and Hidden
|
||||
Service. It is not possible to run Single Onion Services and Hidden
|
||||
Services from the same tor instance: they should be run on different
|
||||
servers with different IP addresses.
|
||||
|
||||
HiddenServiceSingleHopMode requires HiddenServiceNonAnonymousMode to be set
|
||||
to 1. Since a Single Onion is non-anonymous, you can not to run an
|
||||
anonymous SOCKSPort on the same tor instance as a Single Onion service.
|
||||
(Default: 0)
|
||||
|
||||
[[HiddenServiceNonAnonymousMode]] **HiddenServiceNonAnonymousMode** **0**|**1**::
|
||||
Makes hidden services non-anonymous on this tor instance. Allows the
|
||||
non-anonymous HiddenServiceSingleHopMode. Enables direct connections in the
|
||||
server-side hidden service protocol.
|
||||
(Default: 0)
|
||||
|
||||
TESTING NETWORK OPTIONS
|
||||
-----------------------
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
@ -1859,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
|
||||
|
||||
|
@ -2000,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());
|
||||
|
|
|
@ -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);
|
||||
|
|
221
src/or/config.c
221
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 "
|
||||
|
@ -6777,14 +6903,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;
|
||||
|
@ -6793,9 +6922,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.
|
||||
*
|
||||
|
@ -6921,21 +7049,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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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"
|
||||
|
@ -2326,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);
|
||||
|
@ -2369,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,
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -2833,11 +2833,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;
|
||||
|
@ -2849,15 +2844,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;
|
||||
}
|
||||
|
|
48
src/or/or.h
48
src/or/or.h
|
@ -3606,9 +3606,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.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
@ -3699,6 +3703,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
|
||||
|
@ -3754,7 +3778,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. */
|
||||
|
@ -3940,8 +3965,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? */
|
||||
|
@ -5054,7 +5087,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. */
|
||||
|
||||
|
|
|
@ -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
|
||||
|
@ -1527,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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -1067,3 +1067,51 @@ 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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
@ -1001,13 +958,235 @@ rend_service_update_descriptor(rend_service_t *service)
|
|||
}
|
||||
}
|
||||
|
||||
/** Load and/or generate private keys for all hidden services, possibly
|
||||
* including keys for client authorization. Return 0 on success, -1 on
|
||||
* failure. */
|
||||
int
|
||||
rend_service_load_all_keys(void)
|
||||
/* 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)
|
||||
{
|
||||
SMARTLIST_FOREACH_BEGIN(rend_service_list, rend_service_t *, s) {
|
||||
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.
|
||||
* 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(const smartlist_t *service_list)
|
||||
{
|
||||
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, sizeof(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,12 +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. */
|
||||
int
|
||||
rend_service_allow_direct_connection(const or_options_t *options)
|
||||
/* Are HiddenServiceSingleHopMode and HiddenServiceNonAnonymousMode consistent?
|
||||
*/
|
||||
static int
|
||||
rend_service_non_anonymous_mode_consistent(const or_options_t *options)
|
||||
{
|
||||
(void)options;
|
||||
return 0;
|
||||
/* !! 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_non_anonymous_connection(const or_options_t *options)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -8,12 +8,14 @@
|
|||
|
||||
#define CONTROL_PRIVATE
|
||||
#define CIRCUITBUILD_PRIVATE
|
||||
#define RENDSERVICE_PRIVATE
|
||||
|
||||
#include "or.h"
|
||||
#include "test.h"
|
||||
#include "control.h"
|
||||
#include "config.h"
|
||||
#include "rendcommon.h"
|
||||
#include "rendservice.h"
|
||||
#include "routerset.h"
|
||||
#include "circuitbuild.h"
|
||||
#include "test_helpers.h"
|
||||
|
@ -496,6 +498,209 @@ test_hs_auth_cookies(void *arg)
|
|||
return;
|
||||
}
|
||||
|
||||
static int mock_get_options_calls = 0;
|
||||
static or_options_t *mock_options = NULL;
|
||||
|
||||
static void
|
||||
reset_options(or_options_t *options, int *get_options_calls)
|
||||
{
|
||||
memset(options, 0, sizeof(or_options_t));
|
||||
options->TestingTorNetwork = 1;
|
||||
|
||||
*get_options_calls = 0;
|
||||
}
|
||||
|
||||
static const or_options_t *
|
||||
mock_get_options(void)
|
||||
{
|
||||
++mock_get_options_calls;
|
||||
tor_assert(mock_options);
|
||||
return mock_options;
|
||||
}
|
||||
|
||||
/* Test that single onion poisoning works. */
|
||||
static void
|
||||
test_single_onion_poisoning(void *arg)
|
||||
{
|
||||
or_options_t opt;
|
||||
mock_options = &opt;
|
||||
reset_options(mock_options, &mock_get_options_calls);
|
||||
MOCK(get_options, mock_get_options);
|
||||
|
||||
int ret = -1;
|
||||
mock_options->DataDirectory = tor_strdup(get_fname("test_data_dir"));
|
||||
rend_service_t *service_1 = tor_malloc_zero(sizeof(rend_service_t));
|
||||
char *dir1 = tor_strdup(get_fname("test_hs_dir1"));
|
||||
rend_service_t *service_2 = tor_malloc_zero(sizeof(rend_service_t));
|
||||
char *dir2 = tor_strdup(get_fname("test_hs_dir2"));
|
||||
smartlist_t *services = smartlist_new();
|
||||
|
||||
(void) arg;
|
||||
|
||||
/* No services, no problem! */
|
||||
mock_options->HiddenServiceSingleHopMode = 0;
|
||||
mock_options->HiddenServiceNonAnonymousMode = 0;
|
||||
ret = rend_service_list_verify_single_onion_poison(services, mock_options);
|
||||
tt_assert(ret == 0);
|
||||
|
||||
/* Either way, no problem. */
|
||||
mock_options->HiddenServiceSingleHopMode = 1;
|
||||
mock_options->HiddenServiceNonAnonymousMode = 1;
|
||||
ret = rend_service_list_verify_single_onion_poison(services, mock_options);
|
||||
tt_assert(ret == 0);
|
||||
|
||||
/* Create directories for both services */
|
||||
|
||||
#ifdef _WIN32
|
||||
ret = mkdir(mock_options->DataDirectory);
|
||||
tt_assert(ret == 0);
|
||||
ret = mkdir(dir1);
|
||||
tt_assert(ret == 0);
|
||||
ret = mkdir(dir2);
|
||||
#else
|
||||
ret = mkdir(mock_options->DataDirectory, 0700);
|
||||
tt_assert(ret == 0);
|
||||
ret = mkdir(dir1, 0700);
|
||||
tt_assert(ret == 0);
|
||||
ret = mkdir(dir2, 0700);
|
||||
#endif
|
||||
tt_assert(ret == 0);
|
||||
|
||||
service_1->directory = dir1;
|
||||
service_2->directory = dir2;
|
||||
smartlist_add(services, service_1);
|
||||
/* But don't add the second service yet. */
|
||||
|
||||
/* Service directories, but no previous keys, no problem! */
|
||||
mock_options->HiddenServiceSingleHopMode = 0;
|
||||
mock_options->HiddenServiceNonAnonymousMode = 0;
|
||||
ret = rend_service_list_verify_single_onion_poison(services, mock_options);
|
||||
tt_assert(ret == 0);
|
||||
|
||||
/* Either way, no problem. */
|
||||
mock_options->HiddenServiceSingleHopMode = 1;
|
||||
mock_options->HiddenServiceNonAnonymousMode = 1;
|
||||
ret = rend_service_list_verify_single_onion_poison(services, mock_options);
|
||||
tt_assert(ret == 0);
|
||||
|
||||
/* Poison! Poison! Poison!
|
||||
* This can only be done in HiddenServiceSingleHopMode. */
|
||||
mock_options->HiddenServiceSingleHopMode = 1;
|
||||
mock_options->HiddenServiceNonAnonymousMode = 1;
|
||||
ret = rend_service_poison_new_single_onion_dirs(services);
|
||||
tt_assert(ret == 0);
|
||||
/* Poisoning twice is a no-op. */
|
||||
ret = rend_service_poison_new_single_onion_dirs(services);
|
||||
tt_assert(ret == 0);
|
||||
|
||||
/* Poisoned service directories, but no previous keys, no problem! */
|
||||
mock_options->HiddenServiceSingleHopMode = 0;
|
||||
mock_options->HiddenServiceNonAnonymousMode = 0;
|
||||
ret = rend_service_list_verify_single_onion_poison(services, mock_options);
|
||||
tt_assert(ret == 0);
|
||||
|
||||
/* Either way, no problem. */
|
||||
mock_options->HiddenServiceSingleHopMode = 1;
|
||||
mock_options->HiddenServiceNonAnonymousMode = 1;
|
||||
ret = rend_service_list_verify_single_onion_poison(services, mock_options);
|
||||
tt_assert(ret == 0);
|
||||
|
||||
/* Now add some keys, and we'll have a problem. */
|
||||
ret = rend_service_load_all_keys(services);
|
||||
tt_assert(ret == 0);
|
||||
|
||||
/* Poisoned service directories with previous keys are not allowed. */
|
||||
mock_options->HiddenServiceSingleHopMode = 0;
|
||||
mock_options->HiddenServiceNonAnonymousMode = 0;
|
||||
ret = rend_service_list_verify_single_onion_poison(services, mock_options);
|
||||
tt_assert(ret < 0);
|
||||
|
||||
/* But they are allowed if we're in non-anonymous mode. */
|
||||
mock_options->HiddenServiceSingleHopMode = 1;
|
||||
mock_options->HiddenServiceNonAnonymousMode = 1;
|
||||
ret = rend_service_list_verify_single_onion_poison(services, mock_options);
|
||||
tt_assert(ret == 0);
|
||||
|
||||
/* Re-poisoning directories with existing keys is a no-op, because
|
||||
* directories with existing keys are ignored. */
|
||||
mock_options->HiddenServiceSingleHopMode = 1;
|
||||
mock_options->HiddenServiceNonAnonymousMode = 1;
|
||||
ret = rend_service_poison_new_single_onion_dirs(services);
|
||||
tt_assert(ret == 0);
|
||||
/* And it keeps the poison. */
|
||||
ret = rend_service_list_verify_single_onion_poison(services, mock_options);
|
||||
tt_assert(ret == 0);
|
||||
|
||||
/* Now add the second service: it has no key and no poison file */
|
||||
smartlist_add(services, service_2);
|
||||
|
||||
/* A new service, and an existing poisoned service. Not ok. */
|
||||
mock_options->HiddenServiceSingleHopMode = 0;
|
||||
mock_options->HiddenServiceNonAnonymousMode = 0;
|
||||
ret = rend_service_list_verify_single_onion_poison(services, mock_options);
|
||||
tt_assert(ret < 0);
|
||||
|
||||
/* But ok to add in non-anonymous mode. */
|
||||
mock_options->HiddenServiceSingleHopMode = 1;
|
||||
mock_options->HiddenServiceNonAnonymousMode = 1;
|
||||
ret = rend_service_list_verify_single_onion_poison(services, mock_options);
|
||||
tt_assert(ret == 0);
|
||||
|
||||
/* Now remove the poisoning from the first service, and we have the opposite
|
||||
* problem. */
|
||||
char *poison_path = rend_service_sos_poison_path(service_1);
|
||||
ret = unlink(poison_path);
|
||||
tor_free(poison_path);
|
||||
tt_assert(ret == 0);
|
||||
|
||||
/* Unpoisoned service directories with previous keys are ok, as are empty
|
||||
* directories. */
|
||||
mock_options->HiddenServiceSingleHopMode = 0;
|
||||
mock_options->HiddenServiceNonAnonymousMode = 0;
|
||||
ret = rend_service_list_verify_single_onion_poison(services, mock_options);
|
||||
tt_assert(ret == 0);
|
||||
|
||||
/* But the existing unpoisoned key is not ok in non-anonymous mode, even if
|
||||
* there is an empty service. */
|
||||
mock_options->HiddenServiceSingleHopMode = 1;
|
||||
mock_options->HiddenServiceNonAnonymousMode = 1;
|
||||
ret = rend_service_list_verify_single_onion_poison(services, mock_options);
|
||||
tt_assert(ret < 0);
|
||||
|
||||
/* Poisoning directories with existing keys is a no-op, because directories
|
||||
* with existing keys are ignored. But the new directory should poison. */
|
||||
mock_options->HiddenServiceSingleHopMode = 1;
|
||||
mock_options->HiddenServiceNonAnonymousMode = 1;
|
||||
ret = rend_service_poison_new_single_onion_dirs(services);
|
||||
tt_assert(ret == 0);
|
||||
/* And the old directory remains unpoisoned. */
|
||||
ret = rend_service_list_verify_single_onion_poison(services, mock_options);
|
||||
tt_assert(ret < 0);
|
||||
|
||||
/* And the new directory should be ignored, because it has no key. */
|
||||
mock_options->HiddenServiceSingleHopMode = 0;
|
||||
mock_options->HiddenServiceNonAnonymousMode = 0;
|
||||
ret = rend_service_list_verify_single_onion_poison(services, mock_options);
|
||||
tt_assert(ret == 0);
|
||||
|
||||
/* Re-poisoning directories without existing keys is a no-op. */
|
||||
mock_options->HiddenServiceSingleHopMode = 1;
|
||||
mock_options->HiddenServiceNonAnonymousMode = 1;
|
||||
ret = rend_service_poison_new_single_onion_dirs(services);
|
||||
tt_assert(ret == 0);
|
||||
/* And the old directory remains unpoisoned. */
|
||||
ret = rend_service_list_verify_single_onion_poison(services, mock_options);
|
||||
tt_assert(ret < 0);
|
||||
|
||||
done:
|
||||
/* TODO: should we delete the directories here? */
|
||||
rend_service_free(service_1);
|
||||
rend_service_free(service_2);
|
||||
smartlist_free(services);
|
||||
UNMOCK(get_options);
|
||||
tor_free(mock_options->DataDirectory);
|
||||
}
|
||||
|
||||
struct testcase_t hs_tests[] = {
|
||||
{ "hs_rend_data", test_hs_rend_data, TT_FORK,
|
||||
NULL, NULL },
|
||||
|
@ -508,6 +713,8 @@ struct testcase_t hs_tests[] = {
|
|||
NULL, NULL },
|
||||
{ "hs_auth_cookies", test_hs_auth_cookies, TT_FORK,
|
||||
NULL, NULL },
|
||||
{ "single_onion_poisoning", test_single_onion_poisoning, TT_FORK,
|
||||
NULL, NULL },
|
||||
END_OF_TESTCASES
|
||||
};
|
||||
|
||||
|
|
|
@ -2749,6 +2749,154 @@ test_options_validate__rend(void *ignored)
|
|||
tor_free(msg);
|
||||
}
|
||||
|
||||
static void
|
||||
test_options_validate__single_onion(void *ignored)
|
||||
{
|
||||
(void)ignored;
|
||||
int ret;
|
||||
char *msg;
|
||||
options_test_data_t *tdata = NULL;
|
||||
int previous_log = setup_capture_of_logs(LOG_WARN);
|
||||
|
||||
/* Test that HiddenServiceSingleHopMode must come with
|
||||
* HiddenServiceNonAnonymousMode */
|
||||
tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
|
||||
"SOCKSPort 0\n"
|
||||
"HiddenServiceSingleHopMode 1\n"
|
||||
);
|
||||
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
|
||||
tt_int_op(ret, OP_EQ, -1);
|
||||
tt_str_op(msg, OP_EQ, "HiddenServiceSingleHopMode does not provide any "
|
||||
"server anonymity. It must be used with "
|
||||
"HiddenServiceNonAnonymousMode set to 1.");
|
||||
tor_free(msg);
|
||||
free_options_test_data(tdata);
|
||||
|
||||
tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
|
||||
"SOCKSPort 0\n"
|
||||
"HiddenServiceSingleHopMode 1\n"
|
||||
"HiddenServiceNonAnonymousMode 0\n"
|
||||
);
|
||||
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
|
||||
tt_int_op(ret, OP_EQ, -1);
|
||||
tt_str_op(msg, OP_EQ, "HiddenServiceSingleHopMode does not provide any "
|
||||
"server anonymity. It must be used with "
|
||||
"HiddenServiceNonAnonymousMode set to 1.");
|
||||
tor_free(msg);
|
||||
free_options_test_data(tdata);
|
||||
|
||||
tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
|
||||
"SOCKSPort 0\n"
|
||||
"HiddenServiceSingleHopMode 1\n"
|
||||
"HiddenServiceNonAnonymousMode 1\n"
|
||||
);
|
||||
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
|
||||
tt_int_op(ret, OP_EQ, 0);
|
||||
tt_ptr_op(msg, OP_EQ, NULL);
|
||||
free_options_test_data(tdata);
|
||||
|
||||
/* Test that SOCKSPort must come with Tor2webMode if
|
||||
* HiddenServiceSingleHopMode is 1 */
|
||||
tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
|
||||
"SOCKSPort 5000\n"
|
||||
"HiddenServiceSingleHopMode 1\n"
|
||||
"HiddenServiceNonAnonymousMode 1\n"
|
||||
"Tor2webMode 0\n"
|
||||
);
|
||||
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
|
||||
tt_int_op(ret, OP_EQ, -1);
|
||||
tt_str_op(msg, OP_EQ, "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.");
|
||||
tor_free(msg);
|
||||
free_options_test_data(tdata);
|
||||
|
||||
tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
|
||||
"SOCKSPort 0\n"
|
||||
"HiddenServiceSingleHopMode 1\n"
|
||||
"HiddenServiceNonAnonymousMode 1\n"
|
||||
"Tor2webMode 0\n"
|
||||
);
|
||||
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
|
||||
tt_int_op(ret, OP_EQ, 0);
|
||||
tt_ptr_op(msg, OP_EQ, NULL);
|
||||
free_options_test_data(tdata);
|
||||
|
||||
tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
|
||||
"SOCKSPort 5000\n"
|
||||
"HiddenServiceSingleHopMode 0\n"
|
||||
"Tor2webMode 0\n"
|
||||
);
|
||||
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
|
||||
tt_int_op(ret, OP_EQ, 0);
|
||||
tt_ptr_op(msg, OP_EQ, NULL);
|
||||
free_options_test_data(tdata);
|
||||
|
||||
tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
|
||||
"SOCKSPort 5000\n"
|
||||
"HiddenServiceSingleHopMode 1\n"
|
||||
"HiddenServiceNonAnonymousMode 1\n"
|
||||
"Tor2webMode 1\n"
|
||||
);
|
||||
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
|
||||
tt_int_op(ret, OP_EQ, 0);
|
||||
tt_ptr_op(msg, OP_EQ, NULL);
|
||||
free_options_test_data(tdata);
|
||||
|
||||
/* Test that a hidden service can't be run with Tor2web
|
||||
* Use HiddenServiceNonAnonymousMode instead of Tor2webMode, because
|
||||
* Tor2webMode requires a compilation #define */
|
||||
tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
|
||||
"HiddenServiceNonAnonymousMode 1\n"
|
||||
"HiddenServiceDir /Library/Tor/var/lib/tor/hidden_service/\n"
|
||||
"HiddenServicePort 80 127.0.0.1:8080\n"
|
||||
);
|
||||
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
|
||||
tt_int_op(ret, OP_EQ, -1);
|
||||
tt_str_op(msg, OP_EQ, "HiddenServiceNonAnonymousMode does not provide any "
|
||||
"server anonymity. It must be used with "
|
||||
"HiddenServiceSingleHopMode set to 1.");
|
||||
tor_free(msg);
|
||||
free_options_test_data(tdata);
|
||||
|
||||
tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
|
||||
"HiddenServiceNonAnonymousMode 1\n"
|
||||
);
|
||||
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
|
||||
tt_int_op(ret, OP_EQ, -1);
|
||||
tt_str_op(msg, OP_EQ, "HiddenServiceNonAnonymousMode does not provide any "
|
||||
"server anonymity. It must be used with "
|
||||
"HiddenServiceSingleHopMode set to 1.");
|
||||
free_options_test_data(tdata);
|
||||
|
||||
tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
|
||||
"HiddenServiceDir /Library/Tor/var/lib/tor/hidden_service/\n"
|
||||
"HiddenServicePort 80 127.0.0.1:8080\n"
|
||||
);
|
||||
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
|
||||
tt_int_op(ret, OP_EQ, 0);
|
||||
tt_ptr_op(msg, OP_EQ, NULL);
|
||||
free_options_test_data(tdata);
|
||||
|
||||
tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
|
||||
"HiddenServiceNonAnonymousMode 1\n"
|
||||
"HiddenServiceDir /Library/Tor/var/lib/tor/hidden_service/\n"
|
||||
"HiddenServicePort 80 127.0.0.1:8080\n"
|
||||
"HiddenServiceSingleHopMode 1\n"
|
||||
"SOCKSPort 0\n"
|
||||
);
|
||||
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
|
||||
tt_int_op(ret, OP_EQ, 0);
|
||||
tt_ptr_op(msg, OP_EQ, NULL);
|
||||
|
||||
done:
|
||||
policies_free_all();
|
||||
teardown_capture_of_logs(previous_log);
|
||||
free_options_test_data(tdata);
|
||||
tor_free(msg);
|
||||
}
|
||||
|
||||
static void
|
||||
test_options_validate__accounting(void *ignored)
|
||||
{
|
||||
|
@ -4371,6 +4519,7 @@ struct testcase_t options_tests[] = {
|
|||
LOCAL_VALIDATE_TEST(port_forwarding),
|
||||
LOCAL_VALIDATE_TEST(tor2web),
|
||||
LOCAL_VALIDATE_TEST(rend),
|
||||
LOCAL_VALIDATE_TEST(single_onion),
|
||||
LOCAL_VALIDATE_TEST(accounting),
|
||||
LOCAL_VALIDATE_TEST(proxy),
|
||||
LOCAL_VALIDATE_TEST(control),
|
||||
|
|
Loading…
Reference in New Issue