summaryrefslogtreecommitdiff
path: root/src/or/config.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/or/config.c')
-rw-r--r--src/or/config.c793
1 files changed, 573 insertions, 220 deletions
diff --git a/src/or/config.c b/src/or/config.c
index 7594c8989a..2e001ee5ab 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -18,6 +18,7 @@
#include "circuitlist.h"
#include "circuitmux.h"
#include "circuitmux_ewma.h"
+#include "circuitstats.h"
#include "config.h"
#include "connection.h"
#include "connection_edge.h"
@@ -65,11 +66,11 @@
#include <systemd/sd-daemon.h>
#endif
-/* From main.c */
-extern int quiet_level;
-
/* Prefix used to indicate a Unix socket in a FooPort configuration. */
static const char unix_socket_prefix[] = "unix:";
+/* Prefix used to indicate a Unix socket with spaces in it, in a FooPort
+ * configuration. */
+static const char unix_q_socket_prefix[] = "unix:\"";
/** A list of abbreviations and aliases to map command-line options, obsolete
* option names, or alternative option names, to their current values. */
@@ -99,7 +100,7 @@ static config_abbrev_t option_abbrevs_[] = {
{ "BandwidthRateBytes", "BandwidthRate", 0, 0},
{ "BandwidthBurstBytes", "BandwidthBurst", 0, 0},
{ "DirFetchPostPeriod", "StatusFetchPeriod", 0, 0},
- { "DirServer", "DirAuthority", 0, 0}, /* XXXX024 later, make this warn? */
+ { "DirServer", "DirAuthority", 0, 0}, /* XXXX later, make this warn? */
{ "MaxConn", "ConnLimit", 0, 1},
{ "MaxMemInCellQueues", "MaxMemInQueues", 0, 0},
{ "ORBindAddress", "ORListenAddress", 0, 0},
@@ -116,7 +117,6 @@ static config_abbrev_t option_abbrevs_[] = {
{ "BridgeAuthoritativeDirectory", "BridgeAuthoritativeDir", 0, 0},
{ "HashedControlPassword", "__HashedControlSessionPassword", 1, 0},
{ "VirtualAddrNetwork", "VirtualAddrNetworkIPv4", 0, 0},
- { "_UseFilteringSSLBufferevents", "UseFilteringSSLBufferevents", 0, 1},
{ NULL, NULL, 0, 0},
};
@@ -215,6 +215,7 @@ static config_var_t option_vars_[] = {
V(CountPrivateBandwidth, BOOL, "0"),
V(DataDirectory, FILENAME, NULL),
V(DataDirectoryGroupReadable, BOOL, "0"),
+ V(DisableOOSCheck, BOOL, "1"),
V(DisableNetwork, BOOL, "0"),
V(DirAllowPrivateAddresses, BOOL, "0"),
V(TestingAuthDirTimeToLearnReachability, INTERVAL, "30 minutes"),
@@ -228,7 +229,7 @@ static config_var_t option_vars_[] = {
V(DirAuthorityFallbackRate, DOUBLE, "1.0"),
V(DisableAllSwap, BOOL, "0"),
V(DisableDebuggerAttachment, BOOL, "1"),
- V(DisableIOCP, BOOL, "1"),
+ OBSOLETE("DisableIOCP"),
OBSOLETE("DisableV2DirectoryInfo_"),
OBSOLETE("DynamicDHGroups"),
VPORT(DNSPort, LINELIST, NULL),
@@ -247,6 +248,7 @@ static config_var_t option_vars_[] = {
V(ExitNodes, ROUTERSET, NULL),
V(ExitPolicy, LINELIST, NULL),
V(ExitPolicyRejectPrivate, BOOL, "1"),
+ V(ExitPolicyRejectLocalInterfaces, BOOL, "0"),
V(ExitPortStatistics, BOOL, "0"),
V(ExtendAllowPrivateAddresses, BOOL, "0"),
V(ExitRelay, AUTOBOOL, "auto"),
@@ -299,6 +301,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),
@@ -328,6 +332,7 @@ static config_var_t option_vars_[] = {
VAR("MaxMemInQueues", MEMUNIT, MaxMemInQueues_raw, "0"),
OBSOLETE("MaxOnionsPending"),
V(MaxOnionQueueDelay, MSEC_INTERVAL, "1750 msec"),
+ V(MaxUnparseableDescSizeToLog, MEMUNIT, "10 MB"),
V(MinMeasuredBWsForAuthToIgnoreAdvertised, INT, "500"),
V(MyFamily, STRING, NULL),
V(NewCircuitPeriod, INTERVAL, "30 seconds"),
@@ -435,13 +440,14 @@ 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"),
- V(UseNTorHandshake, AUTOBOOL, "1"),
+ OBSOLETE("UseNTorHandshake"),
V(User, STRING, NULL),
- V(UserspaceIOCPBuffers, BOOL, "0"),
+ OBSOLETE("UserspaceIOCPBuffers"),
+ V(AuthDirSharedRandomness, BOOL, "1"),
OBSOLETE("V1AuthoritativeDirectory"),
OBSOLETE("V2AuthoritativeDirectory"),
VAR("V3AuthoritativeDirectory",BOOL, V3AuthoritativeDir, "0"),
@@ -461,7 +467,8 @@ static config_var_t option_vars_[] = {
V(VirtualAddrNetworkIPv4, STRING, "127.192.0.0/10"),
V(VirtualAddrNetworkIPv6, STRING, "[FE80::]/10"),
V(WarnPlaintextPorts, CSV, "23,109,110,143"),
- V(UseFilteringSSLBufferevents, BOOL, "0"),
+ OBSOLETE("UseFilteringSSLBufferevents"),
+ OBSOLETE("__UseFilteringSSLBufferevents"),
VAR("__ReloadTorrcOnSIGHUP", BOOL, ReloadTorrcOnSIGHUP, "1"),
VAR("__AllDirActionsPrivate", BOOL, AllDirActionsPrivate, "0"),
VAR("__DisablePredictedCircuits",BOOL,DisablePredictedCircuits, "0"),
@@ -494,7 +501,7 @@ static config_var_t option_vars_[] = {
* When clients have authorities and fallbacks available, they use these
* schedules: (we stagger the times to avoid thundering herds) */
V(ClientBootstrapConsensusAuthorityDownloadSchedule, CSV_INTERVAL,
- "10, 11, 3600, 10800, 25200, 54000, 111600, 262800" /* 3 days + 1 hour */),
+ "6, 11, 3600, 10800, 25200, 54000, 111600, 262800" /* 3 days + 1 hour */),
V(ClientBootstrapConsensusFallbackDownloadSchedule, CSV_INTERVAL,
"0, 1, 4, 11, 3600, 10800, 25200, 54000, 111600, 262800"),
/* When clients only have authorities available, they use this schedule: */
@@ -505,7 +512,7 @@ static config_var_t option_vars_[] = {
* blackholed. Clients will try 3 directories simultaneously.
* (Relays never use simultaneous connections.) */
V(ClientBootstrapConsensusMaxInProgressTries, UINT, "3"),
- V(TestingBridgeDownloadSchedule, CSV_INTERVAL, "3600, 900, 900, 3600"),
+ V(TestingBridgeDownloadSchedule, CSV_INTERVAL, "1200, 900, 900, 3600"),
V(TestingClientMaxIntervalWithoutRequest, INTERVAL, "10 minutes"),
V(TestingDirConnectionMaxStall, INTERVAL, "5 minutes"),
V(TestingConsensusMaxDownloadTries, UINT, "8"),
@@ -545,7 +552,7 @@ static const config_var_t testing_tor_network_defaults[] = {
"0, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 16, 32, 60"),
V(ClientBootstrapConsensusMaxDownloadTries, UINT, "80"),
V(ClientBootstrapConsensusAuthorityOnlyMaxDownloadTries, UINT, "80"),
- V(ClientDNSRejectInternalAddresses, BOOL,"0"),
+ V(ClientDNSRejectInternalAddresses, BOOL,"0"), // deprecated in 0.2.9.2-alpha
V(ClientRejectInternalAddresses, BOOL, "0"),
V(CountPrivateBandwidth, BOOL, "1"),
V(ExitPolicyRejectPrivate, BOOL, "0"),
@@ -588,6 +595,44 @@ static const config_var_t testing_tor_network_defaults[] = {
#undef V
#undef OBSOLETE
+static const config_deprecation_t option_deprecation_notes_[] = {
+ /* Deprecated since 0.2.9.2-alpha... */
+ { "AllowDotExit", "Unrestricted use of the .exit notation can be used for "
+ "a wide variety of application-level attacks." },
+ { "AllowInvalidNodes", "There is no reason to enable this option; at best "
+ "it will make you easier to track." },
+ { "AllowSingleHopCircuits", "Almost no relays actually allow single-hop "
+ "exits, making this option pointless." },
+ { "AllowSingleHopExits", "Turning this on will make your relay easier "
+ "to abuse." },
+ { "ClientDNSRejectInternalAddresses", "Turning this on makes your client "
+ "easier to fingerprint, and may open you to esoteric attacks." },
+ { "ExcludeSingleHopRelays", "Turning it on makes your client easier to "
+ "fingerprint." },
+ { "FastFirstHopPK", "Changing this option does not make your client more "
+ "secure, but does make it easier to fingerprint." },
+ { "CloseHSClientCircuitsImmediatelyOnTimeout", "This option makes your "
+ "client easier to fingerprint." },
+ { "CloseHSServiceRendCircuitsImmediatelyOnTimeout", "This option makes "
+ "your hidden services easier to fingerprint." },
+ { "WarnUnsafeSocks", "Changing this option makes it easier for you "
+ "to accidentally lose your anonymity by leaking DNS information" },
+ { "TLSECGroup", "The default is a nice secure choice; the other option "
+ "is less secure." },
+ { "ControlListenAddress", "Use ControlPort instead." },
+ { "DirListenAddress", "Use DirPort instead, possibly with the "
+ "NoAdvertise sub-option" },
+ { "DNSListenAddress", "Use DNSPort instead." },
+ { "SocksListenAddress", "Use SocksPort instead." },
+ { "TransListenAddress", "Use TransPort instead." },
+ { "NATDListenAddress", "Use NATDPort instead." },
+ { "ORListenAddress", "Use ORPort instead, possibly with the "
+ "NoAdvertise sub-option" },
+ /* End of options deprecated since 0.2.9.2-alpha. */
+
+ { NULL, NULL }
+};
+
#ifdef _WIN32
static char *get_windows_conf_root(void);
#endif
@@ -636,6 +681,7 @@ STATIC config_format_t options_format = {
OR_OPTIONS_MAGIC,
STRUCT_OFFSET(or_options_t, magic_),
option_abbrevs_,
+ option_deprecation_notes_,
option_vars_,
options_validate_cb,
NULL
@@ -746,7 +792,7 @@ set_options(or_options_t *new_val, char **msg)
}
if (old_options != global_options)
- config_free(&options_format, old_options);
+ or_options_free(old_options);
return 0;
}
@@ -1333,6 +1379,35 @@ options_act_reversible(const or_options_t *old_options, char **msg)
connection_mark_for_close(conn);
}
});
+
+ if (set_conn_limit) {
+ /*
+ * If we adjusted the conn limit, recompute the OOS threshold too
+ *
+ * How many possible sockets to keep in reserve? If we have lots of
+ * possible sockets, keep this below a limit and set ConnLimit_high_thresh
+ * very close to ConnLimit_, but if ConnLimit_ is low, shrink it in
+ * proportion.
+ *
+ * Somewhat arbitrarily, set socks_in_reserve to 5% of ConnLimit_, but
+ * cap it at 64.
+ */
+ int socks_in_reserve = options->ConnLimit_ / 20;
+ if (socks_in_reserve > 64) socks_in_reserve = 64;
+
+ options->ConnLimit_high_thresh = options->ConnLimit_ - socks_in_reserve;
+ options->ConnLimit_low_thresh = (options->ConnLimit_ / 4) * 3;
+ log_info(LD_GENERAL,
+ "Recomputed OOS thresholds: ConnLimit %d, ConnLimit_ %d, "
+ "ConnLimit_high_thresh %d, ConnLimit_low_thresh %d",
+ options->ConnLimit, options->ConnLimit_,
+ options->ConnLimit_high_thresh,
+ options->ConnLimit_low_thresh);
+
+ /* Give the OOS handler a chance with the new thresholds */
+ connection_check_oos(get_n_open_sockets(), 0);
+ }
+
goto done;
rollback:
@@ -1488,10 +1563,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 */
@@ -1654,7 +1729,7 @@ options_act(const or_options_t *old_options)
monitor_owning_controller_process(options->OwningControllerProcess);
/* 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;
}
@@ -1673,17 +1748,6 @@ options_act(const or_options_t *old_options)
if (accounting_is_enabled(options))
configure_accounting(time(NULL));
-#ifdef USE_BUFFEREVENTS
- /* If we're using the bufferevents implementation and our rate limits
- * changed, we need to tell the rate-limiting system about it. */
- if (!old_options ||
- old_options->BandwidthRate != options->BandwidthRate ||
- old_options->BandwidthBurst != options->BandwidthBurst ||
- old_options->RelayBandwidthRate != options->RelayBandwidthRate ||
- old_options->RelayBandwidthBurst != options->RelayBandwidthBurst)
- connection_bucket_init();
-#endif
-
old_ewma_enabled = cell_ewma_enabled();
/* Change the cell EWMA settings */
cell_ewma_set_scale_factor(options, networkstatus_get_latest_consensus());
@@ -1998,11 +2062,6 @@ static const struct {
{ "--list-fingerprint", TAKES_NO_ARGUMENT },
{ "--keygen", TAKES_NO_ARGUMENT },
{ "--newpass", TAKES_NO_ARGUMENT },
-#if 0
-/* XXXX028: This is not working yet in 0.2.7, so disabling with the
- * minimal code modification. */
- { "--master-key", ARGUMENT_NECESSARY },
-#endif
{ "--no-passphrase", TAKES_NO_ARGUMENT },
{ "--passphrase-fd", ARGUMENT_NECESSARY },
{ "--verify-config", TAKES_NO_ARGUMENT },
@@ -2014,6 +2073,7 @@ static const struct {
{ "-h", TAKES_NO_ARGUMENT },
{ "--help", TAKES_NO_ARGUMENT },
{ "--list-torrc-options", TAKES_NO_ARGUMENT },
+ { "--list-deprecated-options",TAKES_NO_ARGUMENT },
{ "--nt-service", TAKES_NO_ARGUMENT },
{ "-nt-service", TAKES_NO_ARGUMENT },
{ NULL, 0 },
@@ -2076,7 +2136,7 @@ config_parse_commandline(int argc, char **argv, int ignore_errors,
if (want_arg == ARGUMENT_NECESSARY && is_last) {
if (ignore_errors) {
- arg = strdup("");
+ arg = tor_strdup("");
} else {
log_warn(LD_CONFIG,"Command-line option '%s' with no value. Failing.",
argv[i]);
@@ -2150,31 +2210,30 @@ option_get_assignment(const or_options_t *options, const char *key)
* what went wrong.
*/
setopt_err_t
-options_trial_assign(config_line_t *list, int use_defaults,
- int clear_first, char **msg)
+options_trial_assign(config_line_t *list, unsigned flags, char **msg)
{
int r;
or_options_t *trial_options = config_dup(&options_format, get_options());
if ((r=config_assign(&options_format, trial_options,
- list, use_defaults, clear_first, msg)) < 0) {
- config_free(&options_format, trial_options);
+ list, flags, msg)) < 0) {
+ or_options_free(trial_options);
return r;
}
if (options_validate(get_options_mutable(), trial_options,
global_default_options, 1, msg) < 0) {
- config_free(&options_format, trial_options);
+ or_options_free(trial_options);
return SETOPT_ERR_PARSE; /*XXX make this a separate return value. */
}
if (options_transition_allowed(get_options(), trial_options, msg) < 0) {
- config_free(&options_format, trial_options);
+ or_options_free(trial_options);
return SETOPT_ERR_TRANSITION;
}
if (set_options(trial_options, msg)<0) {
- config_free(&options_format, trial_options);
+ or_options_free(trial_options);
return SETOPT_ERR_SETTING;
}
@@ -2200,7 +2259,6 @@ static void
list_torrc_options(void)
{
int i;
- smartlist_t *lines = smartlist_new();
for (i = 0; option_vars_[i].name; ++i) {
const config_var_t *var = &option_vars_[i];
if (var->type == CONFIG_TYPE_OBSOLETE ||
@@ -2208,7 +2266,16 @@ list_torrc_options(void)
continue;
printf("%s\n", var->name);
}
- smartlist_free(lines);
+}
+
+/** Print all deprecated but non-obsolete torrc options. */
+static void
+list_deprecated_options(void)
+{
+ const config_deprecation_t *d;
+ for (d = option_deprecation_notes_; d->name; ++d) {
+ printf("%s\n", d->name);
+ }
}
/** Last value actually set by resolve_my_address. */
@@ -2228,6 +2295,14 @@ reset_last_resolved_addr(void)
last_resolved_addr = 0;
}
+/* Return true if <b>options</b> is using the default authorities, and false
+ * if any authority-related option has been overridden. */
+int
+using_default_dir_authorities(const or_options_t *options)
+{
+ return (!options->DirAuthorities && !options->AlternateDirAuthority);
+}
+
/**
* Attempt getting our non-local (as judged by tor_addr_is_internal()
* function) IP address using following techniques, listed in
@@ -2387,7 +2462,7 @@ resolve_my_address(int warn_severity, const or_options_t *options,
addr_string = tor_dup_ip(addr);
if (tor_addr_is_internal(&myaddr, 0)) {
/* make sure we're ok with publishing an internal IP */
- if (!options->DirAuthorities && !options->AlternateDirAuthority) {
+ if (using_default_dir_authorities(options)) {
/* if they are using the default authorities, disallow internal IPs
* always. */
log_fn(warn_severity, LD_CONFIG,
@@ -2483,7 +2558,6 @@ is_local_addr, (const tor_addr_t *addr))
if (get_options()->EnforceDistinctSubnets == 0)
return 0;
if (tor_addr_family(addr) == AF_INET) {
- /*XXXX023 IP6 what corresponds to an /24? */
uint32_t ip = tor_addr_to_ipv4h(addr);
/* It's possible that this next check will hit before the first time
@@ -2677,7 +2751,7 @@ options_validate_cb(void *old_options, void *options, void *default_options,
#define REJECT(arg) \
STMT_BEGIN *msg = tor_strdup(arg); return -1; STMT_END
-#ifdef __GNUC__
+#if defined(__GNUC__) && __GNUC__ <= 3
#define COMPLAIN(args...) \
STMT_BEGIN log_warn(LD_CONFIG, args); STMT_END
#else
@@ -2735,6 +2809,71 @@ 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;
+ }
+
+ 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
@@ -2761,6 +2900,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) &&
@@ -2790,7 +2935,8 @@ options_validate(or_options_t *old_options, or_options_t *options,
} else {
if (!is_legal_nickname(options->Nickname)) {
tor_asprintf(msg,
- "Nickname '%s' is wrong length or contains illegal characters.",
+ "Nickname '%s', nicknames must be between 1 and 19 characters "
+ "inclusive, and must contain only the characters [a-zA-Z0-9].",
options->Nickname);
return -1;
}
@@ -2857,7 +3003,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
} else if (!strcasecmp(options->TransProxyType, "ipfw")) {
#ifndef KERNEL_MAY_SUPPORT_IPFW
/* Earlier versions of OS X have ipfw */
- REJECT("ipfw is a FreeBSD-specific"
+ REJECT("ipfw is a FreeBSD-specific "
"and OS X/Darwin-specific feature.");
#else
options->TransProxyType_parsed = TPT_IPFW;
@@ -3135,10 +3281,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));
@@ -3229,25 +3371,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
@@ -3267,8 +3395,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 "
@@ -3291,6 +3424,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,
@@ -3302,8 +3446,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) {
@@ -3493,10 +3644,10 @@ options_validate(or_options_t *old_options, or_options_t *options,
}
if (server_mode(options)) {
- char *msg = NULL;
- if (have_enough_mem_for_dircache(options, 0, &msg)) {
- log_warn(LD_CONFIG, "%s", msg);
- tor_free(msg);
+ char *dircache_msg = NULL;
+ if (have_enough_mem_for_dircache(options, 0, &dircache_msg)) {
+ log_warn(LD_CONFIG, "%s", dircache_msg);
+ tor_free(dircache_msg);
}
}
@@ -4126,11 +4277,11 @@ have_enough_mem_for_dircache(const or_options_t *options, size_t total_mem,
if (options->DirCache) {
if (total_mem < DIRCACHE_MIN_BANDWIDTH) {
if (options->BridgeRelay) {
- *msg = strdup("Running a Bridge with less than "
+ *msg = tor_strdup("Running a Bridge with less than "
STRINGIFY(DIRCACHE_MIN_MB_BANDWIDTH) " MB of memory is "
"not recommended.");
} else {
- *msg = strdup("Being a directory cache (default) with less than "
+ *msg = tor_strdup("Being a directory cache (default) with less than "
STRINGIFY(DIRCACHE_MIN_MB_BANDWIDTH) " MB of memory is "
"not recommended and may consume most of the available "
"resources, consider disabling this functionality by "
@@ -4139,7 +4290,7 @@ have_enough_mem_for_dircache(const or_options_t *options, size_t total_mem,
}
} else {
if (total_mem >= DIRCACHE_MIN_BANDWIDTH) {
- *msg = strdup("DirCache is disabled and we are configured as a "
+ *msg = tor_strdup("DirCache is disabled and we are configured as a "
"relay. This may disqualify us from becoming a guard in the "
"future.");
}
@@ -4233,9 +4384,16 @@ options_transition_allowed(const or_options_t *old,
return -1;
}
- if (old->DisableIOCP != new_val->DisableIOCP) {
- *msg = tor_strdup("While Tor is running, changing DisableIOCP "
- "is not allowed.");
+ 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;
}
@@ -4321,6 +4479,8 @@ options_transition_affects_descriptor(const or_options_t *old_options,
old_options->ExitRelay != new_options->ExitRelay ||
old_options->ExitPolicyRejectPrivate !=
new_options->ExitPolicyRejectPrivate ||
+ old_options->ExitPolicyRejectLocalInterfaces !=
+ new_options->ExitPolicyRejectLocalInterfaces ||
old_options->IPv6Exit != new_options->IPv6Exit ||
!config_lines_eq(old_options->ORPort_lines,
new_options->ORPort_lines) ||
@@ -4666,10 +4826,15 @@ options_init_from_torrc(int argc, char **argv)
exit(0);
}
if (config_line_find(cmdline_only_options, "--list-torrc-options")) {
- /* For documenting validating whether we've documented everything. */
+ /* For validating whether we've documented everything. */
list_torrc_options();
exit(0);
}
+ if (config_line_find(cmdline_only_options, "--list-deprecated-options")) {
+ /* For validating whether what we have deprecated really exists. */
+ list_deprecated_options();
+ exit(0);
+ }
if (config_line_find(cmdline_only_options, "--version")) {
printf("Tor version %s.\n",get_version());
@@ -4825,7 +4990,7 @@ options_init_from_string(const char *cf_defaults, const char *cf,
{
or_options_t *oldoptions, *newoptions, *newdefaultoptions=NULL;
config_line_t *cl;
- int retval, i;
+ int retval;
setopt_err_t err = SETOPT_ERR_MISC;
tor_assert(msg);
@@ -4838,7 +5003,7 @@ options_init_from_string(const char *cf_defaults, const char *cf,
newoptions->command = command;
newoptions->command_arg = command_arg ? tor_strdup(command_arg) : NULL;
- for (i = 0; i < 2; ++i) {
+ for (int i = 0; i < 2; ++i) {
const char *body = i==0 ? cf_defaults : cf;
if (!body)
continue;
@@ -4848,7 +5013,8 @@ options_init_from_string(const char *cf_defaults, const char *cf,
err = SETOPT_ERR_PARSE;
goto err;
}
- retval = config_assign(&options_format, newoptions, cl, 0, 0, msg);
+ retval = config_assign(&options_format, newoptions, cl,
+ CAL_WARN_DEPRECATIONS, msg);
config_free_lines(cl);
if (retval < 0) {
err = SETOPT_ERR_PARSE;
@@ -4864,7 +5030,7 @@ options_init_from_string(const char *cf_defaults, const char *cf,
/* Go through command-line variables too */
retval = config_assign(&options_format, newoptions,
- global_cmdline_options, 0, 0, msg);
+ global_cmdline_options, CAL_WARN_DEPRECATIONS, msg);
if (retval < 0) {
err = SETOPT_ERR_PARSE;
goto err;
@@ -4882,19 +5048,24 @@ options_init_from_string(const char *cf_defaults, const char *cf,
* let's clean it up. -NM */
/* Change defaults. */
- int i;
- for (i = 0; testing_tor_network_defaults[i].name; ++i) {
+ for (int i = 0; testing_tor_network_defaults[i].name; ++i) {
const config_var_t *new_var = &testing_tor_network_defaults[i];
config_var_t *old_var =
config_find_option_mutable(&options_format, new_var->name);
tor_assert(new_var);
tor_assert(old_var);
old_var->initvalue = new_var->initvalue;
+
+ if ((config_find_deprecation(&options_format, new_var->name))) {
+ log_warn(LD_GENERAL, "Testing options override the deprecated "
+ "option %s. Is that intentional?",
+ new_var->name);
+ }
}
/* Clear newoptions and re-initialize them with new defaults. */
- config_free(&options_format, newoptions);
- config_free(&options_format, newdefaultoptions);
+ or_options_free(newoptions);
+ or_options_free(newdefaultoptions);
newdefaultoptions = NULL;
newoptions = tor_malloc_zero(sizeof(or_options_t));
newoptions->magic_ = OR_OPTIONS_MAGIC;
@@ -4903,7 +5074,7 @@ options_init_from_string(const char *cf_defaults, const char *cf,
newoptions->command_arg = command_arg ? tor_strdup(command_arg) : NULL;
/* Assign all options a second time. */
- for (i = 0; i < 2; ++i) {
+ for (int i = 0; i < 2; ++i) {
const char *body = i==0 ? cf_defaults : cf;
if (!body)
continue;
@@ -4913,7 +5084,7 @@ options_init_from_string(const char *cf_defaults, const char *cf,
err = SETOPT_ERR_PARSE;
goto err;
}
- retval = config_assign(&options_format, newoptions, cl, 0, 0, msg);
+ retval = config_assign(&options_format, newoptions, cl, 0, msg);
config_free_lines(cl);
if (retval < 0) {
err = SETOPT_ERR_PARSE;
@@ -4924,7 +5095,7 @@ options_init_from_string(const char *cf_defaults, const char *cf,
}
/* Assign command-line variables a second time too */
retval = config_assign(&options_format, newoptions,
- global_cmdline_options, 0, 0, msg);
+ global_cmdline_options, 0, msg);
if (retval < 0) {
err = SETOPT_ERR_PARSE;
goto err;
@@ -4947,14 +5118,14 @@ options_init_from_string(const char *cf_defaults, const char *cf,
err = SETOPT_ERR_SETTING;
goto err; /* frees and replaces old options */
}
- config_free(&options_format, global_default_options);
+ or_options_free(global_default_options);
global_default_options = newdefaultoptions;
return SETOPT_OK;
err:
- config_free(&options_format, newoptions);
- config_free(&options_format, newdefaultoptions);
+ or_options_free(newoptions);
+ or_options_free(newdefaultoptions);
if (*msg) {
char *old_msg = *msg;
tor_asprintf(msg, "Failed to parse/validate config: %s", old_msg);
@@ -5024,7 +5195,7 @@ config_register_addressmaps(const or_options_t *options)
/** As addressmap_register(), but detect the wildcarded status of "from" and
* "to", and do not steal a reference to <b>to</b>. */
-/* XXXX024 move to connection_edge.c */
+/* XXXX move to connection_edge.c */
int
addressmap_register_auto(const char *from, const char *to,
time_t expires,
@@ -5076,7 +5247,7 @@ options_init_logs(const or_options_t *old_options, or_options_t *options,
config_line_t *opt;
int ok;
smartlist_t *elts;
- int daemon =
+ int run_as_daemon =
#ifdef _WIN32
0;
#else
@@ -5137,7 +5308,7 @@ options_init_logs(const or_options_t *old_options, or_options_t *options,
int err = smartlist_len(elts) &&
!strcasecmp(smartlist_get(elts,0), "stderr");
if (!validate_only) {
- if (daemon) {
+ if (run_as_daemon) {
log_warn(LD_CONFIG,
"Can't log to %s with RunAsDaemon set; skipping stdout",
err?"stderr":"stdout");
@@ -5166,19 +5337,19 @@ options_init_logs(const or_options_t *old_options, or_options_t *options,
char *fname = expand_filename(smartlist_get(elts, 1));
/* Truncate if TruncateLogFile is set and we haven't seen this option
line before. */
- int truncate = 0;
+ int truncate_log = 0;
if (options->TruncateLogFile) {
- truncate = 1;
+ truncate_log = 1;
if (old_options) {
config_line_t *opt2;
for (opt2 = old_options->Logs; opt2; opt2 = opt2->next)
if (!strcmp(opt->value, opt2->value)) {
- truncate = 0;
+ truncate_log = 0;
break;
}
}
}
- if (add_file_log(severity, fname, truncate) < 0) {
+ if (add_file_log(severity, fname, truncate_log) < 0) {
log_warn(LD_CONFIG, "Couldn't open file for 'Log %s': %s",
opt->value, strerror(errno));
ok = 0;
@@ -5256,10 +5427,14 @@ bridge_line_free(bridge_line_t *bridge_line)
tor_free(bridge_line);
}
-/** Read the contents of a Bridge line from <b>line</b>. Return 0
- * if the line is well-formed, and -1 if it isn't. If
- * <b>validate_only</b> is 0, and the line is well-formed, then add
- * the bridge described in the line to our internal bridge list.
+/** Parse the contents of a string, <b>line</b>, containing a Bridge line,
+ * into a bridge_line_t.
+ *
+ * Validates that the IP:PORT, fingerprint, and SOCKS arguments (given to the
+ * Pluggable Transport, if a one was specified) are well-formed.
+ *
+ * Returns NULL If the Bridge line could not be validated, and returns a
+ * bridge_line_t containing the parsed information otherwise.
*
* Bridge line format:
* Bridge [transport] IP:PORT [id-fingerprint] [k=v] [k=v] ...
@@ -5332,7 +5507,7 @@ parse_bridge_line(const char *line)
goto err;
}
if (base16_decode(bridge_line->digest, DIGEST_LEN,
- fingerprint, HEX_DIGEST_LEN)<0) {
+ fingerprint, HEX_DIGEST_LEN) != DIGEST_LEN) {
log_warn(LD_CONFIG, "Unable to decode Bridge key digest.");
goto err;
}
@@ -5775,7 +5950,7 @@ parse_dir_authority_line(const char *line, dirinfo_type_t required_type,
} else if (!strcmpstart(flag, "weight=")) {
int ok;
const char *wstring = flag + strlen("weight=");
- weight = tor_parse_double(wstring, 0, UINT64_MAX, &ok, NULL);
+ weight = tor_parse_double(wstring, 0, (double)UINT64_MAX, &ok, NULL);
if (!ok) {
log_warn(LD_CONFIG, "Invalid weight '%s' on DirAuthority line.",flag);
weight=1.0;
@@ -5783,7 +5958,8 @@ parse_dir_authority_line(const char *line, dirinfo_type_t required_type,
} else if (!strcasecmpstart(flag, "v3ident=")) {
char *idstr = flag + strlen("v3ident=");
if (strlen(idstr) != HEX_DIGEST_LEN ||
- base16_decode(v3_digest, DIGEST_LEN, idstr, HEX_DIGEST_LEN)<0) {
+ base16_decode(v3_digest, DIGEST_LEN,
+ idstr, HEX_DIGEST_LEN) != DIGEST_LEN) {
log_warn(LD_CONFIG, "Bad v3 identity digest '%s' on DirAuthority line",
flag);
} else {
@@ -5832,7 +6008,8 @@ parse_dir_authority_line(const char *line, dirinfo_type_t required_type,
fingerprint, (int)strlen(fingerprint));
goto err;
}
- if (base16_decode(digest, DIGEST_LEN, fingerprint, HEX_DIGEST_LEN)<0) {
+ if (base16_decode(digest, DIGEST_LEN,
+ fingerprint, HEX_DIGEST_LEN) != DIGEST_LEN) {
log_warn(LD_CONFIG, "Unable to decode DirAuthority key digest.");
goto err;
}
@@ -5900,8 +6077,8 @@ parse_dir_fallback_line(const char *line,
orport = (int)tor_parse_long(cp+strlen("orport="), 10,
1, 65535, &ok, NULL);
} else if (!strcmpstart(cp, "id=")) {
- ok = !base16_decode(id, DIGEST_LEN,
- cp+strlen("id="), strlen(cp)-strlen("id="));
+ ok = base16_decode(id, DIGEST_LEN, cp+strlen("id="),
+ strlen(cp)-strlen("id=")) == DIGEST_LEN;
} else if (!strcasecmpstart(cp, "ipv6=")) {
if (ipv6_addrport_ptr) {
log_warn(LD_CONFIG, "Redundant ipv6 addr/port on FallbackDir line");
@@ -5917,10 +6094,10 @@ parse_dir_fallback_line(const char *line,
ipv6_addrport_ptr = &ipv6_addrport;
}
} else if (!strcmpstart(cp, "weight=")) {
- int ok;
+ int num_ok;
const char *wstring = cp + strlen("weight=");
- weight = tor_parse_double(wstring, 0, UINT64_MAX, &ok, NULL);
- if (!ok) {
+ weight = tor_parse_double(wstring, 0, (double)UINT64_MAX, &num_ok, NULL);
+ if (!num_ok) {
log_warn(LD_CONFIG, "Invalid weight '%s' on FallbackDir line.", cp);
weight=1.0;
}
@@ -5983,6 +6160,8 @@ port_cfg_new(size_t namelen)
tor_assert(namelen <= SIZE_T_CEILING - sizeof(port_cfg_t) - 1);
port_cfg_t *cfg = tor_malloc_zero(sizeof(port_cfg_t) + namelen + 1);
cfg->entry_cfg.ipv4_traffic = 1;
+ cfg->entry_cfg.dns_request = 1;
+ cfg->entry_cfg.onion_traffic = 1;
cfg->entry_cfg.cache_ipv4_answers = 1;
cfg->entry_cfg.prefer_ipv6_virtaddr = 1;
return cfg;
@@ -6085,54 +6264,75 @@ warn_nonlocal_controller_ports(smartlist_t *ports, unsigned forbid_nonlocal)
} SMARTLIST_FOREACH_END(port);
}
-#ifdef HAVE_SYS_UN_H
-
-/** Parse the given <b>addrport</b> and set <b>path_out</b> if a Unix socket
- * path is found. Return 0 on success. On error, a negative value is
- * returned, -ENOENT if no Unix statement found, -EINVAL if the socket path
- * is empty and -ENOSYS if AF_UNIX is not supported (see function in the
- * #else statement below). */
-
+/**
+ * Take a string (<b>line</b>) that begins with either an address:port, a
+ * port, or an AF_UNIX address, optionally quoted, prefixed with
+ * "unix:". Parse that line, and on success, set <b>addrport_out</b> to a new
+ * string containing the beginning portion (without prefix). Iff there was a
+ * unix: prefix, set <b>is_unix_out</b> to true. On success, also set
+ * <b>rest_out</b> to point to the part of the line after the address portion.
+ *
+ * Return 0 on success, -1 on failure.
+ */
int
-config_parse_unix_port(const char *addrport, char **path_out)
+port_cfg_line_extract_addrport(const char *line,
+ char **addrport_out,
+ int *is_unix_out,
+ const char **rest_out)
{
- tor_assert(path_out);
- tor_assert(addrport);
-
- if (strcmpstart(addrport, unix_socket_prefix)) {
- /* Not a Unix socket path. */
- return -ENOENT;
- }
+ tor_assert(line);
+ tor_assert(addrport_out);
+ tor_assert(is_unix_out);
+ tor_assert(rest_out);
+
+ line = eat_whitespace(line);
+
+ if (!strcmpstart(line, unix_q_socket_prefix)) {
+ // It starts with unix:"
+ size_t sz;
+ *is_unix_out = 1;
+ *addrport_out = NULL;
+ line += strlen(unix_socket_prefix); /*No q: Keep the quote */
+ *rest_out = unescape_string(line, addrport_out, &sz);
+ if (!*rest_out || (*addrport_out && sz != strlen(*addrport_out))) {
+ tor_free(*addrport_out);
+ return -1;
+ }
+ *rest_out = eat_whitespace(*rest_out);
+ return 0;
+ } else {
+ // Is there a unix: prefix?
+ if (!strcmpstart(line, unix_socket_prefix)) {
+ line += strlen(unix_socket_prefix);
+ *is_unix_out = 1;
+ } else {
+ *is_unix_out = 0;
+ }
- if (strlen(addrport + strlen(unix_socket_prefix)) == 0) {
- /* Empty socket path, not very usable. */
- return -EINVAL;
+ const char *end = find_whitespace(line);
+ if (BUG(!end)) {
+ end = strchr(line, '\0'); // LCOV_EXCL_LINE -- this can't be NULL
+ }
+ tor_assert(end && end >= line);
+ *addrport_out = tor_strndup(line, end - line);
+ *rest_out = eat_whitespace(end);
+ return 0;
}
-
- *path_out = tor_strdup(addrport + strlen(unix_socket_prefix));
- return 0;
}
-#else /* defined(HAVE_SYS_UN_H) */
-
-int
-config_parse_unix_port(const char *addrport, char **path_out)
+static void
+warn_client_dns_cache(const char *option, int disabling)
{
- tor_assert(path_out);
- tor_assert(addrport);
-
- if (strcmpstart(addrport, unix_socket_prefix)) {
- /* Not a Unix socket path. */
- return -ENOENT;
- }
+ if (disabling)
+ return;
- log_warn(LD_CONFIG,
- "Port configuration %s is for an AF_UNIX socket, but we have no"
- "support available on this platform",
- escaped(addrport));
- return -ENOSYS;
+ warn_deprecated_option(option,
+ "Client-side DNS cacheing enables a wide variety of route-"
+ "capture attacks. If a single bad exit node lies to you about "
+ "an IP address, cacheing that address would make you visit "
+ "an address of the attacker's choice every time you connected "
+ "to your destination.");
}
-#endif /* defined(HAVE_SYS_UN_H) */
/**
* Parse port configuration for a single port type.
@@ -6239,8 +6439,7 @@ parse_port_config(smartlist_t *out,
tor_addr_make_unspec(&cfg->addr); /* Server ports default to 0.0.0.0 */
cfg->server_cfg.no_listen = 1;
cfg->server_cfg.bind_ipv4_only = 1;
- cfg->entry_cfg.ipv4_traffic = 1;
- cfg->entry_cfg.prefer_ipv6_virtaddr = 1;
+ /* cfg->entry_cfg defaults are already set by port_cfg_new */
smartlist_add(out, cfg);
}
@@ -6299,44 +6498,54 @@ parse_port_config(smartlist_t *out,
/* At last we can actually parse the FooPort lines. The syntax is:
* [Addr:](Port|auto) [Options].*/
elts = smartlist_new();
+ char *addrport = NULL;
for (; ports; ports = ports->next) {
tor_addr_t addr;
- int port, ret;
+ int port;
int sessiongroup = SESSION_GROUP_UNSET;
unsigned isolation = ISO_DEFAULT;
int prefer_no_auth = 0;
int socks_iso_keep_alive = 0;
- char *addrport;
uint16_t ptmp=0;
int ok;
+ /* This must be kept in sync with port_cfg_new's defaults */
int no_listen = 0, no_advertise = 0, all_addrs = 0,
bind_ipv4_only = 0, bind_ipv6_only = 0,
- ipv4_traffic = 1, ipv6_traffic = 0, prefer_ipv6 = 0,
+ ipv4_traffic = 1, ipv6_traffic = 0, prefer_ipv6 = 0, dns_request = 1,
+ onion_traffic = 1,
cache_ipv4 = 1, use_cached_ipv4 = 0,
cache_ipv6 = 0, use_cached_ipv6 = 0,
prefer_ipv6_automap = 1, world_writable = 0, group_writable = 0,
relax_dirmode_check = 0,
has_used_unix_socket_only_option = 0;
- smartlist_split_string(elts, ports->value, NULL,
- SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
- if (smartlist_len(elts) == 0) {
- log_warn(LD_CONFIG, "Invalid %sPort line with no value", portname);
+ int is_unix_tagged_addr = 0;
+ const char *rest_of_line = NULL;
+ if (port_cfg_line_extract_addrport(ports->value,
+ &addrport, &is_unix_tagged_addr, &rest_of_line)<0) {
+ log_warn(LD_CONFIG, "Invalid %sPort line with unparsable address",
+ portname);
+ goto err;
+ }
+ if (strlen(addrport) == 0) {
+ log_warn(LD_CONFIG, "Invalid %sPort line with no address", portname);
goto err;
}
- /* Now parse the addr/port value */
- addrport = smartlist_get(elts, 0);
+ /* Split the remainder... */
+ smartlist_split_string(elts, rest_of_line, NULL,
+ SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
/* Let's start to check if it's a Unix socket path. */
- ret = config_parse_unix_port(addrport, &unix_socket_path);
- if (ret < 0 && ret != -ENOENT) {
- if (ret == -EINVAL) {
- log_warn(LD_CONFIG, "Empty Unix socket path.");
- }
+ if (is_unix_tagged_addr) {
+#ifndef HAVE_SYS_UN_H
+ log_warn(LD_CONFIG, "Unix sockets not supported on this system.");
goto err;
+#endif
+ unix_socket_path = addrport;
+ addrport = NULL;
}
if (unix_socket_path &&
@@ -6348,6 +6557,8 @@ parse_port_config(smartlist_t *out,
if (unix_socket_path) {
port = 1;
} else if (is_unix_socket) {
+ if (BUG(!addrport))
+ goto err; // LCOV_EXCL_LINE unreachable, but coverity can't tell that
unix_socket_path = tor_strdup(addrport);
if (!strcmp(addrport, "0"))
port = 0;
@@ -6394,9 +6605,6 @@ parse_port_config(smartlist_t *out,
if (use_server_options) {
/* This is a server port; parse advertising options */
SMARTLIST_FOREACH_BEGIN(elts, char *, elt) {
- if (elt_sl_idx == 0)
- continue; /* Skip addr:port */
-
if (!strcasecmp(elt, "NoAdvertise")) {
no_advertise = 1;
} else if (!strcasecmp(elt, "NoListen")) {
@@ -6444,8 +6652,6 @@ parse_port_config(smartlist_t *out,
SMARTLIST_FOREACH_BEGIN(elts, char *, elt) {
int no = 0, isoflag = 0;
const char *elt_orig = elt;
- if (elt_sl_idx == 0)
- continue; /* Skip addr:port */
if (!strcasecmpstart(elt, "SessionGroup=")) {
int group = (int)tor_parse_long(elt+strlen("SessionGroup="),
@@ -6499,24 +6705,48 @@ parse_port_config(smartlist_t *out,
} else if (!strcasecmp(elt, "PreferIPv6")) {
prefer_ipv6 = ! no;
continue;
+ } else if (!strcasecmp(elt, "DNSRequest")) {
+ dns_request = ! no;
+ continue;
+ } else if (!strcasecmp(elt, "OnionTraffic")) {
+ onion_traffic = ! no;
+ continue;
+ } else if (!strcasecmp(elt, "OnionTrafficOnly")) {
+ /* Only connect to .onion addresses. Equivalent to
+ * NoDNSRequest, NoIPv4Traffic, NoIPv6Traffic. The option
+ * NoOnionTrafficOnly is not supported, it's too confusing. */
+ if (no) {
+ log_warn(LD_CONFIG, "Unsupported %sPort option 'No%s'. Use "
+ "DNSRequest, IPv4Traffic, and/or IPv6Traffic instead.",
+ portname, escaped(elt));
+ } else {
+ ipv4_traffic = ipv6_traffic = dns_request = 0;
+ }
+ continue;
}
}
if (!strcasecmp(elt, "CacheIPv4DNS")) {
+ warn_client_dns_cache(elt, no); // since 0.2.9.2-alpha
cache_ipv4 = ! no;
continue;
} else if (!strcasecmp(elt, "CacheIPv6DNS")) {
+ warn_client_dns_cache(elt, no); // since 0.2.9.2-alpha
cache_ipv6 = ! no;
continue;
} else if (!strcasecmp(elt, "CacheDNS")) {
+ warn_client_dns_cache(elt, no); // since 0.2.9.2-alpha
cache_ipv4 = cache_ipv6 = ! no;
continue;
} else if (!strcasecmp(elt, "UseIPv4Cache")) {
+ warn_client_dns_cache(elt, no); // since 0.2.9.2-alpha
use_cached_ipv4 = ! no;
continue;
} else if (!strcasecmp(elt, "UseIPv6Cache")) {
+ warn_client_dns_cache(elt, no); // since 0.2.9.2-alpha
use_cached_ipv6 = ! no;
continue;
} else if (!strcasecmp(elt, "UseDNSCache")) {
+ warn_client_dns_cache(elt, no); // since 0.2.9.2-alpha
use_cached_ipv4 = use_cached_ipv6 = ! no;
continue;
} else if (!strcasecmp(elt, "PreferIPv6Automap")) {
@@ -6561,9 +6791,24 @@ parse_port_config(smartlist_t *out,
else
got_zero_port = 1;
- if (ipv4_traffic == 0 && ipv6_traffic == 0) {
- log_warn(LD_CONFIG, "You have a %sPort entry with both IPv4 and "
- "IPv6 disabled; that won't work.", portname);
+ if (dns_request == 0 && listener_type == CONN_TYPE_AP_DNS_LISTENER) {
+ log_warn(LD_CONFIG, "You have a %sPort entry with DNS disabled; that "
+ "won't work.", portname);
+ goto err;
+ }
+
+ if (ipv4_traffic == 0 && ipv6_traffic == 0 && onion_traffic == 0
+ && listener_type != CONN_TYPE_AP_DNS_LISTENER) {
+ log_warn(LD_CONFIG, "You have a %sPort entry with all of IPv4 and "
+ "IPv6 and .onion disabled; that won't work.", portname);
+ goto err;
+ }
+
+ if (dns_request == 1 && ipv4_traffic == 0 && ipv6_traffic == 0
+ && listener_type != CONN_TYPE_AP_DNS_LISTENER) {
+ log_warn(LD_CONFIG, "You have a %sPort entry with DNSRequest enabled, "
+ "but IPv4 and IPv6 disabled; DNS-based sites won't work.",
+ portname);
goto err;
}
@@ -6581,6 +6826,13 @@ parse_port_config(smartlist_t *out,
goto err;
}
+ if (unix_socket_path && (isolation & ISO_CLIENTADDR)) {
+ /* `IsolateClientAddr` is nonsensical in the context of AF_LOCAL.
+ * just silently remove the isolation flag.
+ */
+ isolation &= ~ISO_CLIENTADDR;
+ }
+
if (out && port) {
size_t namelen = unix_socket_path ? strlen(unix_socket_path) : 0;
port_cfg_t *cfg = port_cfg_new(namelen);
@@ -6607,6 +6859,8 @@ parse_port_config(smartlist_t *out,
cfg->entry_cfg.ipv4_traffic = ipv4_traffic;
cfg->entry_cfg.ipv6_traffic = ipv6_traffic;
cfg->entry_cfg.prefer_ipv6 = prefer_ipv6;
+ cfg->entry_cfg.dns_request = dns_request;
+ cfg->entry_cfg.onion_traffic = onion_traffic;
cfg->entry_cfg.cache_ipv4_answers = cache_ipv4;
cfg->entry_cfg.cache_ipv6_answers = cache_ipv6;
cfg->entry_cfg.use_cached_ipv4_answers = use_cached_ipv4;
@@ -6621,6 +6875,7 @@ parse_port_config(smartlist_t *out,
}
SMARTLIST_FOREACH(elts, char *, cp, tor_free(cp));
smartlist_clear(elts);
+ tor_free(addrport);
}
if (warn_nonlocal && out) {
@@ -6644,18 +6899,22 @@ parse_port_config(smartlist_t *out,
SMARTLIST_FOREACH(elts, char *, cp, tor_free(cp));
smartlist_free(elts);
tor_free(unix_socket_path);
+ tor_free(addrport);
return retval;
}
/** 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;
@@ -6664,9 +6923,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.
*
@@ -6792,21 +7050,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,
@@ -6836,6 +7095,24 @@ parse_ports(or_options_t *options, int validate_only,
return retval;
}
+/* Does port bind to IPv4? */
+static int
+port_binds_ipv4(const port_cfg_t *port)
+{
+ return tor_addr_family(&port->addr) == AF_INET ||
+ (tor_addr_family(&port->addr) == AF_UNSPEC
+ && !port->server_cfg.bind_ipv6_only);
+}
+
+/* Does port bind to IPv6? */
+static int
+port_binds_ipv6(const port_cfg_t *port)
+{
+ return tor_addr_family(&port->addr) == AF_INET6 ||
+ (tor_addr_family(&port->addr) == AF_UNSPEC
+ && !port->server_cfg.bind_ipv4_only);
+}
+
/** Given a list of <b>port_cfg_t</b> in <b>ports</b>, check them for internal
* consistency and warn as appropriate. Set *<b>n_low_ports_out</b> to the
* number of sub-1024 ports we will be binding. */
@@ -6861,9 +7138,7 @@ check_server_ports(const smartlist_t *ports,
} else if (port->type == CONN_TYPE_OR_LISTENER) {
if (! port->server_cfg.no_advertise) {
++n_orport_advertised;
- if (tor_addr_family(&port->addr) == AF_INET ||
- (tor_addr_family(&port->addr) == AF_UNSPEC &&
- !port->server_cfg.bind_ipv6_only))
+ if (port_binds_ipv4(port))
++n_orport_advertised_ipv4;
}
if (! port->server_cfg.no_listen)
@@ -6997,19 +7272,20 @@ get_first_listener_addrport_string(int listener_type)
}
/** Return the first advertised port of type <b>listener_type</b> in
- <b>address_family</b>. */
+ * <b>address_family</b>. Returns 0 when no port is found, and when passed
+ * AF_UNSPEC. */
int
get_first_advertised_port_by_type_af(int listener_type, int address_family)
{
+ if (address_family == AF_UNSPEC)
+ return 0;
+
const smartlist_t *conf_ports = get_configured_ports();
SMARTLIST_FOREACH_BEGIN(conf_ports, const port_cfg_t *, cfg) {
if (cfg->type == listener_type &&
- !cfg->server_cfg.no_advertise &&
- (tor_addr_family(&cfg->addr) == address_family ||
- tor_addr_family(&cfg->addr) == AF_UNSPEC)) {
- if (tor_addr_family(&cfg->addr) != AF_UNSPEC ||
- (address_family == AF_INET && !cfg->server_cfg.bind_ipv6_only) ||
- (address_family == AF_INET6 && !cfg->server_cfg.bind_ipv4_only)) {
+ !cfg->server_cfg.no_advertise) {
+ if ((address_family == AF_INET && port_binds_ipv4(cfg)) ||
+ (address_family == AF_INET6 && port_binds_ipv6(cfg))) {
return cfg->port;
}
}
@@ -7017,6 +7293,87 @@ get_first_advertised_port_by_type_af(int listener_type, int address_family)
return 0;
}
+/** Return the first advertised address of type <b>listener_type</b> in
+ * <b>address_family</b>. Returns NULL if there is no advertised address,
+ * and when passed AF_UNSPEC. */
+const tor_addr_t *
+get_first_advertised_addr_by_type_af(int listener_type, int address_family)
+{
+ if (address_family == AF_UNSPEC)
+ return NULL;
+ if (!configured_ports)
+ return NULL;
+ SMARTLIST_FOREACH_BEGIN(configured_ports, const port_cfg_t *, cfg) {
+ if (cfg->type == listener_type &&
+ !cfg->server_cfg.no_advertise) {
+ if ((address_family == AF_INET && port_binds_ipv4(cfg)) ||
+ (address_family == AF_INET6 && port_binds_ipv6(cfg))) {
+ return &cfg->addr;
+ }
+ }
+ } SMARTLIST_FOREACH_END(cfg);
+ return NULL;
+}
+
+/** Return 1 if a port exists of type <b>listener_type</b> on <b>addr</b> and
+ * <b>port</b>. If <b>check_wildcard</b> is true, INADDR[6]_ANY and AF_UNSPEC
+ * addresses match any address of the appropriate family; and port -1 matches
+ * any port.
+ * To match auto ports, pass CFG_PORT_AUTO. (Does not match on the actual
+ * automatically chosen listener ports.) */
+int
+port_exists_by_type_addr_port(int listener_type, const tor_addr_t *addr,
+ int port, int check_wildcard)
+{
+ if (!configured_ports || !addr)
+ return 0;
+ SMARTLIST_FOREACH_BEGIN(configured_ports, const port_cfg_t *, cfg) {
+ if (cfg->type == listener_type) {
+ if (cfg->port == port || (check_wildcard && port == -1)) {
+ /* Exact match */
+ if (tor_addr_eq(&cfg->addr, addr)) {
+ return 1;
+ }
+ /* Skip wildcard matches if we're not doing them */
+ if (!check_wildcard) {
+ continue;
+ }
+ /* Wildcard matches IPv4 */
+ const int cfg_v4 = port_binds_ipv4(cfg);
+ const int cfg_any_v4 = tor_addr_is_null(&cfg->addr) && cfg_v4;
+ const int addr_v4 = tor_addr_family(addr) == AF_INET ||
+ tor_addr_family(addr) == AF_UNSPEC;
+ const int addr_any_v4 = tor_addr_is_null(&cfg->addr) && addr_v4;
+ if ((cfg_any_v4 && addr_v4) || (cfg_v4 && addr_any_v4)) {
+ return 1;
+ }
+ /* Wildcard matches IPv6 */
+ const int cfg_v6 = port_binds_ipv6(cfg);
+ const int cfg_any_v6 = tor_addr_is_null(&cfg->addr) && cfg_v6;
+ const int addr_v6 = tor_addr_family(addr) == AF_INET6 ||
+ tor_addr_family(addr) == AF_UNSPEC;
+ const int addr_any_v6 = tor_addr_is_null(&cfg->addr) && addr_v6;
+ if ((cfg_any_v6 && addr_v6) || (cfg_v6 && addr_any_v6)) {
+ return 1;
+ }
+ }
+ }
+ } SMARTLIST_FOREACH_END(cfg);
+ return 0;
+}
+
+/* Like port_exists_by_type_addr_port, but accepts a host-order IPv4 address
+ * instead. */
+int
+port_exists_by_type_addr32h_port(int listener_type, uint32_t addr_ipv4h,
+ int port, int check_wildcard)
+{
+ tor_addr_t ipv4;
+ tor_addr_from_ipv4h(&ipv4, addr_ipv4h);
+ return port_exists_by_type_addr_port(listener_type, &ipv4, port,
+ check_wildcard);
+}
+
/** Adjust the value of options->DataDirectory, or fill it in if it's
* absent. Return 0 on success, -1 on failure. */
static int
@@ -7202,10 +7559,7 @@ init_libevent(const or_options_t *options)
*/
suppress_libevent_log_msg("Function not implemented");
- tor_check_libevent_header_compatibility();
-
memset(&cfg, 0, sizeof(cfg));
- cfg.disable_iocp = options->DisableIOCP;
cfg.num_cpus = get_num_cpus(options);
cfg.msec_per_tick = options->TokenBucketRefillInterval;
@@ -7228,10 +7582,10 @@ init_libevent(const or_options_t *options)
*
* Note: Consider using the get_datadir_fname* macros in or.h.
*/
-char *
-options_get_datadir_fname2_suffix(const or_options_t *options,
- const char *sub1, const char *sub2,
- const char *suffix)
+MOCK_IMPL(char *,
+options_get_datadir_fname2_suffix,(const or_options_t *options,
+ const char *sub1, const char *sub2,
+ const char *suffix))
{
char *fname = NULL;
size_t len;
@@ -7412,8 +7766,8 @@ getinfo_helper_config(control_connection_t *conn,
smartlist_free(sl);
} else if (!strcmp(question, "config/defaults")) {
smartlist_t *sl = smartlist_new();
- int i, dirauth_lines_seen = 0, fallback_lines_seen = 0;
- for (i = 0; option_vars_[i].name; ++i) {
+ int dirauth_lines_seen = 0, fallback_lines_seen = 0;
+ for (int i = 0; option_vars_[i].name; ++i) {
const config_var_t *var = &option_vars_[i];
if (var->initvalue != NULL) {
if (strcmp(option_vars_[i].name, "DirAuthority") == 0) {
@@ -7441,14 +7795,13 @@ getinfo_helper_config(control_connection_t *conn,
* We didn't see any directory authorities with default values,
* so add the list of default authorities manually.
*/
- const char **i;
/*
* default_authorities is defined earlier in this file and
* is a const char ** NULL-terminated array of dirauth config
* lines.
*/
- for (i = default_authorities; *i != NULL; ++i) {
+ for (const char **i = default_authorities; *i != NULL; ++i) {
char *val = esc_for_log(*i);
smartlist_add_asprintf(sl, "DirAuthority %s\n", val);
tor_free(val);
@@ -7565,7 +7918,7 @@ static void
config_maybe_load_geoip_files_(const or_options_t *options,
const or_options_t *old_options)
{
- /* XXXX024 Reload GeoIPFile on SIGHUP. -NM */
+ /* XXXX Reload GeoIPFile on SIGHUP. -NM */
if (options->GeoIPFile &&
((!old_options || !opt_streq(old_options->GeoIPFile,