aboutsummaryrefslogtreecommitdiff
path: root/src/or/config.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/or/config.c')
-rw-r--r--src/or/config.c2886
1 files changed, 2061 insertions, 825 deletions
diff --git a/src/or/config.c b/src/or/config.c
index fde88ad680..fa860af337 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -1,7 +1,7 @@
- /* Copyright (c) 2001 Matej Pfajfar.
+/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -10,8 +10,8 @@
**/
#define CONFIG_PRIVATE
-
#include "or.h"
+#include "compat.h"
#include "addressmap.h"
#include "channel.h"
#include "circuitbuild.h"
@@ -40,20 +40,37 @@
#include "rendservice.h"
#include "rephist.h"
#include "router.h"
+#include "sandbox.h"
#include "util.h"
#include "routerlist.h"
#include "routerset.h"
+#include "scheduler.h"
#include "statefile.h"
#include "transports.h"
+#include "ext_orport.h"
+#include "torgzip.h"
#ifdef _WIN32
#include <shlobj.h>
#endif
#include "procmon.h"
+#ifdef HAVE_SYSTEMD
+# if defined(__COVERITY__) && !defined(__INCLUDE_LEVEL__)
+/* Systemd's use of gcc's __INCLUDE_LEVEL__ extension macro appears to confuse
+ * Coverity. Here's a kludge to unconfuse it.
+ */
+# define __INCLUDE_LEVEL__ 2
+# endif
+#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:";
+
/** A list of abbreviations and aliases to map command-line options, obsolete
* option names, or alternative option names, to their current values. */
static config_abbrev_t option_abbrevs_[] = {
@@ -61,15 +78,16 @@ static config_abbrev_t option_abbrevs_[] = {
PLURAL(AuthDirBadExitCC),
PLURAL(AuthDirInvalidCC),
PLURAL(AuthDirRejectCC),
- PLURAL(ExitNode),
PLURAL(EntryNode),
PLURAL(ExcludeNode),
+ PLURAL(Tor2webRendezvousPoint),
PLURAL(FirewallPort),
PLURAL(LongLivedPort),
PLURAL(HiddenServiceNode),
PLURAL(HiddenServiceExcludeNode),
PLURAL(NumCPU),
PLURAL(RendNode),
+ PLURAL(RecommendedPackage),
PLURAL(RendExcludeNode),
PLURAL(StrictEntryNode),
PLURAL(StrictExitNode),
@@ -83,6 +101,7 @@ static config_abbrev_t option_abbrevs_[] = {
{ "DirFetchPostPeriod", "StatusFetchPeriod", 0, 0},
{ "DirServer", "DirAuthority", 0, 0}, /* XXXX024 later, make this warn? */
{ "MaxConn", "ConnLimit", 0, 1},
+ { "MaxMemInCellQueues", "MaxMemInQueues", 0, 0},
{ "ORBindAddress", "ORListenAddress", 0, 0},
{ "DirBindAddress", "DirListenAddress", 0, 0},
{ "SocksBindAddress", "SocksListenAddress", 0, 0},
@@ -96,8 +115,6 @@ static config_abbrev_t option_abbrevs_[] = {
{ "PreferTunnelledDirConns", "PreferTunneledDirConns", 0, 0},
{ "BridgeAuthoritativeDirectory", "BridgeAuthoritativeDir", 0, 0},
{ "HashedControlPassword", "__HashedControlSessionPassword", 1, 0},
- { "StrictEntryNodes", "StrictNodes", 0, 1},
- { "StrictExitNodes", "StrictNodes", 0, 1},
{ "VirtualAddrNetwork", "VirtualAddrNetworkIPv4", 0, 0},
{ "_UseFilteringSSLBufferevents", "UseFilteringSSLBufferevents", 0, 1},
{ NULL, NULL, 0, 0},
@@ -124,8 +141,8 @@ static config_abbrev_t option_abbrevs_[] = {
* be chosen first.
*/
static config_var_t option_vars_[] = {
- OBSOLETE("AccountingMaxKB"),
V(AccountingMax, MEMUNIT, "0 bytes"),
+ VAR("AccountingRule", STRING, AccountingRule_option, "max"),
V(AccountingStart, STRING, NULL),
V(Address, STRING, NULL),
V(AllowDotExit, BOOL, "0"),
@@ -135,20 +152,21 @@ static config_var_t option_vars_[] = {
V(AllowSingleHopExits, BOOL, "0"),
V(AlternateBridgeAuthority, LINELIST, NULL),
V(AlternateDirAuthority, LINELIST, NULL),
- V(AlternateHSAuthority, LINELIST, NULL),
+ OBSOLETE("AlternateHSAuthority"),
V(AssumeReachable, BOOL, "0"),
- V(AuthDirBadDir, LINELIST, NULL),
- V(AuthDirBadDirCCs, CSV, ""),
+ OBSOLETE("AuthDirBadDir"),
+ OBSOLETE("AuthDirBadDirCCs"),
V(AuthDirBadExit, LINELIST, NULL),
V(AuthDirBadExitCCs, CSV, ""),
V(AuthDirInvalid, LINELIST, NULL),
V(AuthDirInvalidCCs, CSV, ""),
V(AuthDirFastGuarantee, MEMUNIT, "100 KB"),
- V(AuthDirGuardBWGuarantee, MEMUNIT, "250 KB"),
+ V(AuthDirGuardBWGuarantee, MEMUNIT, "2 MB"),
+ V(AuthDirPinKeys, BOOL, "0"),
V(AuthDirReject, LINELIST, NULL),
V(AuthDirRejectCCs, CSV, ""),
- V(AuthDirRejectUnlisted, BOOL, "0"),
- V(AuthDirListBadDirs, BOOL, "0"),
+ OBSOLETE("AuthDirRejectUnlisted"),
+ OBSOLETE("AuthDirListBadDirs"),
V(AuthDirListBadExits, BOOL, "0"),
V(AuthDirMaxServersPerAddr, UINT, "2"),
V(AuthDirMaxServersPerAuthAddr,UINT, "5"),
@@ -188,36 +206,33 @@ static config_var_t option_vars_[] = {
V(ControlPortWriteToFile, FILENAME, NULL),
V(ControlSocket, LINELIST, NULL),
V(ControlSocketsGroupWritable, BOOL, "0"),
+ V(SocksSocketsGroupWritable, BOOL, "0"),
V(CookieAuthentication, BOOL, "0"),
V(CookieAuthFileGroupReadable, BOOL, "0"),
V(CookieAuthFile, STRING, NULL),
V(CountPrivateBandwidth, BOOL, "0"),
V(DataDirectory, FILENAME, NULL),
- OBSOLETE("DebugLogFile"),
V(DisableNetwork, BOOL, "0"),
V(DirAllowPrivateAddresses, BOOL, "0"),
V(TestingAuthDirTimeToLearnReachability, INTERVAL, "30 minutes"),
V(DirListenAddress, LINELIST, NULL),
- OBSOLETE("DirFetchPeriod"),
V(DirPolicy, LINELIST, NULL),
VPORT(DirPort, LINELIST, NULL),
V(DirPortFrontPage, FILENAME, NULL),
- OBSOLETE("DirPostPeriod"),
- OBSOLETE("DirRecordUsageByCountry"),
- OBSOLETE("DirRecordUsageGranularity"),
- OBSOLETE("DirRecordUsageRetainIPs"),
- OBSOLETE("DirRecordUsageSaveInterval"),
- V(DirReqStatistics, BOOL, "1"),
+ VAR("DirReqStatistics", BOOL, DirReqStatistics_option, "1"),
VAR("DirAuthority", LINELIST, DirAuthorities, NULL),
V(DirAuthorityFallbackRate, DOUBLE, "1.0"),
V(DisableAllSwap, BOOL, "0"),
V(DisableDebuggerAttachment, BOOL, "1"),
V(DisableIOCP, BOOL, "1"),
- V(DisableV2DirectoryInfo_, BOOL, "0"),
- V(DynamicDHGroups, BOOL, "0"),
+ OBSOLETE("DisableV2DirectoryInfo_"),
+ OBSOLETE("DynamicDHGroups"),
VPORT(DNSPort, LINELIST, NULL),
V(DNSListenAddress, LINELIST, NULL),
V(DownloadExtraInfo, BOOL, "0"),
+ V(TestingEnableConnBwEvent, BOOL, "0"),
+ V(TestingEnableCellStatsEvent, BOOL, "0"),
+ V(TestingEnableTbEmptyEvent, BOOL, "0"),
V(EnforceDistinctSubnets, BOOL, "1"),
V(EntryNodes, ROUTERSET, NULL),
V(EntryStatistics, BOOL, "0"),
@@ -230,6 +245,10 @@ static config_var_t option_vars_[] = {
V(ExitPolicyRejectPrivate, BOOL, "1"),
V(ExitPortStatistics, BOOL, "0"),
V(ExtendAllowPrivateAddresses, BOOL, "0"),
+ V(ExitRelay, AUTOBOOL, "auto"),
+ VPORT(ExtORPort, LINELIST, NULL),
+ V(ExtORPortCookieAuthFile, STRING, NULL),
+ V(ExtORPortCookieAuthFileGroupReadable, BOOL, "0"),
V(ExtraInfoStatistics, BOOL, "1"),
V(FallbackDir, LINELIST, NULL),
@@ -242,7 +261,7 @@ static config_var_t option_vars_[] = {
V(FetchServerDescriptors, BOOL, "1"),
V(FetchHidServDescriptors, BOOL, "1"),
V(FetchUselessDescriptors, BOOL, "0"),
- V(FetchV2Networkstatus, BOOL, "0"),
+ OBSOLETE("FetchV2Networkstatus"),
V(GeoIPExcludeUnknown, AUTOBOOL, "auto"),
#ifdef _WIN32
V(GeoIPFile, FILENAME, "<default>"),
@@ -253,7 +272,6 @@ static config_var_t option_vars_[] = {
V(GeoIPv6File, FILENAME,
SHARE_DATADIR PATH_SEPARATOR "tor" PATH_SEPARATOR "geoip6"),
#endif
- OBSOLETE("GiveGuardFlagTo_CVE_2011_2768_VulnerableRelays"),
OBSOLETE("Group"),
V(GuardLifetime, INTERVAL, "0 minutes"),
V(HardwareAccel, BOOL, "0"),
@@ -261,17 +279,19 @@ static config_var_t option_vars_[] = {
V(AccelName, STRING, NULL),
V(AccelDir, FILENAME, NULL),
V(HashedControlPassword, LINELIST, NULL),
- V(HidServDirectoryV2, BOOL, "1"),
+ OBSOLETE("HidServDirectoryV2"),
VAR("HiddenServiceDir", LINELIST_S, RendConfigLines, NULL),
- OBSOLETE("HiddenServiceExcludeNodes"),
- OBSOLETE("HiddenServiceNodes"),
+ VAR("HiddenServiceDirGroupReadable", LINELIST_S, RendConfigLines, NULL),
VAR("HiddenServiceOptions",LINELIST_V, RendConfigLines, NULL),
VAR("HiddenServicePort", LINELIST_S, RendConfigLines, NULL),
VAR("HiddenServiceVersion",LINELIST_S, RendConfigLines, NULL),
VAR("HiddenServiceAuthorizeClient",LINELIST_S,RendConfigLines, NULL),
+ VAR("HiddenServiceAllowUnknownPorts",LINELIST_S, RendConfigLines, NULL),
+ VAR("HiddenServiceMaxStreams",LINELIST_S, RendConfigLines, NULL),
+ VAR("HiddenServiceMaxStreamsCloseCircuit",LINELIST_S, RendConfigLines, NULL),
+ VAR("HiddenServiceNumIntroductionPoints", LINELIST_S, RendConfigLines, NULL),
+ V(HiddenServiceStatistics, BOOL, "1"),
V(HidServAuth, LINELIST, NULL),
- V(HSAuthoritativeDir, BOOL, "0"),
- OBSOLETE("HSAuthorityRecordStats"),
V(CloseHSClientCircuitsImmediatelyOnTimeout, BOOL, "0"),
V(CloseHSServiceRendCircuitsImmediatelyOnTimeout, BOOL, "0"),
V(HTTPProxy, STRING, NULL),
@@ -281,41 +301,40 @@ static config_var_t option_vars_[] = {
V(IPv6Exit, BOOL, "0"),
VAR("ServerTransportPlugin", LINELIST, ServerTransportPlugin, NULL),
V(ServerTransportListenAddr, LINELIST, NULL),
+ V(ServerTransportOptions, LINELIST, NULL),
+ V(SigningKeyLifetime, INTERVAL, "30 days"),
V(Socks4Proxy, STRING, NULL),
V(Socks5Proxy, STRING, NULL),
V(Socks5ProxyUsername, STRING, NULL),
V(Socks5ProxyPassword, STRING, NULL),
- OBSOLETE("IgnoreVersion"),
V(KeepalivePeriod, INTERVAL, "5 minutes"),
VAR("Log", LINELIST, Logs, NULL),
V(LogMessageDomains, BOOL, "0"),
- OBSOLETE("LinkPadding"),
- OBSOLETE("LogLevel"),
- OBSOLETE("LogFile"),
V(LogTimeGranularity, MSEC_INTERVAL, "1 second"),
+ V(TruncateLogFile, BOOL, "0"),
V(LongLivedPorts, CSV,
"21,22,706,1863,5050,5190,5222,5223,6523,6667,6697,8300"),
VAR("MapAddress", LINELIST, AddressMap, NULL),
V(MaxAdvertisedBandwidth, MEMUNIT, "1 GB"),
V(MaxCircuitDirtiness, INTERVAL, "10 minutes"),
V(MaxClientCircuitsPending, UINT, "32"),
- V(MaxMemInCellQueues, MEMUNIT, "8 GB"),
+ VAR("MaxMemInQueues", MEMUNIT, MaxMemInQueues_raw, "0"),
OBSOLETE("MaxOnionsPending"),
V(MaxOnionQueueDelay, MSEC_INTERVAL, "1750 msec"),
V(MinMeasuredBWsForAuthToIgnoreAdvertised, INT, "500"),
- OBSOLETE("MonthlyAccountingStart"),
V(MyFamily, STRING, NULL),
V(NewCircuitPeriod, INTERVAL, "30 seconds"),
- VAR("NamingAuthoritativeDirectory",BOOL, NamingAuthoritativeDir, "0"),
+ OBSOLETE("NamingAuthoritativeDirectory"),
V(NATDListenAddress, LINELIST, NULL),
VPORT(NATDPort, LINELIST, NULL),
V(Nickname, STRING, NULL),
+ V(PredictedPortsRelevanceTime, INTERVAL, "1 hour"),
V(WarnUnsafeSocks, BOOL, "1"),
- OBSOLETE("NoPublish"),
VAR("NodeFamily", LINELIST, NodeFamilies, NULL),
V(NumCPUs, UINT, "0"),
V(NumDirectoryGuards, UINT, "0"),
V(NumEntryGuards, UINT, "0"),
+ V(OfflineMasterKey, BOOL, "0"),
V(ORListenAddress, LINELIST, NULL),
VPORT(ORPort, LINELIST, NULL),
V(OutboundBindAddress, LINELIST, NULL),
@@ -337,17 +356,23 @@ static config_var_t option_vars_[] = {
V(PathBiasScaleUseThreshold, INT, "-1"),
V(PathsNeededToBuildCircuits, DOUBLE, "-1"),
- OBSOLETE("PathlenCoinWeight"),
V(PerConnBWBurst, MEMUNIT, "0"),
V(PerConnBWRate, MEMUNIT, "0"),
V(PidFile, STRING, NULL),
V(TestingTorNetwork, BOOL, "0"),
V(TestingMinExitFlagThreshold, MEMUNIT, "0"),
V(TestingMinFastFlagThreshold, MEMUNIT, "0"),
+
+ V(TestingLinkCertLifetime, INTERVAL, "2 days"),
+ V(TestingAuthKeyLifetime, INTERVAL, "2 days"),
+ V(TestingLinkKeySlop, INTERVAL, "3 hours"),
+ V(TestingAuthKeySlop, INTERVAL, "3 hours"),
+ V(TestingSigningKeySlop, INTERVAL, "1 day"),
+
V(OptimisticData, AUTOBOOL, "auto"),
V(PortForwarding, BOOL, "0"),
V(PortForwardingHelper, FILENAME, "tor-fw-helper"),
- V(PreferTunneledDirConns, BOOL, "1"),
+ OBSOLETE("PreferTunneledDirConns"),
V(ProtocolWarnings, BOOL, "0"),
V(PublishServerDescriptor, CSV, "1"),
V(PublishHidServDescriptors, BOOL, "1"),
@@ -357,19 +382,16 @@ static config_var_t option_vars_[] = {
V(RecommendedVersions, LINELIST, NULL),
V(RecommendedClientVersions, LINELIST, NULL),
V(RecommendedServerVersions, LINELIST, NULL),
- OBSOLETE("RedirectExit"),
+ V(RecommendedPackages, LINELIST, NULL),
V(RefuseUnknownExits, AUTOBOOL, "auto"),
V(RejectPlaintextPorts, CSV, ""),
V(RelayBandwidthBurst, MEMUNIT, "0"),
V(RelayBandwidthRate, MEMUNIT, "0"),
- OBSOLETE("RendExcludeNodes"),
- OBSOLETE("RendNodes"),
V(RendPostPeriod, INTERVAL, "1 hour"),
V(RephistTrackTime, INTERVAL, "24 hours"),
- OBSOLETE("RouterFile"),
V(RunAsDaemon, BOOL, "0"),
-// V(RunTesting, BOOL, "0"),
OBSOLETE("RunTesting"), // currently unused
+ V(Sandbox, BOOL, "0"),
V(SafeLogging, STRING, "1"),
V(SafeSocks, BOOL, "0"),
V(ServerDNSAllowBrokenConfig, BOOL, "1"),
@@ -380,48 +402,55 @@ static config_var_t option_vars_[] = {
V(ServerDNSSearchDomains, BOOL, "0"),
V(ServerDNSTestAddresses, CSV,
"www.google.com,www.mit.edu,www.yahoo.com,www.slashdot.org"),
+ V(SchedulerLowWaterMark__, MEMUNIT, "100 MB"),
+ V(SchedulerHighWaterMark__, MEMUNIT, "101 MB"),
+ V(SchedulerMaxFlushCells__, UINT, "1000"),
V(ShutdownWaitLength, INTERVAL, "30 seconds"),
V(SocksListenAddress, LINELIST, NULL),
V(SocksPolicy, LINELIST, NULL),
VPORT(SocksPort, LINELIST, NULL),
V(SocksTimeout, INTERVAL, "2 minutes"),
V(SSLKeyLifetime, INTERVAL, "0"),
- OBSOLETE("StatusFetchPeriod"),
+ OBSOLETE("StrictEntryNodes"),
+ OBSOLETE("StrictExitNodes"),
V(StrictNodes, BOOL, "0"),
- V(Support022HiddenServices, AUTOBOOL, "auto"),
- OBSOLETE("SysLog"),
+ OBSOLETE("Support022HiddenServices"),
V(TestSocks, BOOL, "0"),
- OBSOLETE("TestVia"),
V(TokenBucketRefillInterval, MSEC_INTERVAL, "100 msec"),
V(Tor2webMode, BOOL, "0"),
+ V(Tor2webRendezvousPoints, ROUTERSET, NULL),
V(TLSECGroup, STRING, NULL),
V(TrackHostExits, CSV, NULL),
V(TrackHostExitsExpire, INTERVAL, "30 minutes"),
- OBSOLETE("TrafficShaping"),
V(TransListenAddress, LINELIST, NULL),
VPORT(TransPort, LINELIST, NULL),
- V(TunnelDirConns, BOOL, "1"),
+ V(TransProxyType, STRING, "default"),
+ OBSOLETE("TunnelDirConns"),
V(UpdateBridgesFromAuthority, BOOL, "0"),
V(UseBridges, BOOL, "0"),
V(UseEntryGuards, BOOL, "1"),
V(UseEntryGuardsAsDirGuards, BOOL, "1"),
+ V(UseGuardFraction, AUTOBOOL, "auto"),
V(UseMicrodescriptors, AUTOBOOL, "auto"),
- V(UseNTorHandshake, AUTOBOOL, "auto"),
+ V(UseNTorHandshake, AUTOBOOL, "1"),
V(User, STRING, NULL),
V(UserspaceIOCPBuffers, BOOL, "0"),
- VAR("V1AuthoritativeDirectory",BOOL, V1AuthoritativeDir, "0"),
- VAR("V2AuthoritativeDirectory",BOOL, V2AuthoritativeDir, "0"),
+ OBSOLETE("V1AuthoritativeDirectory"),
+ OBSOLETE("V2AuthoritativeDirectory"),
VAR("V3AuthoritativeDirectory",BOOL, V3AuthoritativeDir, "0"),
V(TestingV3AuthInitialVotingInterval, INTERVAL, "30 minutes"),
V(TestingV3AuthInitialVoteDelay, INTERVAL, "5 minutes"),
V(TestingV3AuthInitialDistDelay, INTERVAL, "5 minutes"),
+ V(TestingV3AuthVotingStartOffset, INTERVAL, "0"),
V(V3AuthVotingInterval, INTERVAL, "1 hour"),
V(V3AuthVoteDelay, INTERVAL, "5 minutes"),
V(V3AuthDistDelay, INTERVAL, "5 minutes"),
V(V3AuthNIntervalsValid, UINT, "3"),
V(V3AuthUseLegacyKey, BOOL, "0"),
V(V3BandwidthsFile, FILENAME, NULL),
+ V(GuardfractionFile, FILENAME, NULL),
VAR("VersioningAuthoritativeDirectory",BOOL,VersioningAuthoritativeDir, "0"),
+ OBSOLETE("VoteOnHidServDirectoriesV2"),
V(VirtualAddrNetworkIPv4, STRING, "127.192.0.0/10"),
V(VirtualAddrNetworkIPv6, STRING, "[FE80::]/10"),
V(WarnPlaintextPorts, CSV, "23,109,110,143"),
@@ -433,8 +462,30 @@ static config_var_t option_vars_[] = {
VAR("__HashedControlSessionPassword", LINELIST, HashedControlSessionPassword,
NULL),
VAR("__OwningControllerProcess",STRING,OwningControllerProcess, NULL),
- V(MinUptimeHidServDirectoryV2, INTERVAL, "25 hours"),
- V(VoteOnHidServDirectoriesV2, BOOL, "1"),
+ V(MinUptimeHidServDirectoryV2, INTERVAL, "96 hours"),
+ V(TestingServerDownloadSchedule, CSV_INTERVAL, "0, 0, 0, 60, 60, 120, "
+ "300, 900, 2147483647"),
+ V(TestingClientDownloadSchedule, CSV_INTERVAL, "0, 0, 60, 300, 600, "
+ "2147483647"),
+ V(TestingServerConsensusDownloadSchedule, CSV_INTERVAL, "0, 0, 60, "
+ "300, 600, 1800, 1800, 1800, 1800, "
+ "1800, 3600, 7200"),
+ V(TestingClientConsensusDownloadSchedule, CSV_INTERVAL, "0, 0, 60, "
+ "300, 600, 1800, 3600, 3600, 3600, "
+ "10800, 21600, 43200"),
+ V(TestingBridgeDownloadSchedule, CSV_INTERVAL, "3600, 900, 900, 3600"),
+ V(TestingClientMaxIntervalWithoutRequest, INTERVAL, "10 minutes"),
+ V(TestingDirConnectionMaxStall, INTERVAL, "5 minutes"),
+ V(TestingConsensusMaxDownloadTries, UINT, "8"),
+ V(TestingDescriptorMaxDownloadTries, UINT, "8"),
+ V(TestingMicrodescMaxDownloadTries, UINT, "8"),
+ V(TestingCertMaxDownloadTries, UINT, "8"),
+ V(TestingDirAuthVoteExit, ROUTERSET, NULL),
+ V(TestingDirAuthVoteExitIsStrict, BOOL, "0"),
+ V(TestingDirAuthVoteGuard, ROUTERSET, NULL),
+ V(TestingDirAuthVoteGuardIsStrict, BOOL, "0"),
+ V(TestingDirAuthVoteHSDir, ROUTERSET, NULL),
+ V(TestingDirAuthVoteHSDirIsStrict, BOOL, "0"),
VAR("___UsingTestNetworkDefaults", BOOL, UsingTestNetworkDefaults_, "0"),
{ NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
@@ -457,13 +508,33 @@ static const config_var_t testing_tor_network_defaults[] = {
V(V3AuthVotingInterval, INTERVAL, "5 minutes"),
V(V3AuthVoteDelay, INTERVAL, "20 seconds"),
V(V3AuthDistDelay, INTERVAL, "20 seconds"),
- V(TestingV3AuthInitialVotingInterval, INTERVAL, "5 minutes"),
+ V(TestingV3AuthInitialVotingInterval, INTERVAL, "150 seconds"),
V(TestingV3AuthInitialVoteDelay, INTERVAL, "20 seconds"),
V(TestingV3AuthInitialDistDelay, INTERVAL, "20 seconds"),
+ V(TestingV3AuthVotingStartOffset, INTERVAL, "0"),
V(TestingAuthDirTimeToLearnReachability, INTERVAL, "0 minutes"),
V(TestingEstimatedDescriptorPropagationTime, INTERVAL, "0 minutes"),
V(MinUptimeHidServDirectoryV2, INTERVAL, "0 minutes"),
+ V(TestingServerDownloadSchedule, CSV_INTERVAL, "0, 0, 0, 5, 10, 15, "
+ "20, 30, 60"),
+ V(TestingClientDownloadSchedule, CSV_INTERVAL, "0, 0, 5, 10, 15, 20, "
+ "30, 60"),
+ V(TestingServerConsensusDownloadSchedule, CSV_INTERVAL, "0, 0, 5, 10, "
+ "15, 20, 30, 60"),
+ V(TestingClientConsensusDownloadSchedule, CSV_INTERVAL, "0, 0, 5, 10, "
+ "15, 20, 30, 60"),
+ V(TestingBridgeDownloadSchedule, CSV_INTERVAL, "60, 30, 30, 60"),
+ V(TestingClientMaxIntervalWithoutRequest, INTERVAL, "5 seconds"),
+ V(TestingDirConnectionMaxStall, INTERVAL, "30 seconds"),
+ V(TestingConsensusMaxDownloadTries, UINT, "80"),
+ V(TestingDescriptorMaxDownloadTries, UINT, "80"),
+ V(TestingMicrodescMaxDownloadTries, UINT, "80"),
+ V(TestingCertMaxDownloadTries, UINT, "80"),
+ V(TestingEnableConnBwEvent, BOOL, "1"),
+ V(TestingEnableCellStatsEvent, BOOL, "1"),
+ V(TestingEnableTbEmptyEvent, BOOL, "1"),
VAR("___UsingTestNetworkDefaults", BOOL, UsingTestNetworkDefaults_, "1"),
+ V(RendPostPeriod, INTERVAL, "2 minutes"),
{ NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
};
@@ -475,9 +546,6 @@ static const config_var_t testing_tor_network_defaults[] = {
#ifdef _WIN32
static char *get_windows_conf_root(void);
#endif
-static int options_validate(or_options_t *old_options,
- or_options_t *options,
- int from_setconf, char **msg);
static int options_act_reversible(const or_options_t *old_options, char **msg);
static int options_act(const or_options_t *old_options);
static int options_transition_allowed(const or_options_t *old,
@@ -487,29 +555,24 @@ static int options_transition_affects_workers(
const or_options_t *old_options, const or_options_t *new_options);
static int options_transition_affects_descriptor(
const or_options_t *old_options, const or_options_t *new_options);
-static int check_nickname_list(const char *lst, const char *name, char **msg);
-
-static int parse_bridge_line(const char *line, int validate_only);
-static int parse_client_transport_line(const char *line, int validate_only);
-
-static int parse_server_transport_line(const char *line, int validate_only);
+static int check_nickname_list(char **lst, const char *name, char **msg);
static char *get_bindaddr_from_transport_listen_line(const char *line,
const char *transport);
static int parse_dir_authority_line(const char *line,
dirinfo_type_t required_type,
int validate_only);
-static int parse_dir_fallback_line(const char *line,
- int validate_only);
static void port_cfg_free(port_cfg_t *port);
static int parse_ports(or_options_t *options, int validate_only,
- char **msg_out, int *n_ports_out);
+ char **msg_out, int *n_ports_out,
+ int *world_writable_control_socket);
static int check_server_ports(const smartlist_t *ports,
const or_options_t *options);
static int validate_data_directory(or_options_t *options);
static int write_configuration_file(const char *fname,
const or_options_t *options);
-static int options_init_logs(or_options_t *options, int validate_only);
+static int options_init_logs(const or_options_t *old_options,
+ or_options_t *options, int validate_only);
static void init_libevent(const or_options_t *options);
static int opt_streq(const char *s1, const char *s2);
@@ -517,18 +580,23 @@ static int parse_outbound_addresses(or_options_t *options, int validate_only,
char **msg);
static void config_maybe_load_geoip_files_(const or_options_t *options,
const or_options_t *old_options);
+static int options_validate_cb(void *old_options, void *options,
+ void *default_options,
+ int from_setconf, char **msg);
+static uint64_t compute_real_max_mem_in_queues(const uint64_t val,
+ int log_guess);
/** Magic value for or_options_t. */
#define OR_OPTIONS_MAGIC 9090909
/** Configuration format for or_options_t. */
-static config_format_t options_format = {
+STATIC config_format_t options_format = {
sizeof(or_options_t),
OR_OPTIONS_MAGIC,
STRUCT_OFFSET(or_options_t, magic_),
option_abbrevs_,
option_vars_,
- (validate_fn_t)options_validate,
+ options_validate_cb,
NULL
};
@@ -545,8 +613,12 @@ static or_options_t *global_default_options = NULL;
static char *torrc_fname = NULL;
/** Name of the most recently read torrc-defaults file.*/
static char *torrc_defaults_fname;
-/** Configuration Options set by command line. */
+/** Configuration options set by command line. */
static config_line_t *global_cmdline_options = NULL;
+/** Non-configuration options set by the command line */
+static config_line_t *global_cmdline_only_options = NULL;
+/** Boolean: Have we parsed the command line? */
+static int have_parsed_cmdline = 0;
/** Contents of most recently read DirPortFrontPage file. */
static char *global_dirfrontpagecontents = NULL;
/** List of port_cfg_t for all configured ports. */
@@ -568,8 +640,8 @@ get_options_mutable(void)
}
/** Returns the currently configured options */
-const or_options_t *
-get_options(void)
+MOCK_IMPL(const or_options_t *,
+get_options,(void))
{
return get_options_mutable();
}
@@ -678,7 +750,7 @@ get_short_version(void)
/** Release additional memory allocated in options
*/
-static void
+STATIC void
or_options_free(or_options_t *options)
{
if (!options)
@@ -691,6 +763,8 @@ or_options_free(or_options_t *options)
smartlist_free(options->NodeFamilySets);
}
tor_free(options->BridgePassword_AuthDigest_);
+ tor_free(options->command_arg);
+ tor_free(options->master_key_fname);
config_free(&options_format, options);
}
@@ -707,6 +781,9 @@ config_free_all(void)
config_free_lines(global_cmdline_options);
global_cmdline_options = NULL;
+ config_free_lines(global_cmdline_only_options);
+ global_cmdline_only_options = NULL;
+
if (configured_ports) {
SMARTLIST_FOREACH(configured_ports,
port_cfg_t *, p, port_cfg_free(p));
@@ -780,53 +857,61 @@ escaped_safe_str(const char *address)
return escaped(address);
}
+/** List of default directory authorities */
+
+static const char *default_authorities[] = {
+ "moria1 orport=9101 "
+ "v3ident=D586D18309DED4CD6D57C18FDB97EFA96D330566 "
+ "128.31.0.39:9131 9695 DFC3 5FFE B861 329B 9F1A B04C 4639 7020 CE31",
+ "tor26 orport=443 "
+ "v3ident=14C131DFC5C6F93646BE72FA1401C02A8DF2E8B4 "
+ "86.59.21.38:80 847B 1F85 0344 D787 6491 A548 92F9 0493 4E4E B85D",
+ "dizum orport=443 "
+ "v3ident=E8A9C45EDE6D711294FADF8E7951F4DE6CA56B58 "
+ "194.109.206.212:80 7EA6 EAD6 FD83 083C 538F 4403 8BBF A077 587D D755",
+ "Tonga orport=443 bridge "
+ "82.94.251.203:80 4A0C CD2D DC79 9508 3D73 F5D6 6710 0C8A 5831 F16D",
+ "gabelmoo orport=443 "
+ "v3ident=ED03BB616EB2F60BEC80151114BB25CEF515B226 "
+ "131.188.40.189:80 F204 4413 DAC2 E02E 3D6B CF47 35A1 9BCA 1DE9 7281",
+ "dannenberg orport=443 "
+ "v3ident=585769C78764D58426B8B52B6651A5A71137189A "
+ "193.23.244.244:80 7BE6 83E6 5D48 1413 21C5 ED92 F075 C553 64AC 7123",
+ "urras orport=80 "
+ "v3ident=80550987E1D626E3EBA5E5E75A458DE0626D088C "
+ "208.83.223.34:443 0AD3 FA88 4D18 F89E EA2D 89C0 1937 9E0E 7FD9 4417",
+ "maatuska orport=80 "
+ "v3ident=49015F787433103580E3B66A1707A00E60F2D15B "
+ "171.25.193.9:443 BD6A 8292 55CB 08E6 6FBE 7D37 4836 3586 E46B 3810",
+ "Faravahar orport=443 "
+ "v3ident=EFCBE720AB3A82B99F9E953CD5BF50F7EEFC7B97 "
+ "154.35.175.225:80 CF6D 0AAF B385 BE71 B8E1 11FC 5CFF 4B47 9237 33BC",
+ "longclaw orport=443 "
+ "v3ident=23D15D965BC35114467363C165C4F724B64B4F66 "
+ "199.254.238.52:80 74A9 1064 6BCE EFBC D2E8 74FC 1DC9 9743 0F96 8145",
+ NULL
+};
+
/** Add the default directory authorities directly into the trusted dir list,
- * but only add them insofar as they share bits with <b>type</b>. */
+ * but only add them insofar as they share bits with <b>type</b>.
+ * Each authority's bits are restricted to the bits shared with <b>type</b>.
+ * If <b>type</b> is ALL_DIRINFO or NO_DIRINFO (zero), add all authorities. */
static void
add_default_trusted_dir_authorities(dirinfo_type_t type)
{
int i;
- const char *authorities[] = {
- "moria1 orport=9101 no-v2 "
- "v3ident=D586D18309DED4CD6D57C18FDB97EFA96D330566 "
- "128.31.0.39:9131 9695 DFC3 5FFE B861 329B 9F1A B04C 4639 7020 CE31",
- "tor26 v1 orport=443 v3ident=14C131DFC5C6F93646BE72FA1401C02A8DF2E8B4 "
- "86.59.21.38:80 847B 1F85 0344 D787 6491 A548 92F9 0493 4E4E B85D",
- "dizum orport=443 v3ident=E8A9C45EDE6D711294FADF8E7951F4DE6CA56B58 "
- "194.109.206.212:80 7EA6 EAD6 FD83 083C 538F 4403 8BBF A077 587D D755",
- "Tonga orport=443 bridge no-v2 82.94.251.203:80 "
- "4A0C CD2D DC79 9508 3D73 F5D6 6710 0C8A 5831 F16D",
- "gabelmoo orport=443 no-v2 "
- "v3ident=ED03BB616EB2F60BEC80151114BB25CEF515B226 "
- "131.188.40.189:80 F204 4413 DAC2 E02E 3D6B CF47 35A1 9BCA 1DE9 7281",
- "dannenberg orport=443 no-v2 "
- "v3ident=585769C78764D58426B8B52B6651A5A71137189A "
- "193.23.244.244:80 7BE6 83E6 5D48 1413 21C5 ED92 F075 C553 64AC 7123",
- "urras orport=80 no-v2 v3ident=80550987E1D626E3EBA5E5E75A458DE0626D088C "
- "208.83.223.34:443 0AD3 FA88 4D18 F89E EA2D 89C0 1937 9E0E 7FD9 4417",
- "maatuska orport=80 no-v2 "
- "v3ident=49015F787433103580E3B66A1707A00E60F2D15B "
- "171.25.193.9:443 BD6A 8292 55CB 08E6 6FBE 7D37 4836 3586 E46B 3810",
- "Faravahar orport=443 no-v2 "
- "v3ident=EFCBE720AB3A82B99F9E953CD5BF50F7EEFC7B97 "
- "154.35.175.225:80 CF6D 0AAF B385 BE71 B8E1 11FC 5CFF 4B47 9237 33BC",
- "longclaw orport=443 no-v2 "
- "v3ident=23D15D965BC35114467363C165C4F724B64B4F66 "
- "199.254.238.52:80 74A9 1064 6BCE EFBC D2E8 74FC 1DC9 9743 0F96 8145",
- NULL
- };
- for (i=0; authorities[i]; i++) {
- if (parse_dir_authority_line(authorities[i], type, 0)<0) {
+ for (i=0; default_authorities[i]; i++) {
+ if (parse_dir_authority_line(default_authorities[i], type, 0)<0) {
log_err(LD_BUG, "Couldn't parse internal DirAuthority line %s",
- authorities[i]);
+ default_authorities[i]);
}
}
}
/** Add the default fallback directory servers into the fallback directory
* server list. */
-static void
-add_default_fallback_dir_servers(void)
+MOCK_IMPL(void,
+add_default_fallback_dir_servers,(void))
{
int i;
const char *fallback[] = {
@@ -850,8 +935,7 @@ validate_dir_servers(or_options_t *options, or_options_t *old_options)
config_line_t *cl;
if (options->DirAuthorities &&
- (options->AlternateDirAuthority || options->AlternateBridgeAuthority ||
- options->AlternateHSAuthority)) {
+ (options->AlternateDirAuthority || options->AlternateBridgeAuthority)) {
log_warn(LD_CONFIG,
"You cannot set both DirAuthority and Alternate*Authority.");
return -1;
@@ -887,9 +971,6 @@ validate_dir_servers(or_options_t *options, or_options_t *old_options)
for (cl = options->AlternateDirAuthority; cl; cl = cl->next)
if (parse_dir_authority_line(cl->value, NO_DIRINFO, 1)<0)
return -1;
- for (cl = options->AlternateHSAuthority; cl; cl = cl->next)
- if (parse_dir_authority_line(cl->value, NO_DIRINFO, 1)<0)
- return -1;
for (cl = options->FallbackDir; cl; cl = cl->next)
if (parse_dir_fallback_line(cl->value, 1)<0)
return -1;
@@ -899,7 +980,7 @@ validate_dir_servers(or_options_t *options, or_options_t *old_options)
/** Look at all the config options and assign new dir authorities
* as appropriate.
*/
-static int
+int
consider_adding_dir_servers(const or_options_t *options,
const or_options_t *old_options)
{
@@ -912,30 +993,41 @@ consider_adding_dir_servers(const or_options_t *options,
!config_lines_eq(options->AlternateBridgeAuthority,
old_options->AlternateBridgeAuthority) ||
!config_lines_eq(options->AlternateDirAuthority,
- old_options->AlternateDirAuthority) ||
- !config_lines_eq(options->AlternateHSAuthority,
- old_options->AlternateHSAuthority);
+ old_options->AlternateDirAuthority);
if (!need_to_update)
return 0; /* all done */
+ /* "You cannot set both DirAuthority and Alternate*Authority."
+ * Checking that this restriction holds allows us to simplify
+ * the unit tests. */
+ tor_assert(!(options->DirAuthorities &&
+ (options->AlternateDirAuthority
+ || options->AlternateBridgeAuthority)));
+
/* Start from a clean slate. */
clear_dir_servers();
if (!options->DirAuthorities) {
/* then we may want some of the defaults */
dirinfo_type_t type = NO_DIRINFO;
- if (!options->AlternateBridgeAuthority)
+ if (!options->AlternateBridgeAuthority) {
type |= BRIDGE_DIRINFO;
- if (!options->AlternateDirAuthority)
- type |= V1_DIRINFO | V2_DIRINFO | V3_DIRINFO | EXTRAINFO_DIRINFO |
- MICRODESC_DIRINFO;
- if (!options->AlternateHSAuthority)
- type |= HIDSERV_DIRINFO;
- add_default_trusted_dir_authorities(type);
+ }
+ if (!options->AlternateDirAuthority) {
+ type |= V3_DIRINFO | EXTRAINFO_DIRINFO | MICRODESC_DIRINFO;
+ /* Only add the default fallback directories when the DirAuthorities,
+ * AlternateDirAuthority, and FallbackDir directory config options
+ * are set to their defaults. */
+ if (!options->FallbackDir) {
+ add_default_fallback_dir_servers();
+ }
+ }
+ /* if type == NO_DIRINFO, we don't want to add any of the
+ * default authorities, because we've replaced them all */
+ if (type != NO_DIRINFO)
+ add_default_trusted_dir_authorities(type);
}
- if (!options->FallbackDir)
- add_default_fallback_dir_servers();
for (cl = options->DirAuthorities; cl; cl = cl->next)
if (parse_dir_authority_line(cl->value, NO_DIRINFO, 0)<0)
@@ -946,9 +1038,6 @@ consider_adding_dir_servers(const or_options_t *options,
for (cl = options->AlternateDirAuthority; cl; cl = cl->next)
if (parse_dir_authority_line(cl->value, NO_DIRINFO, 0)<0)
return -1;
- for (cl = options->AlternateHSAuthority; cl; cl = cl->next)
- if (parse_dir_authority_line(cl->value, NO_DIRINFO, 0)<0)
- return -1;
for (cl = options->FallbackDir; cl; cl = cl->next)
if (parse_dir_fallback_line(cl->value, 0)<0)
return -1;
@@ -971,7 +1060,8 @@ options_act_reversible(const or_options_t *old_options, char **msg)
int running_tor = options->command == CMD_RUN_TOR;
int set_conn_limit = 0;
int r = -1;
- int logs_marked = 0;
+ int logs_marked = 0, logs_initialized = 0;
+ int old_min_log_level = get_min_log_level();
/* Daemonize _first_, since we only want to open most of this stuff in
* the subprocess. Libevent bases can't be reliably inherited across
@@ -981,6 +1071,11 @@ options_act_reversible(const or_options_t *old_options, char **msg)
start_daemon();
}
+#ifdef HAVE_SYSTEMD
+ /* Our PID may have changed, inform supervisor */
+ sd_notifyf(0, "MAINPID=%ld\n", (long int)getpid());
+#endif
+
#ifndef HAVE_SYS_UN_H
if (options->ControlSocket || options->ControlSocketsGroupWritable) {
*msg = tor_strdup("Unix domain sockets (ControlSocket) not supported "
@@ -998,22 +1093,39 @@ options_act_reversible(const or_options_t *old_options, char **msg)
if (running_tor) {
int n_ports=0;
/* We need to set the connection limit before we can open the listeners. */
- if (set_max_file_descriptors((unsigned)options->ConnLimit,
- &options->ConnLimit_) < 0) {
- *msg = tor_strdup("Problem with ConnLimit value. See logs for details.");
- goto rollback;
+ if (! sandbox_is_active()) {
+ if (set_max_file_descriptors((unsigned)options->ConnLimit,
+ &options->ConnLimit_) < 0) {
+ *msg = tor_strdup("Problem with ConnLimit value. "
+ "See logs for details.");
+ goto rollback;
+ }
+ set_conn_limit = 1;
+ } else {
+ tor_assert(old_options);
+ options->ConnLimit_ = old_options->ConnLimit_;
}
- set_conn_limit = 1;
/* Set up libevent. (We need to do this before we can register the
* listeners as listeners.) */
if (running_tor && !libevent_initialized) {
init_libevent(options);
libevent_initialized = 1;
+
+ /* This has to come up after libevent is initialized. */
+ control_initialize_event_queue();
+
+ /*
+ * Initialize the scheduler - this has to come after
+ * options_init_from_torrc() sets up libevent - why yes, that seems
+ * completely sensible to hide the libevent setup in the option parsing
+ * code! It also needs to happen before init_keys(), so it needs to
+ * happen here too. How yucky. */
+ scheduler_init();
}
/* Adjust the port configuration so we can launch listeners. */
- if (parse_ports(options, 0, msg, &n_ports)) {
+ if (parse_ports(options, 0, msg, &n_ports, NULL)) {
if (!*msg)
*msg = tor_strdup("Unexpected problem parsing port config");
goto rollback;
@@ -1039,12 +1151,15 @@ options_act_reversible(const or_options_t *old_options, char **msg)
"non-control network connections. Shutting down all existing "
"connections.");
connection_mark_all_noncontrol_connections();
+ /* We can't complete circuits until the network is re-enabled. */
+ note_that_we_maybe_cant_complete_circuits();
}
}
#if defined(HAVE_NET_IF_H) && defined(HAVE_NET_PFVAR_H)
/* Open /dev/pf before dropping privileges. */
- if (options->TransPort_set) {
+ if (options->TransPort_set &&
+ options->TransProxyType_parsed == TPT_DEFAULT) {
if (get_pf_socket() < 0) {
*msg = tor_strdup("Unable to open /dev/pf for transparent proxy.");
goto rollback;
@@ -1081,23 +1196,6 @@ options_act_reversible(const or_options_t *old_options, char **msg)
/* No need to roll back, since you can't change the value. */
}
- /* Write control ports to disk as appropriate */
- control_ports_write_to_file();
-
- if (directory_caches_v2_dir_info(options)) {
- char *fn = NULL;
- tor_asprintf(&fn, "%s"PATH_SEPARATOR"cached-status",
- options->DataDirectory);
- if (check_private_dir(fn, running_tor ? CPD_CREATE : CPD_CHECK,
- options->User) < 0) {
- tor_asprintf(msg,
- "Couldn't access/create private data directory \"%s\"", fn);
- tor_free(fn);
- goto done;
- }
- tor_free(fn);
- }
-
/* Bail out at this point if we're not going to be a client or server:
* we don't run Tor itself. */
if (!running_tor)
@@ -1105,10 +1203,12 @@ options_act_reversible(const or_options_t *old_options, char **msg)
mark_logs_temp(); /* Close current logs once new logs are open. */
logs_marked = 1;
- if (options_init_logs(options, 0)<0) { /* Configure the tor_log(s) */
+ /* Configure the tor_log(s) */
+ if (options_init_logs(old_options, options, 0)<0) {
*msg = tor_strdup("Failed to init Log options. See logs for details.");
goto rollback;
}
+ logs_initialized = 1;
commit:
r = 0;
@@ -1119,13 +1219,47 @@ options_act_reversible(const or_options_t *old_options, char **msg)
add_callback_log(severity, control_event_logmsg);
control_adjust_event_log_severity();
tor_free(severity);
+ tor_log_update_sigsafe_err_fds();
+ }
+ if (logs_initialized) {
+ flush_log_messages_from_startup();
+ }
+
+ {
+ const char *badness = NULL;
+ int bad_safelog = 0, bad_severity = 0, new_badness = 0;
+ if (options->SafeLogging_ != SAFELOG_SCRUB_ALL) {
+ bad_safelog = 1;
+ if (!old_options || old_options->SafeLogging_ != options->SafeLogging_)
+ new_badness = 1;
+ }
+ if (get_min_log_level() >= LOG_INFO) {
+ bad_severity = 1;
+ if (get_min_log_level() != old_min_log_level)
+ new_badness = 1;
+ }
+ if (bad_safelog && bad_severity)
+ badness = "you disabled SafeLogging, and "
+ "you're logging more than \"notice\"";
+ else if (bad_safelog)
+ badness = "you disabled SafeLogging";
+ else
+ badness = "you're logging more than \"notice\"";
+ if (new_badness)
+ log_warn(LD_GENERAL, "Your log may contain sensitive information - %s. "
+ "Don't log unless it serves an important reason. "
+ "Overwrite the log afterwards.", badness);
}
+
SMARTLIST_FOREACH(replaced_listeners, connection_t *, conn,
{
+ int marked = conn->marked_for_close;
log_notice(LD_NET, "Closing old %s on %s:%d",
conn_type_to_string(conn->type), conn->address, conn->port);
connection_close_immediate(conn);
- connection_mark_for_close(conn);
+ if (!marked) {
+ connection_mark_for_close(conn);
+ }
});
goto done;
@@ -1167,7 +1301,8 @@ options_need_geoip_info(const or_options_t *options, const char **reason_out)
routerset_needs_geoip(options->EntryNodes) ||
routerset_needs_geoip(options->ExitNodes) ||
routerset_needs_geoip(options->ExcludeExitNodes) ||
- routerset_needs_geoip(options->ExcludeNodes);
+ routerset_needs_geoip(options->ExcludeNodes) ||
+ routerset_needs_geoip(options->Tor2webRendezvousPoints);
if (routerset_usage && reason_out) {
*reason_out = "We've been configured to use (or avoid) nodes in certain "
@@ -1218,10 +1353,6 @@ options_transition_requires_fresh_tls_context(const or_options_t *old_options,
if (!old_options)
return 0;
- if ((old_options->DynamicDHGroups != new_options->DynamicDHGroups)) {
- return 1;
- }
-
if (!opt_streq(old_options->TLSECGroup, new_options->TLSECGroup))
return 1;
@@ -1272,6 +1403,9 @@ options_act(const or_options_t *old_options)
}
}
+ /* Write control ports to disk as appropriate */
+ control_ports_write_to_file();
+
if (running_tor && !have_lockfile()) {
if (try_locking(options, 1) < 0)
return -1;
@@ -1297,19 +1431,34 @@ options_act(const or_options_t *old_options)
log_err(LD_CONFIG, "This copy of Tor was not compiled to run in "
"'tor2web mode'. It cannot be run with the Tor2webMode torrc "
"option enabled. To enable Tor2webMode recompile with the "
- "--enable-tor2webmode option.");
+ "--enable-tor2web-mode option.");
return -1;
}
#endif
+ /* If we are a bridge with a pluggable transport proxy but no
+ Extended ORPort, inform the user that she is missing out. */
+ if (server_mode(options) && options->ServerTransportPlugin &&
+ !options->ExtORPort_lines) {
+ log_notice(LD_CONFIG, "We use pluggable transports but the Extended "
+ "ORPort is disabled. Tor and your pluggable transports proxy "
+ "communicate with each other via the Extended ORPort so it "
+ "is suggested you enable it: it will also allow your Bridge "
+ "to collect statistics about its clients that use pluggable "
+ "transports. Please enable it using the ExtORPort torrc option "
+ "(e.g. set 'ExtORPort auto').");
+ }
+
if (options->Bridges) {
mark_bridge_list();
for (cl = options->Bridges; cl; cl = cl->next) {
- if (parse_bridge_line(cl->value, 0)<0) {
+ bridge_line_t *bridge_line = parse_bridge_line(cl->value);
+ if (!bridge_line) {
log_warn(LD_BUG,
"Previously validated Bridge line could not be added!");
return -1;
}
+ bridge_add_from_config(bridge_line);
}
sweep_bridge_list();
}
@@ -1333,32 +1482,47 @@ options_act(const or_options_t *old_options)
rep_hist_load_mtbf_data(time(NULL));
}
+ /* If we have an ExtORPort, initialize its auth cookie. */
+ if (running_tor &&
+ init_ext_or_cookie_authentication(!!options->ExtORPort_lines) < 0) {
+ log_warn(LD_CONFIG,"Error creating Extended ORPort cookie file.");
+ return -1;
+ }
+
mark_transport_list();
pt_prepare_proxy_list_for_config_read();
- if (options->ClientTransportPlugin) {
- for (cl = options->ClientTransportPlugin; cl; cl = cl->next) {
- if (parse_client_transport_line(cl->value, 0)<0) {
- log_warn(LD_BUG,
- "Previously validated ClientTransportPlugin line "
- "could not be added!");
- return -1;
+ if (!options->DisableNetwork) {
+ if (options->ClientTransportPlugin) {
+ for (cl = options->ClientTransportPlugin; cl; cl = cl->next) {
+ if (parse_transport_line(options, cl->value, 0, 0) < 0) {
+ log_warn(LD_BUG,
+ "Previously validated ClientTransportPlugin line "
+ "could not be added!");
+ return -1;
+ }
}
}
- }
- if (options->ServerTransportPlugin && server_mode(options)) {
- for (cl = options->ServerTransportPlugin; cl; cl = cl->next) {
- if (parse_server_transport_line(cl->value, 0)<0) {
- log_warn(LD_BUG,
- "Previously validated ServerTransportPlugin line "
- "could not be added!");
- return -1;
+ if (options->ServerTransportPlugin && server_mode(options)) {
+ for (cl = options->ServerTransportPlugin; cl; cl = cl->next) {
+ if (parse_transport_line(options, cl->value, 0, 1) < 0) {
+ log_warn(LD_BUG,
+ "Previously validated ServerTransportPlugin line "
+ "could not be added!");
+ return -1;
+ }
}
}
}
sweep_transport_list();
sweep_proxy_list();
+ /* Start the PT proxy configuration. By doing this configuration
+ here, we also figure out which proxies need to be restarted and
+ which not. */
+ if (pt_proxies_configuration_pending() && !net_is_disabled())
+ pt_configure_remaining_proxies();
+
/* Bail out at this point if we're not going to be a client or server:
* we want to not fork, and to log stuff to stderr. */
if (!running_tor)
@@ -1370,24 +1534,6 @@ options_act(const or_options_t *old_options)
finish_daemon(options->DataDirectory);
}
- /* If needed, generate a new TLS DH prime according to the current torrc. */
- if (server_mode(options) && options->DynamicDHGroups) {
- char *keydir = get_datadir_fname("keys");
- if (check_private_dir(keydir, CPD_CREATE, options->User)) {
- tor_free(keydir);
- return -1;
- }
- tor_free(keydir);
-
- if (!old_options || !old_options->DynamicDHGroups) {
- char *fname = get_datadir_fname2("keys", "dynamic_dh_params");
- crypto_set_tls_dh_prime(fname);
- tor_free(fname);
- }
- } else { /* clients don't need a dynamic DH prime. */
- crypto_set_tls_dh_prime(NULL);
- }
-
/* We want to reinit keys as needed before we do much of anything else:
keys are important, and other things can depend on them. */
if (transition_affects_workers ||
@@ -1408,8 +1554,9 @@ options_act(const or_options_t *old_options)
/* Write our PID to the PID file. If we do not have write permissions we
* will log a warning */
- if (options->PidFile)
+ if (options->PidFile && !sandbox_is_active()) {
write_pidfile(options->PidFile);
+ }
/* Register addressmap directives */
config_register_addressmaps(options);
@@ -1423,8 +1570,8 @@ options_act(const or_options_t *old_options)
return -1;
}
- if (init_cookie_authentication(options->CookieAuthentication) < 0) {
- log_warn(LD_CONFIG,"Error creating cookie authentication file.");
+ if (init_control_cookie_authentication(options->CookieAuthentication) < 0) {
+ log_warn(LD_CONFIG,"Error creating control cookie authentication file.");
return -1;
}
@@ -1436,6 +1583,12 @@ options_act(const or_options_t *old_options)
return -1;
}
+ /* Set up scheduler thresholds */
+ scheduler_set_watermarks((uint32_t)options->SchedulerLowWaterMark__,
+ (uint32_t)options->SchedulerHighWaterMark__,
+ (options->SchedulerMaxFlushCells__ > 0) ?
+ options->SchedulerMaxFlushCells__ : 1000);
+
/* Set up accounting */
if (accounting_parse_options(options, 0)<0) {
log_warn(LD_CONFIG,"Error in accounting options");
@@ -1485,11 +1638,25 @@ options_act(const or_options_t *old_options)
}
if (parse_outbound_addresses(options, 0, &msg) < 0) {
- log_warn(LD_BUG, "Failed parsing oubound bind addresses: %s", msg);
+ log_warn(LD_BUG, "Failed parsing outbound bind addresses: %s", msg);
tor_free(msg);
return -1;
}
+ config_maybe_load_geoip_files_(options, old_options);
+
+ if (geoip_is_loaded(AF_INET) && options->GeoIPExcludeUnknown) {
+ /* ExcludeUnknown is true or "auto" */
+ const int is_auto = options->GeoIPExcludeUnknown == -1;
+ int changed;
+
+ changed = routerset_add_unknown_ccs(&options->ExcludeNodes, is_auto);
+ changed += routerset_add_unknown_ccs(&options->ExcludeExitNodes, is_auto);
+
+ if (changed)
+ routerset_add_unknown_ccs(&options->ExcludeExitNodesUnion_, is_auto);
+ }
+
/* Check for transitions that need action. */
if (old_options) {
int revise_trackexithosts = 0;
@@ -1503,6 +1670,8 @@ options_act(const or_options_t *old_options)
options->ExcludeExitNodes) ||
!routerset_equal(old_options->EntryNodes, options->EntryNodes) ||
!routerset_equal(old_options->ExitNodes, options->ExitNodes) ||
+ !routerset_equal(old_options->Tor2webRendezvousPoints,
+ options->Tor2webRendezvousPoints) ||
options->StrictNodes != old_options->StrictNodes) {
log_info(LD_CIRC,
"Changed to using entry guards or bridges, or changed "
@@ -1568,11 +1737,12 @@ options_act(const or_options_t *old_options)
"Worker-related options changed. Rotating workers.");
if (server_mode(options) && !server_mode(old_options)) {
+ cpu_init();
ip_address_changed(0);
- if (can_complete_circuit || !any_predicted_circuits(time(NULL)))
+ if (have_completed_a_circuit() || !any_predicted_circuits(time(NULL)))
inform_testing_reachability();
}
- cpuworkers_rotate();
+ cpuworkers_rotate_keyinfo();
if (dns_reset())
return -1;
} else {
@@ -1585,32 +1755,24 @@ options_act(const or_options_t *old_options)
connection_or_update_token_buckets(get_connection_array(), options);
}
- config_maybe_load_geoip_files_(options, old_options);
-
- if (geoip_is_loaded(AF_INET) && options->GeoIPExcludeUnknown) {
- /* ExcludeUnknown is true or "auto" */
- const int is_auto = options->GeoIPExcludeUnknown == -1;
- int changed;
-
- changed = routerset_add_unknown_ccs(&options->ExcludeNodes, is_auto);
- changed += routerset_add_unknown_ccs(&options->ExcludeExitNodes, is_auto);
-
- if (changed)
- routerset_add_unknown_ccs(&options->ExcludeExitNodesUnion_, is_auto);
- }
+ /* Only collect directory-request statistics on relays and bridges. */
+ options->DirReqStatistics = options->DirReqStatistics_option &&
+ server_mode(options);
if (options->CellStatistics || options->DirReqStatistics ||
options->EntryStatistics || options->ExitPortStatistics ||
options->ConnDirectionStatistics ||
+ options->HiddenServiceStatistics ||
options->BridgeAuthoritativeDir) {
time_t now = time(NULL);
int print_notice = 0;
- /* If we aren't acting as a server, we can't collect stats anyway. */
- if (!server_mode(options)) {
+ /* Only collect other relay-only statistics on relays. */
+ if (!public_server_mode(options)) {
options->CellStatistics = 0;
- options->DirReqStatistics = 0;
options->EntryStatistics = 0;
+ options->ConnDirectionStatistics = 0;
+ options->HiddenServiceStatistics = 0;
options->ExitPortStatistics = 0;
}
@@ -1625,8 +1787,8 @@ options_act(const or_options_t *old_options)
geoip_dirreq_stats_init(now);
print_notice = 1;
} else {
+ /* disable statistics collection since we have no geoip file */
options->DirReqStatistics = 0;
- /* Don't warn Tor clients, they don't use statistics */
if (options->ORPort_set)
log_notice(LD_CONFIG, "Configured to measure directory request "
"statistics, but no GeoIP database found. "
@@ -1656,6 +1818,11 @@ options_act(const or_options_t *old_options)
options->ConnDirectionStatistics) {
rep_hist_conn_stats_init(now);
}
+ if ((!old_options || !old_options->HiddenServiceStatistics) &&
+ options->HiddenServiceStatistics) {
+ log_info(LD_CONFIG, "Configured to measure hidden service statistics.");
+ rep_hist_hs_stats_init(now);
+ }
if ((!old_options || !old_options->BridgeAuthoritativeDir) &&
options->BridgeAuthoritativeDir) {
rep_hist_desc_stats_init(now);
@@ -1667,6 +1834,8 @@ options_act(const or_options_t *old_options)
"data directory in 24 hours from now.");
}
+ /* If we used to have statistics enabled but we just disabled them,
+ stop gathering them. */
if (old_options && old_options->CellStatistics &&
!options->CellStatistics)
rep_hist_buffer_stats_term();
@@ -1676,6 +1845,9 @@ options_act(const or_options_t *old_options)
if (old_options && old_options->EntryStatistics &&
!options->EntryStatistics)
geoip_entry_stats_term();
+ if (old_options && old_options->HiddenServiceStatistics &&
+ !options->HiddenServiceStatistics)
+ rep_hist_hs_stats_term();
if (old_options && old_options->ExitPortStatistics &&
!options->ExitPortStatistics)
rep_hist_exit_stats_term();
@@ -1708,7 +1880,7 @@ options_act(const or_options_t *old_options)
directory_fetches_dir_info_early(old_options)) ||
!bool_eq(directory_fetches_dir_info_later(options),
directory_fetches_dir_info_later(old_options))) {
- /* Make sure update_router_have_min_dir_info gets called. */
+ /* Make sure update_router_have_minimum_dir_info() gets called. */
router_dir_info_changed();
/* We might need to download a new consensus status later or sooner than
* we had expected. */
@@ -1732,40 +1904,80 @@ options_act(const or_options_t *old_options)
return 0;
}
-/** Helper: Read a list of configuration options from the command line.
- * If successful, put them in *<b>result</b> and return 0, and return
- * -1 and leave *<b>result</b> alone. */
-static int
-config_get_commandlines(int argc, char **argv, config_line_t **result)
+typedef enum {
+ TAKES_NO_ARGUMENT = 0,
+ ARGUMENT_NECESSARY = 1,
+ ARGUMENT_OPTIONAL = 2
+} takes_argument_t;
+
+static const struct {
+ const char *name;
+ takes_argument_t takes_argument;
+} CMDLINE_ONLY_OPTIONS[] = {
+ { "-f", ARGUMENT_NECESSARY },
+ { "--allow-missing-torrc", TAKES_NO_ARGUMENT },
+ { "--defaults-torrc", ARGUMENT_NECESSARY },
+ { "--hash-password", ARGUMENT_NECESSARY },
+ { "--dump-config", ARGUMENT_OPTIONAL },
+ { "--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 },
+ { "--ignore-missing-torrc", TAKES_NO_ARGUMENT },
+ { "--quiet", TAKES_NO_ARGUMENT },
+ { "--hush", TAKES_NO_ARGUMENT },
+ { "--version", TAKES_NO_ARGUMENT },
+ { "--library-versions", TAKES_NO_ARGUMENT },
+ { "-h", TAKES_NO_ARGUMENT },
+ { "--help", TAKES_NO_ARGUMENT },
+ { "--list-torrc-options", TAKES_NO_ARGUMENT },
+ { "--nt-service", TAKES_NO_ARGUMENT },
+ { "-nt-service", TAKES_NO_ARGUMENT },
+ { NULL, 0 },
+};
+
+/** Helper: Read a list of configuration options from the command line. If
+ * successful, or if ignore_errors is set, put them in *<b>result</b>, put the
+ * commandline-only options in *<b>cmdline_result</b>, and return 0;
+ * otherwise, return -1 and leave *<b>result</b> and <b>cmdline_result</b>
+ * alone. */
+int
+config_parse_commandline(int argc, char **argv, int ignore_errors,
+ config_line_t **result,
+ config_line_t **cmdline_result)
{
+ config_line_t *param = NULL;
+
config_line_t *front = NULL;
config_line_t **new = &front;
- char *s;
+
+ config_line_t *front_cmdline = NULL;
+ config_line_t **new_cmdline = &front_cmdline;
+
+ char *s, *arg;
int i = 1;
while (i < argc) {
unsigned command = CONFIG_LINE_NORMAL;
- int want_arg = 1;
-
- if (!strcmp(argv[i],"-f") ||
- !strcmp(argv[i],"--defaults-torrc") ||
- !strcmp(argv[i],"--hash-password")) {
- i += 2; /* command-line option with argument. ignore them. */
- continue;
- } else if (!strcmp(argv[i],"--list-fingerprint") ||
- !strcmp(argv[i],"--verify-config") ||
- !strcmp(argv[i],"--ignore-missing-torrc") ||
- !strcmp(argv[i],"--quiet") ||
- !strcmp(argv[i],"--hush")) {
- i += 1; /* command-line option. ignore it. */
- continue;
- } else if (!strcmp(argv[i],"--nt-service") ||
- !strcmp(argv[i],"-nt-service")) {
- i += 1;
- continue;
+ takes_argument_t want_arg = ARGUMENT_NECESSARY;
+ int is_cmdline = 0;
+ int j;
+
+ for (j = 0; CMDLINE_ONLY_OPTIONS[j].name != NULL; ++j) {
+ if (!strcmp(argv[i], CMDLINE_ONLY_OPTIONS[j].name)) {
+ is_cmdline = 1;
+ want_arg = CMDLINE_ONLY_OPTIONS[j].takes_argument;
+ break;
+ }
}
- *new = tor_malloc_zero(sizeof(config_line_t));
s = argv[i];
/* Each keyword may be prefixed with one or two dashes. */
@@ -1784,23 +1996,45 @@ config_get_commandlines(int argc, char **argv, config_line_t **result)
want_arg = 0;
}
- if (want_arg && i == argc-1) {
- log_warn(LD_CONFIG,"Command-line option '%s' with no value. Failing.",
- argv[i]);
- config_free_lines(front);
- return -1;
+ const int is_last = (i == argc-1);
+
+ if (want_arg == ARGUMENT_NECESSARY && is_last) {
+ if (ignore_errors) {
+ arg = strdup("");
+ } else {
+ log_warn(LD_CONFIG,"Command-line option '%s' with no value. Failing.",
+ argv[i]);
+ config_free_lines(front);
+ config_free_lines(front_cmdline);
+ return -1;
+ }
+ } else if (want_arg == ARGUMENT_OPTIONAL && is_last) {
+ arg = tor_strdup("");
+ } else {
+ arg = (want_arg != TAKES_NO_ARGUMENT) ? tor_strdup(argv[i+1]) :
+ tor_strdup("");
}
- (*new)->key = tor_strdup(config_expand_abbrev(&options_format, s, 1, 1));
- (*new)->value = want_arg ? tor_strdup(argv[i+1]) : tor_strdup("");
- (*new)->command = command;
- (*new)->next = NULL;
+ param = tor_malloc_zero(sizeof(config_line_t));
+ param->key = is_cmdline ? tor_strdup(argv[i]) :
+ tor_strdup(config_expand_abbrev(&options_format, s, 1, 1));
+ param->value = arg;
+ param->command = command;
+ param->next = NULL;
log_debug(LD_CONFIG, "command line: parsed keyword '%s', value '%s'",
- (*new)->key, (*new)->value);
+ param->key, param->value);
+
+ if (is_cmdline) {
+ *new_cmdline = param;
+ new_cmdline = &((*new_cmdline)->next);
+ } else {
+ *new = param;
+ new = &((*new)->next);
+ }
- new = &((*new)->next);
i += want_arg ? 2 : 1;
}
+ *cmdline_result = front_cmdline;
*result = front;
return 0;
}
@@ -1852,7 +2086,8 @@ options_trial_assign(config_line_t *list, int use_defaults,
return r;
}
- if (options_validate(get_options_mutable(), trial_options, 1, msg) < 0) {
+ if (options_validate(get_options_mutable(), trial_options,
+ global_default_options, 1, msg) < 0) {
config_free(&options_format, trial_options);
return SETOPT_ERR_PARSE; /*XXX make this a separate return value. */
}
@@ -1878,7 +2113,7 @@ print_usage(void)
printf(
"Copyright (c) 2001-2004, Roger Dingledine\n"
"Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson\n"
-"Copyright (c) 2007-2013, The Tor Project, Inc.\n\n"
+"Copyright (c) 2007-2015, The Tor Project, Inc.\n\n"
"tor -f <torrc> [args]\n"
"See man page for options, or https://www.torproject.org/ for "
"documentation.\n");
@@ -1910,8 +2145,41 @@ get_last_resolved_addr(void)
return last_resolved_addr;
}
+/** Reset last_resolved_addr from outside this file. */
+void
+reset_last_resolved_addr(void)
+{
+ last_resolved_addr = 0;
+}
+
/**
- * Use <b>options-\>Address</b> to guess our public IP address.
+ * Attempt getting our non-local (as judged by tor_addr_is_internal()
+ * function) IP address using following techniques, listed in
+ * order from best (most desirable, try first) to worst (least
+ * desirable, try if everything else fails).
+ *
+ * First, attempt using <b>options-\>Address</b> to get our
+ * non-local IP address.
+ *
+ * If <b>options-\>Address</b> represents a non-local IP address,
+ * consider it ours.
+ *
+ * If <b>options-\>Address</b> is a DNS name that resolves to
+ * a non-local IP address, consider this IP address ours.
+ *
+ * If <b>options-\>Address</b> is NULL, fall back to getting local
+ * hostname and using it in above-described ways to try and
+ * get our IP address.
+ *
+ * In case local hostname cannot be resolved to a non-local IP
+ * address, try getting an IP address of network interface
+ * in hopes it will be non-local one.
+ *
+ * Fail if one or more of the following is true:
+ * - DNS name in <b>options-\>Address</b> cannot be resolved.
+ * - <b>options-\>Address</b> is a local host address.
+ * - Attempt to getting local hostname fails.
+ * - Attempt to getting network interface address fails.
*
* Return 0 if all is well, or -1 if we can't find a suitable
* public IP address.
@@ -1920,6 +2188,11 @@ get_last_resolved_addr(void)
* - Put our public IP address (in host order) into *<b>addr_out</b>.
* - If <b>method_out</b> is non-NULL, set *<b>method_out</b> to a static
* string describing how we arrived at our answer.
+ * - "CONFIGURED" - parsed from IP address string in
+ * <b>options-\>Address</b>
+ * - "RESOLVED" - resolved from DNS name in <b>options-\>Address</b>
+ * - "GETHOSTNAME" - resolved from a local hostname.
+ * - "INTERFACE" - retrieved from a network interface.
* - If <b>hostname_out</b> is non-NULL, and we resolved a hostname to
* get our address, set *<b>hostname_out</b> to a newly allocated string
* holding that hostname. (If we didn't get our address by resolving a
@@ -1945,6 +2218,7 @@ resolve_my_address(int warn_severity, const or_options_t *options,
int notice_severity = warn_severity <= LOG_NOTICE ?
LOG_NOTICE : warn_severity;
+ tor_addr_t myaddr;
tor_assert(addr_out);
/*
@@ -1957,7 +2231,7 @@ resolve_my_address(int warn_severity, const or_options_t *options,
explicit_ip = 0; /* it's implicit */
explicit_hostname = 0; /* it's implicit */
- if (gethostname(hostname, sizeof(hostname)) < 0) {
+ if (tor_gethostname(hostname, sizeof(hostname)) < 0) {
log_fn(warn_severity, LD_NET,"Error obtaining local hostname");
return -1;
}
@@ -1995,24 +2269,26 @@ resolve_my_address(int warn_severity, const or_options_t *options,
"local interface. Using that.", fmt_addr32(addr));
strlcpy(hostname, "<guessed from interfaces>", sizeof(hostname));
} else { /* resolved hostname into addr */
+ tor_addr_from_ipv4h(&myaddr, addr);
+
if (!explicit_hostname &&
- is_internal_IP(addr, 0)) {
- uint32_t interface_ip;
+ tor_addr_is_internal(&myaddr, 0)) {
+ tor_addr_t interface_ip;
log_fn(notice_severity, LD_CONFIG, "Guessed local hostname '%s' "
"resolves to a private IP address (%s). Trying something "
"else.", hostname, fmt_addr32(addr));
- if (get_interface_address(warn_severity, &interface_ip)) {
+ if (get_interface_address6(warn_severity, AF_INET, &interface_ip)<0) {
log_fn(warn_severity, LD_CONFIG,
"Could not get local interface IP address. Too bad.");
- } else if (is_internal_IP(interface_ip, 0)) {
+ } else if (tor_addr_is_internal(&interface_ip, 0)) {
log_fn(notice_severity, LD_CONFIG,
"Interface IP address '%s' is a private address too. "
- "Ignoring.", fmt_addr32(interface_ip));
+ "Ignoring.", fmt_addr(&interface_ip));
} else {
from_interface = 1;
- addr = interface_ip;
+ addr = tor_addr_to_ipv4h(&interface_ip);
log_fn(notice_severity, LD_CONFIG,
"Learned IP address '%s' for local interface."
" Using that.", fmt_addr32(addr));
@@ -2030,8 +2306,10 @@ resolve_my_address(int warn_severity, const or_options_t *options,
* out if it is and we don't want that.
*/
+ tor_addr_from_ipv4h(&myaddr,addr);
+
addr_string = tor_dup_ip(addr);
- if (is_internal_IP(addr, 0)) {
+ if (tor_addr_is_internal(&myaddr, 0)) {
/* make sure we're ok with publishing an internal IP */
if (!options->DirAuthorities && !options->AlternateDirAuthority) {
/* if they are using the default authorities, disallow internal IPs
@@ -2120,8 +2398,8 @@ resolve_my_address(int warn_severity, const or_options_t *options,
/** Return true iff <b>addr</b> is judged to be on the same network as us, or
* on a private network.
*/
-int
-is_local_addr(const tor_addr_t *addr)
+MOCK_IMPL(int,
+is_local_addr, (const tor_addr_t *addr))
{
if (tor_addr_is_internal(addr, 0))
return 1;
@@ -2137,7 +2415,7 @@ is_local_addr(const tor_addr_t *addr)
* resolve_my_address will never be called at all). In those cases,
* last_resolved_addr will be 0, and so checking to see whether ip is on
* the same /24 as last_resolved_addr will be the same as checking whether
- * it was on net 0, which is already done by is_internal_IP.
+ * it was on net 0, which is already done by tor_addr_is_internal.
*/
if ((last_resolved_addr & (uint32_t)0xffffff00ul)
== (ip & (uint32_t)0xffffff00ul))
@@ -2166,10 +2444,29 @@ options_init(or_options_t *options)
* include options that are the same as Tor's defaults.
*/
char *
-options_dump(const or_options_t *options, int minimal)
+options_dump(const or_options_t *options, int how_to_dump)
{
- return config_dump(&options_format, global_default_options,
- options, minimal, 0);
+ const or_options_t *use_defaults;
+ int minimal;
+ switch (how_to_dump) {
+ case OPTIONS_DUMP_MINIMAL:
+ use_defaults = global_default_options;
+ minimal = 1;
+ break;
+ case OPTIONS_DUMP_DEFAULTS:
+ use_defaults = NULL;
+ minimal = 1;
+ break;
+ case OPTIONS_DUMP_ALL:
+ use_defaults = NULL;
+ minimal = 0;
+ break;
+ default:
+ log_warn(LD_BUG, "Bogus value for how_to_dump==%d", how_to_dump);
+ return NULL;
+ }
+
+ return config_dump(&options_format, use_defaults, options, minimal, 0);
}
/** Return 0 if every element of sl is a string holding a decimal
@@ -2218,7 +2515,7 @@ ensure_bandwidth_cap(uint64_t *value, const char *desc, char **msg)
/** Parse an authority type from <b>options</b>-\>PublishServerDescriptor
* and write it to <b>options</b>-\>PublishServerDescriptor_. Treat "1"
- * as "v2,v3" unless BridgeRelay is 1, in which case treat it as "bridge".
+ * as "v3" unless BridgeRelay is 1, in which case treat it as "bridge".
* Treat "0" as "".
* Return 0 on success or -1 if not a recognized authority type (in which
* case the value of PublishServerDescriptor_ is undefined). */
@@ -2232,14 +2529,16 @@ compute_publishserverdescriptor(or_options_t *options)
return 0;
SMARTLIST_FOREACH_BEGIN(list, const char *, string) {
if (!strcasecmp(string, "v1"))
- *auth |= V1_DIRINFO;
+ log_warn(LD_CONFIG, "PublishServerDescriptor v1 has no effect, because "
+ "there are no v1 directory authorities anymore.");
else if (!strcmp(string, "1"))
if (options->BridgeRelay)
*auth |= BRIDGE_DIRINFO;
else
- *auth |= V2_DIRINFO | V3_DIRINFO;
+ *auth |= V3_DIRINFO;
else if (!strcasecmp(string, "v2"))
- *auth |= V2_DIRINFO;
+ log_warn(LD_CONFIG, "PublishServerDescriptor v2 has no effect, because "
+ "there are no v2 directory authorities anymore.");
else if (!strcasecmp(string, "v3"))
*auth |= V3_DIRINFO;
else if (!strcasecmp(string, "bridge"))
@@ -2259,6 +2558,12 @@ compute_publishserverdescriptor(or_options_t *options)
/** Lowest allowable value for RendPostPeriod; if this is too low, hidden
* services can overload the directory system. */
#define MIN_REND_POST_PERIOD (10*60)
+#define MIN_REND_POST_PERIOD_TESTING (5)
+
+/** Higest allowable value for PredictedPortsRelevanceTime; if this is
+ * too high, our selection of exits will decrease for an extended
+ * period of time to an uncomfortable level .*/
+#define MAX_PREDICTED_CIRCS_RELEVANCE (60*60)
/** Highest allowable value for RendPostPeriod. */
#define MAX_DIR_PERIOD (MIN_ONION_KEY_LIFETIME/2)
@@ -2286,10 +2591,79 @@ compute_publishserverdescriptor(or_options_t *options)
* */
#define RECOMMENDED_MIN_CIRCUIT_BUILD_TIMEOUT (10)
-/** Return 0 if every setting in <b>options</b> is reasonable, and a
- * permissible transition from <b>old_options</b>. Else return -1.
- * Should have no side effects, except for normalizing the contents of
- * <b>options</b>.
+static int
+options_validate_cb(void *old_options, void *options, void *default_options,
+ int from_setconf, char **msg)
+{
+ return options_validate(old_options, options, default_options,
+ from_setconf, msg);
+}
+
+#define REJECT(arg) \
+ STMT_BEGIN *msg = tor_strdup(arg); return -1; STMT_END
+#ifdef __GNUC__
+#define COMPLAIN(args...) \
+ STMT_BEGIN log_warn(LD_CONFIG, args); STMT_END
+#else
+#define COMPLAIN(args, ...) \
+ STMT_BEGIN log_warn(LD_CONFIG, args, ##__VA_ARGS__); STMT_END
+#endif
+
+/** Log a warning message iff <b>filepath</b> is not absolute.
+ * Warning message must contain option name <b>option</b> and
+ * an absolute path that <b>filepath<b> will resolve to.
+ *
+ * In case <b>filepath</b> is absolute, do nothing.
+ */
+static void
+warn_if_option_path_is_relative(const char *option,
+ char *filepath)
+{
+ if (filepath && path_is_relative(filepath)) {
+ char *abs_path = make_path_absolute(filepath);
+ COMPLAIN("Path for %s (%s) is relative and will resolve to %s."
+ " Is this what you wanted?", option, filepath, abs_path);
+ tor_free(abs_path);
+ }
+}
+
+/** Scan <b>options</b> for occurances of relative file/directory
+ * path and log a warning whenever it is found.
+ */
+static void
+warn_about_relative_paths(or_options_t *options)
+{
+ tor_assert(options);
+
+ warn_if_option_path_is_relative("CookieAuthFile",
+ options->CookieAuthFile);
+ warn_if_option_path_is_relative("ExtORPortCookieAuthFile",
+ options->ExtORPortCookieAuthFile);
+ warn_if_option_path_is_relative("DirPortFrontPage",
+ options->DirPortFrontPage);
+ warn_if_option_path_is_relative("V3BandwidthsFile",
+ options->V3BandwidthsFile);
+ warn_if_option_path_is_relative("ControlPortWriteToFile",
+ options->ControlPortWriteToFile);
+ warn_if_option_path_is_relative("GeoIPFile",options->GeoIPFile);
+ warn_if_option_path_is_relative("GeoIPv6File",options->GeoIPv6File);
+ warn_if_option_path_is_relative("Log",options->DebugLogFile);
+ warn_if_option_path_is_relative("AccelDir",options->AccelDir);
+ warn_if_option_path_is_relative("DataDirectory",options->DataDirectory);
+ warn_if_option_path_is_relative("PidFile",options->PidFile);
+
+ for (config_line_t *hs_line = options->RendConfigLines; hs_line;
+ hs_line = hs_line->next) {
+ if (!strcasecmp(hs_line->key, "HiddenServiceDir"))
+ warn_if_option_path_is_relative("HiddenServiceDir",hs_line->value);
+ }
+}
+
+/** 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
+ * testing mode. Else return -1. Should have no side effects, except for
+ * normalizing the contents of <b>options</b>.
*
* On error, tor_strdup an error explanation into *<b>msg</b>.
*
@@ -2298,21 +2672,21 @@ compute_publishserverdescriptor(or_options_t *options)
* Log line should stay empty. If it's 0, then give us a default log
* if there are no logs defined.
*/
-static int
+STATIC int
options_validate(or_options_t *old_options, or_options_t *options,
- int from_setconf, char **msg)
+ or_options_t *default_options, int from_setconf, char **msg)
{
int i;
config_line_t *cl;
const char *uname = get_uname();
int n_ports=0;
-#define REJECT(arg) \
- STMT_BEGIN *msg = tor_strdup(arg); return -1; STMT_END
-#define COMPLAIN(arg) STMT_BEGIN log_warn(LD_CONFIG, arg); STMT_END
+ int world_writable_control_socket=0;
tor_assert(msg);
*msg = NULL;
+ warn_about_relative_paths(options);
+
if (server_mode(options) &&
(!strcmpstart(uname, "Windows 95") ||
!strcmpstart(uname, "Windows 98") ||
@@ -2323,7 +2697,8 @@ options_validate(or_options_t *old_options, or_options_t *options,
"for details.", uname);
}
- if (parse_ports(options, 1, msg, &n_ports) < 0)
+ if (parse_ports(options, 1, msg, &n_ports,
+ &world_writable_control_socket) < 0)
return -1;
if (parse_outbound_addresses(options, 1, msg) < 0)
@@ -2358,7 +2733,8 @@ options_validate(or_options_t *old_options, or_options_t *options,
config_line_append(&options->Logs, "Log", "warn stdout");
}
- if (options_init_logs(options, 1)<0) /* Validate the tor_log(s) */
+ /* Validate the tor_log(s) */
+ if (options_init_logs(old_options, options, 1)<0)
REJECT("Failed to validate Log options. See logs for details.");
if (authdir_mode(options)) {
@@ -2368,10 +2744,12 @@ options_validate(or_options_t *old_options, or_options_t *options,
REJECT("Failed to resolve/guess local address. See logs for details.");
}
-#ifndef _WIN32
- if (options->RunAsDaemon && torrc_fname && path_is_relative(torrc_fname))
- REJECT("Can't use a relative path to torrc when RunAsDaemon is set.");
-#endif
+ if (server_mode(options) && options->RendConfigLines)
+ log_warn(LD_CONFIG,
+ "Tor is currently configured as a relay and a hidden service. "
+ "That's not very secure: you should probably run your hidden service "
+ "in a separate Tor process, at least -- see "
+ "https://trac.torproject.org/8742");
/* XXXX require that the only port not be DirPort? */
/* XXXX require that at least one port be listened-upon. */
@@ -2381,10 +2759,47 @@ options_validate(or_options_t *old_options, or_options_t *options,
"undefined, and there aren't any hidden services configured. "
"Tor will still run, but probably won't do anything.");
-#ifndef USE_TRANSPARENT
- /* XXXX024 I think we can remove this TransListenAddress */
- if (options->TransPort_set || options->TransListenAddress)
- REJECT("TransPort and TransListenAddress are disabled in this build.");
+ options->TransProxyType_parsed = TPT_DEFAULT;
+#ifdef USE_TRANSPARENT
+ if (options->TransProxyType) {
+ if (!strcasecmp(options->TransProxyType, "default")) {
+ options->TransProxyType_parsed = TPT_DEFAULT;
+ } else if (!strcasecmp(options->TransProxyType, "pf-divert")) {
+#if !defined(__OpenBSD__) && !defined( DARWIN )
+ /* Later versions of OS X have pf */
+ REJECT("pf-divert is a OpenBSD-specific "
+ "and OS X/Darwin-specific feature.");
+#else
+ options->TransProxyType_parsed = TPT_PF_DIVERT;
+#endif
+ } else if (!strcasecmp(options->TransProxyType, "tproxy")) {
+#if !defined(__linux__)
+ REJECT("TPROXY is a Linux-specific feature.");
+#else
+ options->TransProxyType_parsed = TPT_TPROXY;
+#endif
+ } else if (!strcasecmp(options->TransProxyType, "ipfw")) {
+#if !defined(__FreeBSD__) && !defined( DARWIN )
+ /* Earlier versions of OS X have ipfw */
+ REJECT("ipfw is a FreeBSD-specific"
+ "and OS X/Darwin-specific feature.");
+#else
+ options->TransProxyType_parsed = TPT_IPFW;
+#endif
+ } else {
+ REJECT("Unrecognized value for TransProxyType");
+ }
+
+ if (strcasecmp(options->TransProxyType, "default") &&
+ !options->TransPort_set) {
+ REJECT("Cannot use TransProxyType without any valid TransPort or "
+ "TransListenAddress.");
+ }
+ }
+#else
+ if (options->TransPort_set)
+ REJECT("TransPort and TransListenAddress are disabled "
+ "in this build.");
#endif
if (options->TokenBucketRefillInterval <= 0
@@ -2392,16 +2807,23 @@ options_validate(or_options_t *old_options, or_options_t *options,
REJECT("TokenBucketRefillInterval must be between 1 and 1000 inclusive.");
}
- if (options->DisableV2DirectoryInfo_ && ! authdir_mode(options)) {
- REJECT("DisableV2DirectoryInfo_ set, but we aren't an authority.");
- }
-
if (options->ExcludeExitNodes || options->ExcludeNodes) {
options->ExcludeExitNodesUnion_ = routerset_new();
routerset_union(options->ExcludeExitNodesUnion_,options->ExcludeExitNodes);
routerset_union(options->ExcludeExitNodesUnion_,options->ExcludeNodes);
}
+ if (options->SchedulerLowWaterMark__ == 0 ||
+ options->SchedulerLowWaterMark__ > UINT32_MAX) {
+ log_warn(LD_GENERAL, "Bad SchedulerLowWaterMark__ option");
+ return -1;
+ } else if (options->SchedulerHighWaterMark__ <=
+ options->SchedulerLowWaterMark__ ||
+ options->SchedulerHighWaterMark__ > UINT32_MAX) {
+ log_warn(LD_GENERAL, "Bad SchedulerHighWaterMark option");
+ return -1;
+ }
+
if (options->NodeFamilies) {
options->NodeFamilySets = smartlist_new();
for (cl = options->NodeFamilies; cl; cl = cl->next) {
@@ -2419,6 +2841,9 @@ options_validate(or_options_t *old_options, or_options_t *options,
COMPLAIN("Unrecognized TLSECGroup: Falling back to the default.");
tor_free(options->TLSECGroup);
}
+ if (!evaluate_ecgroup_for_tls(options->TLSECGroup)) {
+ REJECT("Unsupported TLSECGroup.");
+ }
if (options->ExcludeNodes && options->StrictNodes) {
COMPLAIN("You have asked to exclude certain relays from all positions "
@@ -2426,11 +2851,16 @@ options_validate(or_options_t *old_options, or_options_t *options,
"features to be broken in unpredictable ways.");
}
+ for (cl = options->RecommendedPackages; cl; cl = cl->next) {
+ if (! validate_recommended_package_line(cl->value)) {
+ log_warn(LD_CONFIG, "Invalid RecommendedPackage line %s will be ignored",
+ escaped(cl->value));
+ }
+ }
+
if (options->AuthoritativeDir) {
if (!options->ContactInfo && !options->TestingTorNetwork)
REJECT("Authoritative directory servers must set ContactInfo");
- if (options->V1AuthoritativeDir && !options->RecommendedVersions)
- REJECT("V1 authoritative dir servers must set RecommendedVersions.");
if (!options->RecommendedClientVersions)
options->RecommendedClientVersions =
config_lines_dup(options->RecommendedVersions);
@@ -2452,15 +2882,18 @@ options_validate(or_options_t *old_options, or_options_t *options,
"extra-info documents. Setting DownloadExtraInfo.");
options->DownloadExtraInfo = 1;
}
- if (!(options->BridgeAuthoritativeDir || options->HSAuthoritativeDir ||
- options->V1AuthoritativeDir || options->V2AuthoritativeDir ||
+ if (!(options->BridgeAuthoritativeDir ||
options->V3AuthoritativeDir))
REJECT("AuthoritativeDir is set, but none of "
- "(Bridge/HS/V1/V2/V3)AuthoritativeDir is set.");
+ "(Bridge/V3)AuthoritativeDir is set.");
/* If we have a v3bandwidthsfile and it's broken, complain on startup */
if (options->V3BandwidthsFile && !old_options) {
dirserv_read_measured_bandwidths(options->V3BandwidthsFile, NULL);
}
+ /* same for guardfraction file */
+ if (options->GuardfractionFile && !old_options) {
+ dirserv_read_guardfraction_file(options->GuardfractionFile, NULL);
+ }
}
if (options->AuthoritativeDir && !options->DirPort_set)
@@ -2476,10 +2909,6 @@ options_validate(or_options_t *old_options, or_options_t *options,
REJECT("FetchDirInfoExtraEarly requires that you also set "
"FetchDirInfoEarly");
- if (options->HSAuthoritativeDir && proxy_mode(options))
- REJECT("Running as authoritative v0 HS directory, but also configured "
- "as a client.");
-
if (options->ConnLimit <= 0) {
tor_asprintf(msg,
"ConnLimit must be greater than 0, but was set to %d",
@@ -2616,11 +3045,10 @@ options_validate(or_options_t *old_options, or_options_t *options,
REJECT("If EntryNodes is set, UseEntryGuards must be enabled.");
}
- if (options->MaxMemInCellQueues < (256 << 20)) {
- log_warn(LD_CONFIG, "MaxMemInCellQueues must be at least 256 MB for now. "
- "Ideally, have it as large as you can afford.");
- options->MaxMemInCellQueues = (256 << 20);
- }
+ options->MaxMemInQueues =
+ compute_real_max_mem_in_queues(options->MaxMemInQueues_raw,
+ server_mode(options));
+ options->MaxMemInQueues_low_threshold = (options->MaxMemInQueues / 4) * 3;
options->AllowInvalid_ = 0;
@@ -2665,8 +3093,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
if ((options->BridgeRelay
|| options->PublishServerDescriptor_ & BRIDGE_DIRINFO)
- && (options->PublishServerDescriptor_
- & (V1_DIRINFO|V2_DIRINFO|V3_DIRINFO))) {
+ && (options->PublishServerDescriptor_ & V3_DIRINFO)) {
REJECT("Bridges are not supposed to publish router descriptors to the "
"directory authorities. Please correct your "
"PublishServerDescriptor line.");
@@ -2686,10 +3113,13 @@ options_validate(or_options_t *old_options, or_options_t *options,
options->MinUptimeHidServDirectoryV2 = 0;
}
- if (options->RendPostPeriod < MIN_REND_POST_PERIOD) {
+ const int min_rendpostperiod =
+ options->TestingTorNetwork ?
+ MIN_REND_POST_PERIOD_TESTING : MIN_REND_POST_PERIOD;
+ if (options->RendPostPeriod < min_rendpostperiod) {
log_warn(LD_CONFIG, "RendPostPeriod option is too short; "
- "raising to %d seconds.", MIN_REND_POST_PERIOD);
- options->RendPostPeriod = MIN_REND_POST_PERIOD;
+ "raising to %d seconds.", min_rendpostperiod);
+ options->RendPostPeriod = min_rendpostperiod;;
}
if (options->RendPostPeriod > MAX_DIR_PERIOD) {
@@ -2698,6 +3128,14 @@ options_validate(or_options_t *old_options, or_options_t *options,
options->RendPostPeriod = MAX_DIR_PERIOD;
}
+ if (options->PredictedPortsRelevanceTime >
+ MAX_PREDICTED_CIRCS_RELEVANCE) {
+ log_warn(LD_CONFIG, "PredictedPortsRelevanceTime is too large; "
+ "clipping to %ds.", MAX_PREDICTED_CIRCS_RELEVANCE);
+ options->PredictedPortsRelevanceTime = MAX_PREDICTED_CIRCS_RELEVANCE;
+ }
+
+#ifdef ENABLE_TOR2WEB_MODE
if (options->Tor2webMode && options->LearnCircuitBuildTimeout) {
/* LearnCircuitBuildTimeout and Tor2webMode are incompatible in
* two ways:
@@ -2729,6 +3167,11 @@ options_validate(or_options_t *old_options, or_options_t *options,
"Tor2WebMode is enabled; disabling UseEntryGuards.");
options->UseEntryGuards = 0;
}
+#endif
+
+ if (options->Tor2webRendezvousPoints && !options->Tor2webMode) {
+ REJECT("Tor2webRendezvousPoints cannot be set without Tor2webMode.");
+ }
if (!(options->UseEntryGuards) &&
(options->RendConfigLines != NULL)) {
@@ -2739,6 +3182,21 @@ options_validate(or_options_t *old_options, or_options_t *options,
"http://freehaven.net/anonbib/#hs-attack06 for details.");
}
+ if (options->EntryNodes &&
+ routerset_is_list(options->EntryNodes) &&
+ (routerset_len(options->EntryNodes) == 1) &&
+ (options->RendConfigLines != NULL)) {
+ tor_asprintf(msg,
+ "You have one single EntryNodes and at least one hidden service "
+ "configured. This is bad because it's very easy to locate your "
+ "entry guard which can then lead to the deanonymization of your "
+ "hidden service -- for more details, see "
+ "https://trac.torproject.org/projects/tor/ticket/14917. "
+ "For this reason, the use of one EntryNodes with an hidden "
+ "service is prohibited until a better solution is found.");
+ return -1;
+ }
+
if (!options->LearnCircuitBuildTimeout && options->CircuitBuildTimeout &&
options->CircuitBuildTimeout < RECOMMENDED_MIN_CIRCUIT_BUILD_TIMEOUT) {
log_warn(LD_CONFIG,
@@ -2814,6 +3272,11 @@ options_validate(or_options_t *old_options, or_options_t *options,
if (options->KeepalivePeriod < 1)
REJECT("KeepalivePeriod option must be positive.");
+ if (options->PortForwarding && options->Sandbox) {
+ REJECT("PortForwarding is not compatible with Sandbox; at most one can "
+ "be set");
+ }
+
if (ensure_bandwidth_cap(&options->BandwidthRate,
"BandwidthRate", msg) < 0)
return -1;
@@ -2848,29 +3311,34 @@ options_validate(or_options_t *old_options, or_options_t *options,
options->RelayBandwidthRate = options->RelayBandwidthBurst;
if (server_mode(options)) {
- if (options->BandwidthRate < ROUTER_REQUIRED_MIN_BANDWIDTH) {
+ const unsigned required_min_bw =
+ public_server_mode(options) ?
+ RELAY_REQUIRED_MIN_BANDWIDTH : BRIDGE_REQUIRED_MIN_BANDWIDTH;
+ const char * const optbridge =
+ public_server_mode(options) ? "" : "bridge ";
+ if (options->BandwidthRate < required_min_bw) {
tor_asprintf(msg,
"BandwidthRate is set to %d bytes/second. "
- "For servers, it must be at least %d.",
- (int)options->BandwidthRate,
- ROUTER_REQUIRED_MIN_BANDWIDTH);
+ "For %sservers, it must be at least %u.",
+ (int)options->BandwidthRate, optbridge,
+ required_min_bw);
return -1;
} else if (options->MaxAdvertisedBandwidth <
- ROUTER_REQUIRED_MIN_BANDWIDTH/2) {
+ required_min_bw/2) {
tor_asprintf(msg,
"MaxAdvertisedBandwidth is set to %d bytes/second. "
- "For servers, it must be at least %d.",
- (int)options->MaxAdvertisedBandwidth,
- ROUTER_REQUIRED_MIN_BANDWIDTH/2);
+ "For %sservers, it must be at least %u.",
+ (int)options->MaxAdvertisedBandwidth, optbridge,
+ required_min_bw/2);
return -1;
}
if (options->RelayBandwidthRate &&
- options->RelayBandwidthRate < ROUTER_REQUIRED_MIN_BANDWIDTH) {
+ options->RelayBandwidthRate < required_min_bw) {
tor_asprintf(msg,
"RelayBandwidthRate is set to %d bytes/second. "
- "For servers, it must be at least %d.",
- (int)options->RelayBandwidthRate,
- ROUTER_REQUIRED_MIN_BANDWIDTH);
+ "For %sservers, it must be at least %u.",
+ (int)options->RelayBandwidthRate, optbridge,
+ required_min_bw);
return -1;
}
}
@@ -2906,6 +3374,16 @@ options_validate(or_options_t *old_options, or_options_t *options,
}
}
+ options->AccountingRule = ACCT_MAX;
+ if (options->AccountingRule_option) {
+ if (!strcmp(options->AccountingRule_option, "sum"))
+ options->AccountingRule = ACCT_SUM;
+ else if (!strcmp(options->AccountingRule_option, "max"))
+ options->AccountingRule = ACCT_MAX;
+ else
+ REJECT("AccountingRule must be 'sum' or 'max'");
+ }
+
if (options->HTTPProxy) { /* parse it now */
if (tor_addr_port_lookup(options->HTTPProxy,
&options->HTTPProxyAddr, &options->HTTPProxyPort) < 0)
@@ -2954,11 +3432,11 @@ options_validate(or_options_t *old_options, or_options_t *options,
}
}
- /* Check if more than one proxy type has been enabled. */
+ /* Check if more than one exclusive proxy type has been enabled. */
if (!!options->Socks4Proxy + !!options->Socks5Proxy +
- !!options->HTTPSProxy + !!options->ClientTransportPlugin > 1)
+ !!options->HTTPSProxy > 1)
REJECT("You have configured more than one proxy type. "
- "(Socks4Proxy|Socks5Proxy|HTTPSProxy|ClientTransportPlugin)");
+ "(Socks4Proxy|Socks5Proxy|HTTPSProxy)");
/* Check if the proxies will give surprising behavior. */
if (options->HTTPProxy && !(options->Socks4Proxy ||
@@ -2973,14 +3451,14 @@ options_validate(or_options_t *old_options, or_options_t *options,
size_t len;
len = strlen(options->Socks5ProxyUsername);
- if (len < 1 || len > 255)
+ if (len < 1 || len > MAX_SOCKS5_AUTH_FIELD_SIZE)
REJECT("Socks5ProxyUsername must be between 1 and 255 characters.");
if (!options->Socks5ProxyPassword)
REJECT("Socks5ProxyPassword must be included with Socks5ProxyUsername.");
len = strlen(options->Socks5ProxyPassword);
- if (len < 1 || len > 255)
+ if (len < 1 || len > MAX_SOCKS5_AUTH_FIELD_SIZE)
REJECT("Socks5ProxyPassword must be between 1 and 255 characters.");
} else if (options->Socks5ProxyPassword)
REJECT("Socks5ProxyPassword must be included with Socks5ProxyUsername.");
@@ -3016,13 +3494,16 @@ options_validate(or_options_t *old_options, or_options_t *options,
}
}
- if (options->ControlPort_set && !options->HashedControlPassword &&
+ if ((options->ControlPort_set || world_writable_control_socket) &&
+ !options->HashedControlPassword &&
!options->HashedControlSessionPassword &&
!options->CookieAuthentication) {
- log_warn(LD_CONFIG, "ControlPort is open, but no authentication method "
+ log_warn(LD_CONFIG, "Control%s is %s, but no authentication method "
"has been configured. This means that any program on your "
"computer can reconfigure your Tor. That's bad! You should "
- "upgrade your Tor controller as soon as possible.");
+ "upgrade your Tor controller as soon as possible.",
+ options->ControlPort_set ? "Port" : "Socket",
+ options->ControlPort_set ? "open" : "world writable");
}
if (options->CookieAuthFileGroupReadable && !options->CookieAuthFile) {
@@ -3037,7 +3518,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
"You should also make sure you aren't listing this bridge's "
"fingerprint in any other MyFamily.");
}
- if (check_nickname_list(options->MyFamily, "MyFamily", msg))
+ if (check_nickname_list(&options->MyFamily, "MyFamily", msg))
return -1;
for (cl = options->NodeFamilies; cl; cl = cl->next) {
routerset_t *rs = routerset_new();
@@ -3057,26 +3538,22 @@ options_validate(or_options_t *old_options, or_options_t *options,
if (options->UseBridges && !options->Bridges)
REJECT("If you set UseBridges, you must specify at least one bridge.");
- if (options->UseBridges && !options->TunnelDirConns)
- REJECT("If you set UseBridges, you must set TunnelDirConns.");
- if (options->RendConfigLines &&
- (!options->TunnelDirConns || !options->PreferTunneledDirConns))
- REJECT("If you are running a hidden service, you must set TunnelDirConns "
- "and PreferTunneledDirConns");
for (cl = options->Bridges; cl; cl = cl->next) {
- if (parse_bridge_line(cl->value, 1)<0)
- REJECT("Bridge line did not parse. See logs for details.");
+ bridge_line_t *bridge_line = parse_bridge_line(cl->value);
+ if (!bridge_line)
+ REJECT("Bridge line did not parse. See logs for details.");
+ bridge_line_free(bridge_line);
}
for (cl = options->ClientTransportPlugin; cl; cl = cl->next) {
- if (parse_client_transport_line(cl->value, 1)<0)
- REJECT("Transport line did not parse. See logs for details.");
+ if (parse_transport_line(options, cl->value, 1, 0) < 0)
+ REJECT("Invalid client transport line. See logs for details.");
}
for (cl = options->ServerTransportPlugin; cl; cl = cl->next) {
- if (parse_server_transport_line(cl->value, 1)<0)
- REJECT("Server transport line did not parse. See logs for details.");
+ if (parse_transport_line(options, cl->value, 1, 1) < 0)
+ REJECT("Invalid server transport line. See logs for details.");
}
if (options->ServerTransportPlugin && !server_mode(options)) {
@@ -3102,6 +3579,19 @@ options_validate(or_options_t *old_options, or_options_t *options,
"ServerTransportListenAddr line will be ignored.");
}
+ for (cl = options->ServerTransportOptions; cl; cl = cl->next) {
+ /** If get_options_from_transport_options_line() fails with
+ 'transport' being NULL, it means that something went wrong
+ while parsing the ServerTransportOptions line. */
+ smartlist_t *options_sl =
+ get_options_from_transport_options_line(cl->value, NULL);
+ if (!options_sl)
+ REJECT("ServerTransportOptions did not parse. See logs for details.");
+
+ SMARTLIST_FOREACH(options_sl, char *, cp, tor_free(cp));
+ smartlist_free(options_sl);
+ }
+
if (options->ConstrainedSockets) {
/* If the user wants to constrain socket buffer use, make sure the desired
* limit is between MIN|MAX_TCPSOCK_BUFFER in k increments. */
@@ -3126,19 +3616,68 @@ options_validate(or_options_t *old_options, or_options_t *options,
if (options->V3AuthVoteDelay + options->V3AuthDistDelay >=
options->V3AuthVotingInterval/2) {
- REJECT("V3AuthVoteDelay plus V3AuthDistDelay must be less than half "
- "V3AuthVotingInterval");
+ /*
+ This doesn't work, but it seems like it should:
+ what code is preventing the interval being less than twice the lead-up?
+ if (options->TestingTorNetwork) {
+ if (options->V3AuthVoteDelay + options->V3AuthDistDelay >=
+ options->V3AuthVotingInterval) {
+ REJECT("V3AuthVoteDelay plus V3AuthDistDelay must be less than "
+ "V3AuthVotingInterval");
+ } else {
+ COMPLAIN("V3AuthVoteDelay plus V3AuthDistDelay is more than half "
+ "V3AuthVotingInterval. This may lead to "
+ "consensus instability, particularly if clocks drift.");
+ }
+ } else {
+ */
+ REJECT("V3AuthVoteDelay plus V3AuthDistDelay must be less than half "
+ "V3AuthVotingInterval");
+ /*
+ }
+ */
+ }
+
+ if (options->V3AuthVoteDelay < MIN_VOTE_SECONDS) {
+ if (options->TestingTorNetwork) {
+ if (options->V3AuthVoteDelay < MIN_VOTE_SECONDS_TESTING) {
+ REJECT("V3AuthVoteDelay is way too low.");
+ } else {
+ COMPLAIN("V3AuthVoteDelay is very low. "
+ "This may lead to failure to vote for a consensus.");
+ }
+ } else {
+ REJECT("V3AuthVoteDelay is way too low.");
+ }
+ }
+
+ if (options->V3AuthDistDelay < MIN_DIST_SECONDS) {
+ if (options->TestingTorNetwork) {
+ if (options->V3AuthDistDelay < MIN_DIST_SECONDS_TESTING) {
+ REJECT("V3AuthDistDelay is way too low.");
+ } else {
+ COMPLAIN("V3AuthDistDelay is very low. "
+ "This may lead to missing votes in a consensus.");
+ }
+ } else {
+ REJECT("V3AuthDistDelay is way too low.");
+ }
}
- if (options->V3AuthVoteDelay < MIN_VOTE_SECONDS)
- REJECT("V3AuthVoteDelay is way too low.");
- if (options->V3AuthDistDelay < MIN_DIST_SECONDS)
- REJECT("V3AuthDistDelay is way too low.");
if (options->V3AuthNIntervalsValid < 2)
REJECT("V3AuthNIntervalsValid must be at least 2.");
if (options->V3AuthVotingInterval < MIN_VOTE_INTERVAL) {
- REJECT("V3AuthVotingInterval is insanely low.");
+ if (options->TestingTorNetwork) {
+ if (options->V3AuthVotingInterval < MIN_VOTE_INTERVAL_TESTING) {
+ REJECT("V3AuthVotingInterval is insanely low.");
+ } else {
+ COMPLAIN("V3AuthVotingInterval is very low. "
+ "This may lead to failure to synchronise for a consensus.");
+ }
+ } else {
+ REJECT("V3AuthVotingInterval is insanely low.");
+ }
} else if (options->V3AuthVotingInterval > 24*60*60) {
REJECT("V3AuthVotingInterval is insanely high.");
} else if (((24*60*60) % options->V3AuthVotingInterval) != 0) {
@@ -3160,24 +3699,6 @@ options_validate(or_options_t *old_options, or_options_t *options,
AF_INET6, 1, msg)<0)
return -1;
- if (options->PreferTunneledDirConns && !options->TunnelDirConns)
- REJECT("Must set TunnelDirConns if PreferTunneledDirConns is set.");
-
- if ((options->Socks4Proxy || options->Socks5Proxy) &&
- !options->HTTPProxy && !options->PreferTunneledDirConns)
- REJECT("When Socks4Proxy or Socks5Proxy is configured, "
- "PreferTunneledDirConns and TunnelDirConns must both be "
- "set to 1, or HTTPProxy must be configured.");
-
- if (options->AutomapHostsSuffixes) {
- SMARTLIST_FOREACH(options->AutomapHostsSuffixes, char *, suf,
- {
- size_t len = strlen(suf);
- if (len && suf[len-1] == '.')
- suf[len-1] = '\0';
- });
- }
-
if (options->TestingTorNetwork &&
!(options->DirAuthorities ||
(options->AlternateDirAuthority &&
@@ -3194,65 +3715,144 @@ options_validate(or_options_t *old_options, or_options_t *options,
"ignore you.");
}
- /*XXXX checking for defaults manually like this is a bit fragile.*/
-
- /* Keep changes to hard-coded values synchronous to man page and default
- * values table. */
- if (options->TestingV3AuthInitialVotingInterval != 30*60 &&
- !options->TestingTorNetwork && !options->UsingTestNetworkDefaults_) {
- REJECT("TestingV3AuthInitialVotingInterval may only be changed in testing "
- "Tor networks!");
- } else if (options->TestingV3AuthInitialVotingInterval < MIN_VOTE_INTERVAL) {
+#define CHECK_DEFAULT(arg) \
+ STMT_BEGIN \
+ if (!options->TestingTorNetwork && \
+ !options->UsingTestNetworkDefaults_ && \
+ !config_is_same(&options_format,options, \
+ default_options,#arg)) { \
+ REJECT(#arg " may only be changed in testing Tor " \
+ "networks!"); \
+ } STMT_END
+ CHECK_DEFAULT(TestingV3AuthInitialVotingInterval);
+ CHECK_DEFAULT(TestingV3AuthInitialVoteDelay);
+ CHECK_DEFAULT(TestingV3AuthInitialDistDelay);
+ CHECK_DEFAULT(TestingV3AuthVotingStartOffset);
+ CHECK_DEFAULT(TestingAuthDirTimeToLearnReachability);
+ CHECK_DEFAULT(TestingEstimatedDescriptorPropagationTime);
+ CHECK_DEFAULT(TestingServerDownloadSchedule);
+ CHECK_DEFAULT(TestingClientDownloadSchedule);
+ CHECK_DEFAULT(TestingServerConsensusDownloadSchedule);
+ CHECK_DEFAULT(TestingClientConsensusDownloadSchedule);
+ CHECK_DEFAULT(TestingBridgeDownloadSchedule);
+ CHECK_DEFAULT(TestingClientMaxIntervalWithoutRequest);
+ CHECK_DEFAULT(TestingDirConnectionMaxStall);
+ CHECK_DEFAULT(TestingConsensusMaxDownloadTries);
+ CHECK_DEFAULT(TestingDescriptorMaxDownloadTries);
+ CHECK_DEFAULT(TestingMicrodescMaxDownloadTries);
+ CHECK_DEFAULT(TestingCertMaxDownloadTries);
+ CHECK_DEFAULT(TestingAuthKeyLifetime);
+ CHECK_DEFAULT(TestingLinkCertLifetime);
+ CHECK_DEFAULT(TestingSigningKeySlop);
+ CHECK_DEFAULT(TestingAuthKeySlop);
+ CHECK_DEFAULT(TestingLinkKeySlop);
+#undef CHECK_DEFAULT
+
+ if (options->SigningKeyLifetime < options->TestingSigningKeySlop*2)
+ REJECT("SigningKeyLifetime is too short.");
+ if (options->TestingLinkCertLifetime < options->TestingAuthKeySlop*2)
+ REJECT("LinkCertLifetime is too short.");
+ if (options->TestingAuthKeyLifetime < options->TestingLinkKeySlop*2)
+ REJECT("TestingAuthKeyLifetime is too short.");
+
+ if (options->TestingV3AuthInitialVotingInterval
+ < MIN_VOTE_INTERVAL_TESTING_INITIAL) {
REJECT("TestingV3AuthInitialVotingInterval is insanely low.");
} else if (((30*60) % options->TestingV3AuthInitialVotingInterval) != 0) {
REJECT("TestingV3AuthInitialVotingInterval does not divide evenly into "
"30 minutes.");
}
- if (options->TestingV3AuthInitialVoteDelay != 5*60 &&
- !options->TestingTorNetwork && !options->UsingTestNetworkDefaults_) {
-
- REJECT("TestingV3AuthInitialVoteDelay may only be changed in testing "
- "Tor networks!");
- } else if (options->TestingV3AuthInitialVoteDelay < MIN_VOTE_SECONDS) {
+ if (options->TestingV3AuthInitialVoteDelay < MIN_VOTE_SECONDS_TESTING) {
REJECT("TestingV3AuthInitialVoteDelay is way too low.");
}
- if (options->TestingV3AuthInitialDistDelay != 5*60 &&
- !options->TestingTorNetwork && !options->UsingTestNetworkDefaults_) {
- REJECT("TestingV3AuthInitialDistDelay may only be changed in testing "
- "Tor networks!");
- } else if (options->TestingV3AuthInitialDistDelay < MIN_DIST_SECONDS) {
+ if (options->TestingV3AuthInitialDistDelay < MIN_DIST_SECONDS_TESTING) {
REJECT("TestingV3AuthInitialDistDelay is way too low.");
}
if (options->TestingV3AuthInitialVoteDelay +
options->TestingV3AuthInitialDistDelay >=
- options->TestingV3AuthInitialVotingInterval/2) {
+ options->TestingV3AuthInitialVotingInterval) {
REJECT("TestingV3AuthInitialVoteDelay plus TestingV3AuthInitialDistDelay "
- "must be less than half TestingV3AuthInitialVotingInterval");
+ "must be less than TestingV3AuthInitialVotingInterval");
}
- if (options->TestingAuthDirTimeToLearnReachability != 30*60 &&
- !options->TestingTorNetwork && !options->UsingTestNetworkDefaults_) {
- REJECT("TestingAuthDirTimeToLearnReachability may only be changed in "
- "testing Tor networks!");
- } else if (options->TestingAuthDirTimeToLearnReachability < 0) {
+ if (options->TestingV3AuthVotingStartOffset >
+ MIN(options->TestingV3AuthInitialVotingInterval,
+ options->V3AuthVotingInterval)) {
+ REJECT("TestingV3AuthVotingStartOffset is higher than the voting "
+ "interval.");
+ } else if (options->TestingV3AuthVotingStartOffset < 0) {
+ REJECT("TestingV3AuthVotingStartOffset must be non-negative.");
+ }
+
+ if (options->TestingAuthDirTimeToLearnReachability < 0) {
REJECT("TestingAuthDirTimeToLearnReachability must be non-negative.");
} else if (options->TestingAuthDirTimeToLearnReachability > 2*60*60) {
COMPLAIN("TestingAuthDirTimeToLearnReachability is insanely high.");
}
- if (options->TestingEstimatedDescriptorPropagationTime != 10*60 &&
- !options->TestingTorNetwork && !options->UsingTestNetworkDefaults_) {
- REJECT("TestingEstimatedDescriptorPropagationTime may only be changed in "
- "testing Tor networks!");
- } else if (options->TestingEstimatedDescriptorPropagationTime < 0) {
+ if (options->TestingEstimatedDescriptorPropagationTime < 0) {
REJECT("TestingEstimatedDescriptorPropagationTime must be non-negative.");
} else if (options->TestingEstimatedDescriptorPropagationTime > 60*60) {
COMPLAIN("TestingEstimatedDescriptorPropagationTime is insanely high.");
}
+ if (options->TestingClientMaxIntervalWithoutRequest < 1) {
+ REJECT("TestingClientMaxIntervalWithoutRequest is way too low.");
+ } else if (options->TestingClientMaxIntervalWithoutRequest > 3600) {
+ COMPLAIN("TestingClientMaxIntervalWithoutRequest is insanely high.");
+ }
+
+ if (options->TestingDirConnectionMaxStall < 5) {
+ REJECT("TestingDirConnectionMaxStall is way too low.");
+ } else if (options->TestingDirConnectionMaxStall > 3600) {
+ COMPLAIN("TestingDirConnectionMaxStall is insanely high.");
+ }
+
+ if (options->TestingConsensusMaxDownloadTries < 2) {
+ REJECT("TestingConsensusMaxDownloadTries must be greater than 1.");
+ } else if (options->TestingConsensusMaxDownloadTries > 800) {
+ COMPLAIN("TestingConsensusMaxDownloadTries is insanely high.");
+ }
+
+ if (options->TestingDescriptorMaxDownloadTries < 2) {
+ REJECT("TestingDescriptorMaxDownloadTries must be greater than 1.");
+ } else if (options->TestingDescriptorMaxDownloadTries > 800) {
+ COMPLAIN("TestingDescriptorMaxDownloadTries is insanely high.");
+ }
+
+ if (options->TestingMicrodescMaxDownloadTries < 2) {
+ REJECT("TestingMicrodescMaxDownloadTries must be greater than 1.");
+ } else if (options->TestingMicrodescMaxDownloadTries > 800) {
+ COMPLAIN("TestingMicrodescMaxDownloadTries is insanely high.");
+ }
+
+ if (options->TestingCertMaxDownloadTries < 2) {
+ REJECT("TestingCertMaxDownloadTries must be greater than 1.");
+ } else if (options->TestingCertMaxDownloadTries > 800) {
+ COMPLAIN("TestingCertMaxDownloadTries is insanely high.");
+ }
+
+ if (options->TestingEnableConnBwEvent &&
+ !options->TestingTorNetwork && !options->UsingTestNetworkDefaults_) {
+ REJECT("TestingEnableConnBwEvent may only be changed in testing "
+ "Tor networks!");
+ }
+
+ if (options->TestingEnableCellStatsEvent &&
+ !options->TestingTorNetwork && !options->UsingTestNetworkDefaults_) {
+ REJECT("TestingEnableCellStatsEvent may only be changed in testing "
+ "Tor networks!");
+ }
+
+ if (options->TestingEnableTbEmptyEvent &&
+ !options->TestingTorNetwork && !options->UsingTestNetworkDefaults_) {
+ REJECT("TestingEnableTbEmptyEvent may only be changed in testing "
+ "Tor networks!");
+ }
+
if (options->TestingTorNetwork) {
log_warn(LD_CONFIG, "TestingTorNetwork is set. This will make your node "
"almost unusable in the public Tor network, and is "
@@ -3282,8 +3882,71 @@ options_validate(or_options_t *old_options, or_options_t *options,
"combination.");
return 0;
+}
+
#undef REJECT
#undef COMPLAIN
+
+/* Given the value that the user has set for MaxMemInQueues, compute the
+ * actual maximum value. We clip this value if it's too low, and autodetect
+ * it if it's set to 0. */
+static uint64_t
+compute_real_max_mem_in_queues(const uint64_t val, int log_guess)
+{
+ uint64_t result;
+
+ if (val == 0) {
+#define ONE_GIGABYTE (U64_LITERAL(1) << 30)
+#define ONE_MEGABYTE (U64_LITERAL(1) << 20)
+#if SIZEOF_VOID_P >= 8
+#define MAX_DEFAULT_MAXMEM (8*ONE_GIGABYTE)
+#else
+#define MAX_DEFAULT_MAXMEM (2*ONE_GIGABYTE)
+#endif
+ /* The user didn't pick a memory limit. Choose a very large one
+ * that is still smaller than the system memory */
+ static int notice_sent = 0;
+ size_t ram = 0;
+ if (get_total_system_memory(&ram) < 0) {
+ /* We couldn't determine our total system memory! */
+#if SIZEOF_VOID_P >= 8
+ /* 64-bit system. Let's hope for 8 GB. */
+ result = 8 * ONE_GIGABYTE;
+#else
+ /* (presumably) 32-bit system. Let's hope for 1 GB. */
+ result = ONE_GIGABYTE;
+#endif
+ } else {
+ /* We detected it, so let's pick 3/4 of the total RAM as our limit. */
+ const uint64_t avail = (ram / 4) * 3;
+
+ /* Make sure it's in range from 0.25 GB to 8 GB. */
+ if (avail > MAX_DEFAULT_MAXMEM) {
+ /* If you want to use more than this much RAM, you need to configure
+ it yourself */
+ result = MAX_DEFAULT_MAXMEM;
+ } else if (avail < ONE_GIGABYTE / 4) {
+ result = ONE_GIGABYTE / 4;
+ } else {
+ result = avail;
+ }
+ }
+ if (log_guess && ! notice_sent) {
+ log_notice(LD_CONFIG, "%sMaxMemInQueues is set to "U64_FORMAT" MB. "
+ "You can override this by setting MaxMemInQueues by hand.",
+ ram ? "Based on detected system memory, " : "",
+ U64_PRINTF_ARG(result / ONE_MEGABYTE));
+ notice_sent = 1;
+ }
+ return result;
+ } else if (val < ONE_GIGABYTE / 4) {
+ log_warn(LD_CONFIG, "MaxMemInQueues must be at least 256 MB for now. "
+ "Ideally, have it as large as you can afford.");
+ return ONE_GIGABYTE / 4;
+ } else {
+ /* The value was fine all along */
+ return val;
+ }
}
/** Helper: return true iff s1 and s2 are both NULL, or both non-NULL
@@ -3314,6 +3977,12 @@ options_transition_allowed(const or_options_t *old,
return -1;
}
+ if (old->Sandbox != new_val->Sandbox) {
+ *msg = tor_strdup("While Tor is running, changing Sandbox "
+ "is not allowed.");
+ return -1;
+ }
+
if (strcmp(old->DataDirectory,new_val->DataDirectory)!=0) {
tor_asprintf(msg,
"While Tor is running, changing DataDirectory "
@@ -3366,6 +4035,38 @@ options_transition_allowed(const or_options_t *old,
return -1;
}
+ if (sandbox_is_active()) {
+#define SB_NOCHANGE_STR(opt) \
+ do { \
+ if (! opt_streq(old->opt, new_val->opt)) { \
+ *msg = tor_strdup("Can't change " #opt " while Sandbox is active"); \
+ return -1; \
+ } \
+ } while (0)
+
+ SB_NOCHANGE_STR(PidFile);
+ SB_NOCHANGE_STR(ServerDNSResolvConfFile);
+ SB_NOCHANGE_STR(DirPortFrontPage);
+ SB_NOCHANGE_STR(CookieAuthFile);
+ SB_NOCHANGE_STR(ExtORPortCookieAuthFile);
+
+#undef SB_NOCHANGE_STR
+
+ if (! config_lines_eq(old->Logs, new_val->Logs)) {
+ *msg = tor_strdup("Can't change Logs while Sandbox is active");
+ return -1;
+ }
+ if (old->ConnLimit != new_val->ConnLimit) {
+ *msg = tor_strdup("Can't change ConnLimit while Sandbox is active");
+ return -1;
+ }
+ if (server_mode(old) != server_mode(new_val)) {
+ *msg = tor_strdup("Can't start/stop being a server while "
+ "Sandbox is active");
+ return -1;
+ }
+ }
+
return 0;
}
@@ -3405,6 +4106,7 @@ options_transition_affects_descriptor(const or_options_t *old_options,
!opt_streq(old_options->Nickname,new_options->Nickname) ||
!opt_streq(old_options->Address,new_options->Address) ||
!config_lines_eq(old_options->ExitPolicy,new_options->ExitPolicy) ||
+ old_options->ExitRelay != new_options->ExitRelay ||
old_options->ExitPolicyRejectPrivate !=
new_options->ExitPolicyRejectPrivate ||
old_options->IPv6Exit != new_options->IPv6Exit ||
@@ -3493,7 +4195,10 @@ get_windows_conf_root(void)
static const char *
get_default_conf_file(int defaults_file)
{
-#ifdef _WIN32
+#ifdef DISABLE_SYSTEM_TORRC
+ (void) defaults_file;
+ return NULL;
+#elif defined(_WIN32)
if (defaults_file) {
static char defaults_path[MAX_PATH+1];
tor_snprintf(defaults_path, MAX_PATH, "%s\\torrc-defaults",
@@ -3511,31 +4216,63 @@ get_default_conf_file(int defaults_file)
}
/** Verify whether lst is a string containing valid-looking comma-separated
- * nicknames, or NULL. Return 0 on success. Warn and return -1 on failure.
+ * nicknames, or NULL. Will normalise <b>lst</b> to prefix '$' to any nickname
+ * or fingerprint that needs it. Return 0 on success.
+ * Warn and return -1 on failure.
*/
static int
-check_nickname_list(const char *lst, const char *name, char **msg)
+check_nickname_list(char **lst, const char *name, char **msg)
{
int r = 0;
smartlist_t *sl;
+ int changes = 0;
- if (!lst)
+ if (!*lst)
return 0;
sl = smartlist_new();
- smartlist_split_string(sl, lst, ",",
+ smartlist_split_string(sl, *lst, ",",
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK|SPLIT_STRIP_SPACE, 0);
- SMARTLIST_FOREACH(sl, const char *, s,
+ SMARTLIST_FOREACH_BEGIN(sl, char *, s)
{
if (!is_legal_nickname_or_hexdigest(s)) {
+ // check if first char is dollar
+ if (s[0] != '$') {
+ // Try again but with a dollar symbol prepended
+ char *prepended;
+ tor_asprintf(&prepended, "$%s", s);
+
+ if (is_legal_nickname_or_hexdigest(prepended)) {
+ // The nickname is valid when it's prepended, swap the current
+ // version with a prepended one
+ tor_free(s);
+ SMARTLIST_REPLACE_CURRENT(sl, s, prepended);
+ changes = 1;
+ continue;
+ }
+
+ // Still not valid, free and fallback to error message
+ tor_free(prepended);
+ }
+
tor_asprintf(msg, "Invalid nickname '%s' in %s line", s, name);
r = -1;
break;
}
- });
+ }
+ SMARTLIST_FOREACH_END(s);
+
+ // Replace the caller's nickname list with a fixed one
+ if (changes && r == 0) {
+ char *newNicknames = smartlist_join_strings(sl, ", ", 0, NULL);
+ tor_free(*lst);
+ *lst = newNicknames;
+ }
+
SMARTLIST_FOREACH(sl, char *, s, tor_free(s));
smartlist_free(sl);
+
return r;
}
@@ -3551,26 +4288,26 @@ check_nickname_list(const char *lst, const char *name, char **msg)
* filename if it doesn't exist.
*/
static char *
-find_torrc_filename(int argc, char **argv,
+find_torrc_filename(config_line_t *cmd_arg,
int defaults_file,
int *using_default_fname, int *ignore_missing_torrc)
{
char *fname=NULL;
- int i;
+ config_line_t *p_index;
const char *fname_opt = defaults_file ? "--defaults-torrc" : "-f";
const char *ignore_opt = defaults_file ? NULL : "--ignore-missing-torrc";
if (defaults_file)
*ignore_missing_torrc = 1;
- for (i = 1; i < argc; ++i) {
- if (i < argc-1 && !strcmp(argv[i],fname_opt)) {
+ for (p_index = cmd_arg; p_index; p_index = p_index->next) {
+ if (!strcmp(p_index->key, fname_opt)) {
if (fname) {
log_warn(LD_CONFIG, "Duplicate %s options on command line.",
fname_opt);
tor_free(fname);
}
- fname = expand_filename(argv[i+1]);
+ fname = expand_filename(p_index->value);
{
char *absfname;
@@ -3580,8 +4317,7 @@ find_torrc_filename(int argc, char **argv,
}
*using_default_fname = 0;
- ++i;
- } else if (ignore_opt && !strcmp(argv[i],ignore_opt)) {
+ } else if (ignore_opt && !strcmp(p_index->key,ignore_opt)) {
*ignore_missing_torrc = 1;
}
}
@@ -3589,27 +4325,45 @@ find_torrc_filename(int argc, char **argv,
if (*using_default_fname) {
/* didn't find one, try CONFDIR */
const char *dflt = get_default_conf_file(defaults_file);
- if (dflt && file_status(dflt) == FN_FILE) {
+ file_status_t st = file_status(dflt);
+ if (dflt && (st == FN_FILE || st == FN_EMPTY)) {
fname = tor_strdup(dflt);
} else {
#ifndef _WIN32
char *fn = NULL;
- if (!defaults_file)
+ if (!defaults_file) {
fn = expand_filename("~/.torrc");
- if (fn && file_status(fn) == FN_FILE) {
- fname = fn;
+ }
+ if (fn) {
+ file_status_t hmst = file_status(fn);
+ if (hmst == FN_FILE || hmst == FN_EMPTY || dflt == NULL) {
+ fname = fn;
+ } else {
+ tor_free(fn);
+ fname = tor_strdup(dflt);
+ }
} else {
- tor_free(fn);
- fname = tor_strdup(dflt);
+ fname = dflt ? tor_strdup(dflt) : NULL;
}
#else
- fname = tor_strdup(dflt);
+ fname = dflt ? tor_strdup(dflt) : NULL;
#endif
}
}
return fname;
}
+/** Read the torrc from standard input and return it as a string.
+ * Upon failure, return NULL.
+ */
+static char *
+load_torrc_from_stdin(void)
+{
+ size_t sz_out;
+
+ return read_file_to_str_until_eof(STDIN_FILENO,SIZE_MAX,&sz_out);
+}
+
/** Load a configuration file from disk, setting torrc_fname or
* torrc_defaults_fname if successful.
*
@@ -3618,7 +4372,7 @@ find_torrc_filename(int argc, char **argv,
* Return the contents of the file on success, and NULL on failure.
*/
static char *
-load_torrc_from_disk(int argc, char **argv, int defaults_file)
+load_torrc_from_disk(config_line_t *cmd_arg, int defaults_file)
{
char *fname=NULL;
char *cf = NULL;
@@ -3626,16 +4380,20 @@ load_torrc_from_disk(int argc, char **argv, int defaults_file)
int ignore_missing_torrc = 0;
char **fname_var = defaults_file ? &torrc_defaults_fname : &torrc_fname;
- fname = find_torrc_filename(argc, argv, defaults_file,
- &using_default_torrc, &ignore_missing_torrc);
- tor_assert(fname);
- log_debug(LD_CONFIG, "Opening config file \"%s\"", fname);
-
- tor_free(*fname_var);
- *fname_var = fname;
+ if (*fname_var == NULL) {
+ fname = find_torrc_filename(cmd_arg, defaults_file,
+ &using_default_torrc, &ignore_missing_torrc);
+ tor_free(*fname_var);
+ *fname_var = fname;
+ } else {
+ fname = *fname_var;
+ }
+ log_debug(LD_CONFIG, "Opening config file \"%s\"", fname?fname:"<NULL>");
/* Open config file */
- if (file_status(fname) != FN_FILE ||
+ file_status_t st = fname ? file_status(fname) : FN_EMPTY;
+ if (fname == NULL ||
+ !(st == FN_FILE || st == FN_EMPTY) ||
!(cf = read_file_to_str(fname,0,NULL))) {
if (using_default_torrc == 1 || ignore_missing_torrc) {
if (!defaults_file)
@@ -3668,59 +4426,70 @@ int
options_init_from_torrc(int argc, char **argv)
{
char *cf=NULL, *cf_defaults=NULL;
- int i, command;
+ int command;
int retval = -1;
- static char **backup_argv;
- static int backup_argc;
char *command_arg = NULL;
char *errmsg=NULL;
+ config_line_t *p_index = NULL;
+ config_line_t *cmdline_only_options = NULL;
- if (argv) { /* first time we're called. save command line args */
- backup_argv = argv;
- backup_argc = argc;
- } else { /* we're reloading. need to clean up old options first. */
- argv = backup_argv;
- argc = backup_argc;
+ /* Go through command-line variables */
+ if (! have_parsed_cmdline) {
+ /* Or we could redo the list every time we pass this place.
+ * It does not really matter */
+ if (config_parse_commandline(argc, argv, 0, &global_cmdline_options,
+ &global_cmdline_only_options) < 0) {
+ goto err;
+ }
+ have_parsed_cmdline = 1;
}
- if (argc > 1 && (!strcmp(argv[1], "-h") || !strcmp(argv[1],"--help"))) {
+ cmdline_only_options = global_cmdline_only_options;
+
+ if (config_line_find(cmdline_only_options, "-h") ||
+ config_line_find(cmdline_only_options, "--help")) {
print_usage();
exit(0);
}
- if (argc > 1 && !strcmp(argv[1], "--list-torrc-options")) {
+ if (config_line_find(cmdline_only_options, "--list-torrc-options")) {
/* For documenting validating whether we've documented everything. */
list_torrc_options();
exit(0);
}
- if (argc > 1 && (!strcmp(argv[1],"--version"))) {
+ if (config_line_find(cmdline_only_options, "--version")) {
printf("Tor version %s.\n",get_version());
exit(0);
}
- if (argc > 1 && (!strcmp(argv[1],"--digests"))) {
- printf("Tor version %s.\n",get_version());
- printf("%s", libor_get_digests());
- printf("%s", tor_get_digests());
- exit(0);
- }
- /* Go through command-line variables */
- if (!global_cmdline_options) {
- /* Or we could redo the list every time we pass this place.
- * It does not really matter */
- if (config_get_commandlines(argc, argv, &global_cmdline_options) < 0) {
- goto err;
- }
+ if (config_line_find(cmdline_only_options, "--library-versions")) {
+ printf("Tor version %s. \n", get_version());
+ printf("Library versions\tCompiled\t\tRuntime\n");
+ printf("Libevent\t\t%-15s\t\t%s\n",
+ tor_libevent_get_header_version_str(),
+ tor_libevent_get_version_str());
+ printf("OpenSSL \t\t%-15s\t\t%s\n",
+ crypto_openssl_get_header_version_str(),
+ crypto_openssl_get_version_str());
+ printf("Zlib \t\t%-15s\t\t%s\n",
+ tor_zlib_get_header_version_str(),
+ tor_zlib_get_version_str());
+ //TODO: Hex versions?
+ exit(0);
}
command = CMD_RUN_TOR;
- for (i = 1; i < argc; ++i) {
- if (!strcmp(argv[i],"--list-fingerprint")) {
+ for (p_index = cmdline_only_options; p_index; p_index = p_index->next) {
+ if (!strcmp(p_index->key,"--keygen")) {
+ command = CMD_KEYGEN;
+ } else if (!strcmp(p_index->key,"--list-fingerprint")) {
command = CMD_LIST_FINGERPRINT;
- } else if (!strcmp(argv[i],"--hash-password")) {
+ } else if (!strcmp(p_index->key, "--hash-password")) {
command = CMD_HASH_PASSWORD;
- command_arg = tor_strdup( (i < argc-1) ? argv[i+1] : "");
- ++i;
- } else if (!strcmp(argv[i],"--verify-config")) {
+ command_arg = p_index->value;
+ } else if (!strcmp(p_index->key, "--dump-config")) {
+ command = CMD_DUMP_CONFIG;
+ command_arg = p_index->value;
+ } else if (!strcmp(p_index->key, "--verify-config")) {
command = CMD_VERIFY_CONFIG;
}
}
@@ -3729,15 +4498,91 @@ options_init_from_torrc(int argc, char **argv)
cf_defaults = tor_strdup("");
cf = tor_strdup("");
} else {
- cf_defaults = load_torrc_from_disk(argc, argv, 1);
- cf = load_torrc_from_disk(argc, argv, 0);
- if (!cf)
- goto err;
+ cf_defaults = load_torrc_from_disk(cmdline_only_options, 1);
+
+ const config_line_t *f_line = config_line_find(cmdline_only_options,
+ "-f");
+
+ const int read_torrc_from_stdin =
+ (f_line != NULL && strcmp(f_line->value, "-") == 0);
+
+ if (read_torrc_from_stdin) {
+ cf = load_torrc_from_stdin();
+ } else {
+ cf = load_torrc_from_disk(cmdline_only_options, 0);
+ }
+
+ if (!cf) {
+ if (config_line_find(cmdline_only_options, "--allow-missing-torrc")) {
+ cf = tor_strdup("");
+ } else {
+ goto err;
+ }
+ }
}
retval = options_init_from_string(cf_defaults, cf, command, command_arg,
&errmsg);
+ if (retval < 0)
+ goto err;
+
+ if (config_line_find(cmdline_only_options, "--no-passphrase")) {
+ if (command == CMD_KEYGEN) {
+ get_options_mutable()->keygen_force_passphrase = FORCE_PASSPHRASE_OFF;
+ } else {
+ log_err(LD_CONFIG, "--no-passphrase specified without --keygen!");
+ exit(1);
+ }
+ }
+
+ if (config_line_find(cmdline_only_options, "--newpass")) {
+ if (command == CMD_KEYGEN) {
+ get_options_mutable()->change_key_passphrase = 1;
+ } else {
+ log_err(LD_CONFIG, "--newpass specified without --keygen!");
+ exit(1);
+ }
+ }
+
+ {
+ const config_line_t *fd_line = config_line_find(cmdline_only_options,
+ "--passphrase-fd");
+ if (fd_line) {
+ if (get_options()->keygen_force_passphrase == FORCE_PASSPHRASE_OFF) {
+ log_err(LD_CONFIG, "--no-passphrase specified with --passphrase-fd!");
+ exit(1);
+ } else if (command != CMD_KEYGEN) {
+ log_err(LD_CONFIG, "--passphrase-fd specified without --keygen!");
+ exit(1);
+ } else {
+ const char *v = fd_line->value;
+ int ok = 1;
+ long fd = tor_parse_long(v, 10, 0, INT_MAX, &ok, NULL);
+ if (fd < 0 || ok == 0) {
+ log_err(LD_CONFIG, "Invalid --passphrase-fd value %s", escaped(v));
+ exit(1);
+ }
+ get_options_mutable()->keygen_passphrase_fd = (int)fd;
+ get_options_mutable()->use_keygen_passphrase_fd = 1;
+ get_options_mutable()->keygen_force_passphrase = FORCE_PASSPHRASE_ON;
+ }
+ }
+ }
+
+ {
+ const config_line_t *key_line = config_line_find(cmdline_only_options,
+ "--master-key");
+ if (key_line) {
+ if (command != CMD_KEYGEN) {
+ log_err(LD_CONFIG, "--master-key without --keygen!");
+ exit(1);
+ } else {
+ get_options_mutable()->master_key_fname = tor_strdup(key_line->value);
+ }
+ }
+ }
+
err:
tor_free(cf);
@@ -3776,7 +4621,7 @@ options_init_from_string(const char *cf_defaults, const char *cf,
newoptions->magic_ = OR_OPTIONS_MAGIC;
options_init(newoptions);
newoptions->command = command;
- newoptions->command_arg = command_arg;
+ newoptions->command_arg = command_arg ? tor_strdup(command_arg) : NULL;
for (i = 0; i < 2; ++i) {
const char *body = i==0 ? cf_defaults : cf;
@@ -3840,7 +4685,7 @@ options_init_from_string(const char *cf_defaults, const char *cf,
newoptions->magic_ = OR_OPTIONS_MAGIC;
options_init(newoptions);
newoptions->command = command;
- newoptions->command_arg = command_arg;
+ newoptions->command_arg = command_arg ? tor_strdup(command_arg) : NULL;
/* Assign all options a second time. */
for (i = 0; i < 2; ++i) {
@@ -3872,7 +4717,8 @@ options_init_from_string(const char *cf_defaults, const char *cf,
}
/* Validate newoptions */
- if (options_validate(oldoptions, newoptions, 0, msg) < 0) {
+ if (options_validate(oldoptions, newoptions, newdefaultoptions,
+ 0, msg) < 0) {
err = SETOPT_ERR_PARSE; /*XXX make this a separate return value.*/
goto err;
}
@@ -3902,7 +4748,7 @@ options_init_from_string(const char *cf_defaults, const char *cf,
return err;
}
-/** Return the location for our configuration file.
+/** Return the location for our configuration file. May return NULL.
*/
const char *
get_torrc_fname(int defaults_fname)
@@ -4009,7 +4855,8 @@ addressmap_register_auto(const char *from, const char *to,
* Initialize the logs based on the configuration file.
*/
static int
-options_init_logs(or_options_t *options, int validate_only)
+options_init_logs(const or_options_t *old_options, or_options_t *options,
+ int validate_only)
{
config_line_t *opt;
int ok;
@@ -4102,7 +4949,21 @@ options_init_logs(or_options_t *options, int validate_only)
!strcasecmp(smartlist_get(elts,0), "file")) {
if (!validate_only) {
char *fname = expand_filename(smartlist_get(elts, 1));
- if (add_file_log(severity, fname) < 0) {
+ /* Truncate if TruncateLogFile is set and we haven't seen this option
+ line before. */
+ int truncate = 0;
+ if (options->TruncateLogFile) {
+ truncate = 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;
+ break;
+ }
+ }
+ }
+ if (add_file_log(severity, fname, truncate) < 0) {
log_warn(LD_CONFIG, "Couldn't open file for 'Log %s': %s",
opt->value, strerror(errno));
ok = 0;
@@ -4129,21 +4990,72 @@ options_init_logs(or_options_t *options, int validate_only)
return ok?0:-1;
}
+/** Given a smartlist of SOCKS arguments to be passed to a transport
+ * proxy in <b>args</b>, validate them and return -1 if they are
+ * corrupted. Return 0 if they seem OK. */
+static int
+validate_transport_socks_arguments(const smartlist_t *args)
+{
+ char *socks_string = NULL;
+ size_t socks_string_len;
+
+ tor_assert(args);
+ tor_assert(smartlist_len(args) > 0);
+
+ SMARTLIST_FOREACH_BEGIN(args, const char *, s) {
+ if (!string_is_key_value(LOG_WARN, s)) { /* items should be k=v items */
+ log_warn(LD_CONFIG, "'%s' is not a k=v item.", s);
+ return -1;
+ }
+ } SMARTLIST_FOREACH_END(s);
+
+ socks_string = pt_stringify_socks_args(args);
+ if (!socks_string)
+ return -1;
+
+ socks_string_len = strlen(socks_string);
+ tor_free(socks_string);
+
+ if (socks_string_len > MAX_SOCKS5_AUTH_SIZE_TOTAL) {
+ log_warn(LD_CONFIG, "SOCKS arguments can't be more than %u bytes (%lu).",
+ MAX_SOCKS5_AUTH_SIZE_TOTAL,
+ (unsigned long) socks_string_len);
+ return -1;
+ }
+
+ return 0;
+}
+
+/** Deallocate a bridge_line_t structure. */
+/* private */ void
+bridge_line_free(bridge_line_t *bridge_line)
+{
+ if (!bridge_line)
+ return;
+
+ if (bridge_line->socks_args) {
+ SMARTLIST_FOREACH(bridge_line->socks_args, char*, s, tor_free(s));
+ smartlist_free(bridge_line->socks_args);
+ }
+ tor_free(bridge_line->transport_name);
+ 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. */
-static int
-parse_bridge_line(const char *line, int validate_only)
+ * the bridge described in the line to our internal bridge list.
+ *
+ * Bridge line format:
+ * Bridge [transport] IP:PORT [id-fingerprint] [k=v] [k=v] ...
+ */
+/* private */ bridge_line_t *
+parse_bridge_line(const char *line)
{
smartlist_t *items = NULL;
- int r;
char *addrport=NULL, *fingerprint=NULL;
- char *transport_name=NULL;
- char *field1=NULL;
- tor_addr_t addr;
- uint16_t port = 0;
- char digest[DIGEST_LEN];
+ char *field=NULL;
+ bridge_line_t *bridge_line = tor_malloc_zero(sizeof(bridge_line_t));
items = smartlist_new();
smartlist_split_string(items, line, NULL,
@@ -4153,107 +5065,143 @@ parse_bridge_line(const char *line, int validate_only)
goto err;
}
- /* field1 is either a transport name or addrport */
- field1 = smartlist_get(items, 0);
+ /* first field is either a transport name or addrport */
+ field = smartlist_get(items, 0);
smartlist_del_keeporder(items, 0);
- if (!(strstr(field1, ".") || strstr(field1, ":"))) {
- /* new-style bridge line */
- transport_name = field1;
+ if (string_is_C_identifier(field)) {
+ /* It's a transport name. */
+ bridge_line->transport_name = field;
if (smartlist_len(items) < 1) {
log_warn(LD_CONFIG, "Too few items to Bridge line.");
goto err;
}
- addrport = smartlist_get(items, 0);
+ addrport = smartlist_get(items, 0); /* Next field is addrport then. */
smartlist_del_keeporder(items, 0);
} else {
- addrport = field1;
+ addrport = field;
}
- if (tor_addr_port_lookup(addrport, &addr, &port)<0) {
+ if (tor_addr_port_parse(LOG_INFO, addrport,
+ &bridge_line->addr, &bridge_line->port, 443)<0) {
log_warn(LD_CONFIG, "Error parsing Bridge address '%s'", addrport);
goto err;
}
- if (!port) {
- log_info(LD_CONFIG,
- "Bridge address '%s' has no port; using default port 443.",
- addrport);
- port = 443;
- }
+ /* If transports are enabled, next field could be a fingerprint or a
+ socks argument. If transports are disabled, next field must be
+ a fingerprint. */
if (smartlist_len(items)) {
- fingerprint = smartlist_join_strings(items, "", 0, NULL);
+ if (bridge_line->transport_name) { /* transports enabled: */
+ field = smartlist_get(items, 0);
+ smartlist_del_keeporder(items, 0);
+
+ /* If it's a key=value pair, then it's a SOCKS argument for the
+ transport proxy... */
+ if (string_is_key_value(LOG_DEBUG, field)) {
+ bridge_line->socks_args = smartlist_new();
+ smartlist_add(bridge_line->socks_args, field);
+ } else { /* ...otherwise, it's the bridge fingerprint. */
+ fingerprint = field;
+ }
+
+ } else { /* transports disabled: */
+ fingerprint = smartlist_join_strings(items, "", 0, NULL);
+ }
+ }
+
+ /* Handle fingerprint, if it was provided. */
+ if (fingerprint) {
if (strlen(fingerprint) != HEX_DIGEST_LEN) {
log_warn(LD_CONFIG, "Key digest for Bridge is wrong length.");
goto err;
}
- if (base16_decode(digest, DIGEST_LEN, fingerprint, HEX_DIGEST_LEN)<0) {
+ if (base16_decode(bridge_line->digest, DIGEST_LEN,
+ fingerprint, HEX_DIGEST_LEN)<0) {
log_warn(LD_CONFIG, "Unable to decode Bridge key digest.");
goto err;
}
}
- if (!validate_only) {
- log_debug(LD_DIR, "Bridge at %s (transport: %s) (%s)",
- fmt_addrport(&addr, port),
- transport_name ? transport_name : "no transport",
- fingerprint ? fingerprint : "no key listed");
- bridge_add_from_config(&addr, port,
- fingerprint ? digest : NULL, transport_name);
+ /* If we are using transports, any remaining items in the smartlist
+ should be k=v values. */
+ if (bridge_line->transport_name && smartlist_len(items)) {
+ if (!bridge_line->socks_args)
+ bridge_line->socks_args = smartlist_new();
+
+ /* append remaining items of 'items' to 'socks_args' */
+ smartlist_add_all(bridge_line->socks_args, items);
+ smartlist_clear(items);
+
+ tor_assert(smartlist_len(bridge_line->socks_args) > 0);
+ }
+
+ if (bridge_line->socks_args) {
+ if (validate_transport_socks_arguments(bridge_line->socks_args) < 0)
+ goto err;
}
- r = 0;
goto done;
err:
- r = -1;
+ bridge_line_free(bridge_line);
+ bridge_line = NULL;
done:
SMARTLIST_FOREACH(items, char*, s, tor_free(s));
smartlist_free(items);
tor_free(addrport);
- tor_free(transport_name);
tor_free(fingerprint);
- return r;
+
+ return bridge_line;
}
-/** Read the contents of a ClientTransportPlugin line from
- * <b>line</b>. Return 0 if the line is well-formed, and -1 if it
- * isn't.
+/** Read the contents of a ClientTransportPlugin or ServerTransportPlugin
+ * line from <b>line</b>, depending on the value of <b>server</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:
+ * If <b>validate_only</b> is 0, the line is well-formed, and the transport is
+ * needed by some bridge:
* - If it's an external proxy line, add the transport described in the line to
* our internal transport list.
- * - If it's a managed proxy line, launch the managed proxy. */
-static int
-parse_client_transport_line(const char *line, int validate_only)
+ * - If it's a managed proxy line, launch the managed proxy.
+ */
+
+STATIC int
+parse_transport_line(const or_options_t *options,
+ const char *line, int validate_only,
+ int server)
{
+
smartlist_t *items = NULL;
int r;
- char *field2=NULL;
-
- const char *transports=NULL;
- smartlist_t *transport_list=NULL;
- char *addrport=NULL;
+ const char *transports = NULL;
+ smartlist_t *transport_list = NULL;
+ char *type = NULL;
+ char *addrport = NULL;
tor_addr_t addr;
uint16_t port = 0;
- int socks_ver=PROXY_NONE;
+ int socks_ver = PROXY_NONE;
/* managed proxy options */
- int is_managed=0;
- char **proxy_argv=NULL;
- char **tmp=NULL;
- int proxy_argc,i;
+ int is_managed = 0;
+ char **proxy_argv = NULL;
+ char **tmp = NULL;
+ int proxy_argc, i;
+ int is_useless_proxy = 1;
int line_length;
+ /* Split the line into space-separated tokens */
items = smartlist_new();
smartlist_split_string(items, line, NULL,
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
+ line_length = smartlist_len(items);
- line_length = smartlist_len(items);
if (line_length < 3) {
- log_warn(LD_CONFIG, "Too few arguments on ClientTransportPlugin line.");
+ log_warn(LD_CONFIG,
+ "Too few arguments on %sTransportPlugin line.",
+ server ? "Server" : "Client");
goto err;
}
@@ -4265,59 +5213,109 @@ parse_client_transport_line(const char *line, int validate_only)
smartlist_split_string(transport_list, transports, ",",
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
SMARTLIST_FOREACH_BEGIN(transport_list, const char *, transport_name) {
+ /* validate transport names */
if (!string_is_C_identifier(transport_name)) {
log_warn(LD_CONFIG, "Transport name is not a C identifier (%s).",
transport_name);
goto err;
}
- } SMARTLIST_FOREACH_END(transport_name);
- /* field2 is either a SOCKS version or "exec" */
- field2 = smartlist_get(items, 1);
+ /* see if we actually need the transports provided by this proxy */
+ if (!validate_only && transport_is_needed(transport_name))
+ is_useless_proxy = 0;
+ } SMARTLIST_FOREACH_END(transport_name);
- if (!strcmp(field2,"socks4")) {
+ type = smartlist_get(items, 1);
+ if (!strcmp(type, "exec")) {
+ is_managed = 1;
+ } else if (server && !strcmp(type, "proxy")) {
+ /* 'proxy' syntax only with ServerTransportPlugin */
+ is_managed = 0;
+ } else if (!server && !strcmp(type, "socks4")) {
+ /* 'socks4' syntax only with ClientTransportPlugin */
+ is_managed = 0;
socks_ver = PROXY_SOCKS4;
- } else if (!strcmp(field2,"socks5")) {
+ } else if (!server && !strcmp(type, "socks5")) {
+ /* 'socks5' syntax only with ClientTransportPlugin */
+ is_managed = 0;
socks_ver = PROXY_SOCKS5;
- } else if (!strcmp(field2,"exec")) {
- is_managed=1;
} else {
- log_warn(LD_CONFIG, "Strange ClientTransportPlugin field '%s'.",
- field2);
+ log_warn(LD_CONFIG,
+ "Strange %sTransportPlugin type '%s'",
+ server ? "Server" : "Client", type);
+ goto err;
+ }
+
+ if (is_managed && options->Sandbox) {
+ log_warn(LD_CONFIG,
+ "Managed proxies are not compatible with Sandbox mode."
+ "(%sTransportPlugin line was %s)",
+ server ? "Server" : "Client", escaped(line));
goto err;
}
- if (is_managed) { /* managed */
- if (!validate_only) { /* if we are not just validating, use the
- rest of the line as the argv of the proxy
- to be launched */
- proxy_argc = line_length-2;
+ if (is_managed) {
+ /* managed */
+
+ if (!server && !validate_only && is_useless_proxy) {
+ log_info(LD_GENERAL,
+ "Pluggable transport proxy (%s) does not provide "
+ "any needed transports and will not be launched.",
+ line);
+ }
+
+ /*
+ * If we are not just validating, use the rest of the line as the
+ * argv of the proxy to be launched. Also, make sure that we are
+ * only launching proxies that contribute useful transports.
+ */
+
+ if (!validate_only && (server || !is_useless_proxy)) {
+ proxy_argc = line_length - 2;
tor_assert(proxy_argc > 0);
- proxy_argv = tor_malloc_zero(sizeof(char*)*(proxy_argc+1));
+ proxy_argv = tor_calloc((proxy_argc + 1), sizeof(char *));
tmp = proxy_argv;
- for (i=0;i<proxy_argc;i++) { /* store arguments */
+
+ for (i = 0; i < proxy_argc; i++) {
+ /* store arguments */
*tmp++ = smartlist_get(items, 2);
smartlist_del_keeporder(items, 2);
}
- *tmp = NULL; /*terminated with NULL, just like execve() likes it*/
+ *tmp = NULL; /* terminated with NULL, just like execve() likes it */
/* kickstart the thing */
- pt_kickstart_client_proxy(transport_list, proxy_argv);
+ if (server) {
+ pt_kickstart_server_proxy(transport_list, proxy_argv);
+ } else {
+ pt_kickstart_client_proxy(transport_list, proxy_argv);
+ }
+ }
+ } else {
+ /* external */
+
+ /* ClientTransportPlugins connecting through a proxy is managed only. */
+ if (!server && (options->Socks4Proxy || options->Socks5Proxy ||
+ options->HTTPSProxy)) {
+ log_warn(LD_CONFIG, "You have configured an external proxy with another "
+ "proxy type. (Socks4Proxy|Socks5Proxy|HTTPSProxy)");
+ goto err;
}
- } else { /* external */
+
if (smartlist_len(transport_list) != 1) {
- log_warn(LD_CONFIG, "You can't have an external proxy with "
- "more than one transports.");
+ log_warn(LD_CONFIG,
+ "You can't have an external proxy with more than "
+ "one transport.");
goto err;
}
addrport = smartlist_get(items, 2);
- if (tor_addr_port_lookup(addrport, &addr, &port)<0) {
- log_warn(LD_CONFIG, "Error parsing transport "
- "address '%s'", addrport);
+ if (tor_addr_port_lookup(addrport, &addr, &port) < 0) {
+ log_warn(LD_CONFIG,
+ "Error parsing transport address '%s'", addrport);
goto err;
}
+
if (!port) {
log_warn(LD_CONFIG,
"Transport address '%s' has no port.", addrport);
@@ -4325,11 +5323,15 @@ parse_client_transport_line(const char *line, int validate_only)
}
if (!validate_only) {
- transport_add_from_config(&addr, port, smartlist_get(transport_list, 0),
- socks_ver);
-
- log_info(LD_DIR, "Transport '%s' found at %s",
+ log_info(LD_DIR, "%s '%s' at %s.",
+ server ? "Server transport" : "Transport",
transports, fmt_addrport(&addr, port));
+
+ if (!server) {
+ transport_add_from_config(&addr, port,
+ smartlist_get(transport_list, 0),
+ socks_ver);
+ }
}
}
@@ -4385,7 +5387,7 @@ get_bindaddr_from_transport_listen_line(const char *line,const char *transport)
goto err;
/* Validate addrport */
- if (tor_addr_port_parse(LOG_WARN, addrport, &addr, &port)<0) {
+ if (tor_addr_port_parse(LOG_WARN, addrport, &addr, &port, -1)<0) {
log_warn(LD_CONFIG, "Error parsing ServerTransportListenAddr "
"address '%s'", addrport);
goto err;
@@ -4404,151 +5406,109 @@ get_bindaddr_from_transport_listen_line(const char *line,const char *transport)
return addrport;
}
-/** Given the name of a pluggable transport in <b>transport</b>, check
- * the configuration file to see if the user has explicitly asked for
- * it to listen on a specific port. Return a <address:port> string if
- * so, otherwise NULL. */
-char *
-get_transport_bindaddr_from_config(const char *transport)
-{
- config_line_t *cl;
- const or_options_t *options = get_options();
-
- for (cl = options->ServerTransportListenAddr; cl; cl = cl->next) {
- char *bindaddr =
- get_bindaddr_from_transport_listen_line(cl->value, transport);
- if (bindaddr)
- return bindaddr;
- }
-
- return NULL;
-}
-
-/** Read the contents of a ServerTransportPlugin 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, the line is well-formed, and it's a
- * managed proxy line, launch the managed proxy. */
-static int
-parse_server_transport_line(const char *line, int validate_only)
+/** Given a ServerTransportOptions <b>line</b>, return a smartlist
+ * with the options. Return NULL if the line was not well-formed.
+ *
+ * If <b>transport</b> is set, return NULL if the line is not
+ * referring to <b>transport</b>.
+ *
+ * The returned smartlist and its strings are allocated on the heap
+ * and it's the responsibility of the caller to free it. */
+smartlist_t *
+get_options_from_transport_options_line(const char *line,const char *transport)
{
- smartlist_t *items = NULL;
- int r;
- const char *transports=NULL;
- smartlist_t *transport_list=NULL;
- char *type=NULL;
- char *addrport=NULL;
- tor_addr_t addr;
- uint16_t port = 0;
-
- /* managed proxy options */
- int is_managed=0;
- char **proxy_argv=NULL;
- char **tmp=NULL;
- int proxy_argc,i;
-
- int line_length;
+ smartlist_t *items = smartlist_new();
+ smartlist_t *options = smartlist_new();
+ const char *parsed_transport = NULL;
- items = smartlist_new();
smartlist_split_string(items, line, NULL,
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
- line_length = smartlist_len(items);
- if (line_length < 3) {
- log_warn(LD_CONFIG, "Too few arguments on ServerTransportPlugin line.");
+ if (smartlist_len(items) < 2) {
+ log_warn(LD_CONFIG,"Too few arguments on ServerTransportOptions line.");
goto err;
}
- /* Get the first line element, split it to commas into
- transport_list (in case it's multiple transports) and validate
- the transport names. */
- transports = smartlist_get(items, 0);
- transport_list = smartlist_new();
- smartlist_split_string(transport_list, transports, ",",
- SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
- SMARTLIST_FOREACH_BEGIN(transport_list, const char *, transport_name) {
- if (!string_is_C_identifier(transport_name)) {
- log_warn(LD_CONFIG, "Transport name is not a C identifier (%s).",
- transport_name);
- goto err;
- }
- } SMARTLIST_FOREACH_END(transport_name);
-
- type = smartlist_get(items, 1);
-
- if (!strcmp(type, "exec")) {
- is_managed=1;
- } else if (!strcmp(type, "proxy")) {
- is_managed=0;
- } else {
- log_warn(LD_CONFIG, "Strange ServerTransportPlugin type '%s'", type);
+ parsed_transport = smartlist_get(items, 0);
+ /* If 'transport' is given, check if it matches the one on the line */
+ if (transport && strcmp(transport, parsed_transport))
goto err;
- }
-
- if (is_managed) { /* managed */
- if (!validate_only) {
- proxy_argc = line_length-2;
- tor_assert(proxy_argc > 0);
- proxy_argv = tor_malloc_zero(sizeof(char*)*(proxy_argc+1));
- tmp = proxy_argv;
-
- for (i=0;i<proxy_argc;i++) { /* store arguments */
- *tmp++ = smartlist_get(items, 2);
- smartlist_del_keeporder(items, 2);
- }
- *tmp = NULL; /*terminated with NULL, just like execve() likes it*/
-
- /* kickstart the thing */
- pt_kickstart_server_proxy(transport_list, proxy_argv);
- }
- } else { /* external */
- if (smartlist_len(transport_list) != 1) {
- log_warn(LD_CONFIG, "You can't have an external proxy with "
- "more than one transports.");
- goto err;
- }
- addrport = smartlist_get(items, 2);
+ SMARTLIST_FOREACH_BEGIN(items, const char *, option) {
+ if (option_sl_idx == 0) /* skip the transport field (first field)*/
+ continue;
- if (tor_addr_port_lookup(addrport, &addr, &port)<0) {
- log_warn(LD_CONFIG, "Error parsing transport "
- "address '%s'", addrport);
- goto err;
- }
- if (!port) {
- log_warn(LD_CONFIG,
- "Transport address '%s' has no port.", addrport);
+ /* validate that it's a k=v value */
+ if (!string_is_key_value(LOG_WARN, option)) {
+ log_warn(LD_CONFIG, "%s is not a k=v value.", escaped(option));
goto err;
}
- if (!validate_only) {
- log_info(LD_DIR, "Server transport '%s' at %s.",
- transports, fmt_addrport(&addr, port));
- }
- }
+ /* add it to the options smartlist */
+ smartlist_add(options, tor_strdup(option));
+ log_debug(LD_CONFIG, "Added %s to the list of options", escaped(option));
+ } SMARTLIST_FOREACH_END(option);
- r = 0;
goto done;
err:
- r = -1;
+ SMARTLIST_FOREACH(options, char*, s, tor_free(s));
+ smartlist_free(options);
+ options = NULL;
done:
SMARTLIST_FOREACH(items, char*, s, tor_free(s));
smartlist_free(items);
- if (transport_list) {
- SMARTLIST_FOREACH(transport_list, char*, s, tor_free(s));
- smartlist_free(transport_list);
+
+ return options;
+}
+
+/** Given the name of a pluggable transport in <b>transport</b>, check
+ * the configuration file to see if the user has explicitly asked for
+ * it to listen on a specific port. Return a <address:port> string if
+ * so, otherwise NULL. */
+char *
+get_transport_bindaddr_from_config(const char *transport)
+{
+ config_line_t *cl;
+ const or_options_t *options = get_options();
+
+ for (cl = options->ServerTransportListenAddr; cl; cl = cl->next) {
+ char *bindaddr =
+ get_bindaddr_from_transport_listen_line(cl->value, transport);
+ if (bindaddr)
+ return bindaddr;
}
- return r;
+ return NULL;
+}
+
+/** Given the name of a pluggable transport in <b>transport</b>, check
+ * the configuration file to see if the user has asked us to pass any
+ * parameters to the pluggable transport. Return a smartlist
+ * containing the parameters, otherwise NULL. */
+smartlist_t *
+get_options_for_server_transport(const char *transport)
+{
+ config_line_t *cl;
+ const or_options_t *options = get_options();
+
+ for (cl = options->ServerTransportOptions; cl; cl = cl->next) {
+ smartlist_t *options_sl =
+ get_options_from_transport_options_line(cl->value, transport);
+ if (options_sl)
+ return options_sl;
+ }
+
+ return NULL;
}
/** Read the contents of a DirAuthority line from <b>line</b>. If
* <b>validate_only</b> is 0, and the line is well-formed, and it
* shares any bits with <b>required_type</b> or <b>required_type</b>
- * is 0, then add the dirserver described in the line (minus whatever
- * bits it's missing) as a valid authority. Return 0 on success,
+ * is NO_DIRINFO (zero), then add the dirserver described in the line
+ * (minus whatever bits it's missing) as a valid authority.
+ * Return 0 on success or filtering out by type,
* or -1 if the line isn't well-formed or if we can't add it. */
static int
parse_dir_authority_line(const char *line, dirinfo_type_t required_type,
@@ -4560,8 +5520,7 @@ parse_dir_authority_line(const char *line, dirinfo_type_t required_type,
uint16_t dir_port = 0, or_port = 0;
char digest[DIGEST_LEN];
char v3_digest[DIGEST_LEN];
- dirinfo_type_t type = V2_DIRINFO;
- int is_not_hidserv_authority = 0, is_not_v2_authority = 0;
+ dirinfo_type_t type = 0;
double weight = 1.0;
items = smartlist_new();
@@ -4581,16 +5540,15 @@ parse_dir_authority_line(const char *line, dirinfo_type_t required_type,
char *flag = smartlist_get(items, 0);
if (TOR_ISDIGIT(flag[0]))
break;
- if (!strcasecmp(flag, "v1")) {
- type |= (V1_DIRINFO | HIDSERV_DIRINFO);
- } else if (!strcasecmp(flag, "hs")) {
- type |= HIDSERV_DIRINFO;
- } else if (!strcasecmp(flag, "no-hs")) {
- is_not_hidserv_authority = 1;
+ if (!strcasecmp(flag, "hs") ||
+ !strcasecmp(flag, "no-hs")) {
+ log_warn(LD_CONFIG, "The DirAuthority options 'hs' and 'no-hs' are "
+ "obsolete; you don't need them any more.");
} else if (!strcasecmp(flag, "bridge")) {
type |= BRIDGE_DIRINFO;
} else if (!strcasecmp(flag, "no-v2")) {
- is_not_v2_authority = 1;
+ /* obsolete, but may still be contained in DirAuthority lines generated
+ by various tools */;
} else if (!strcasecmpstart(flag, "orport=")) {
int ok;
char *portstring = flag + strlen("orport=");
@@ -4622,10 +5580,6 @@ parse_dir_authority_line(const char *line, dirinfo_type_t required_type,
tor_free(flag);
smartlist_del_keeporder(items, 0);
}
- if (is_not_hidserv_authority)
- type &= ~HIDSERV_DIRINFO;
- if (is_not_v2_authority)
- type &= ~V2_DIRINFO;
if (smartlist_len(items) < 2) {
log_warn(LD_CONFIG, "Too few arguments to DirAuthority line.");
@@ -4648,14 +5602,6 @@ parse_dir_authority_line(const char *line, dirinfo_type_t required_type,
fingerprint, (int)strlen(fingerprint));
goto err;
}
- if (!strcmp(fingerprint, "E623F7625FBE0C87820F11EC5F6D5377ED816294")) {
- /* a known bad fingerprint. refuse to use it. We can remove this
- * clause once Tor 0.1.2.17 is obsolete. */
- log_warn(LD_CONFIG, "Dangerous dirserver line. To correct, erase your "
- "torrc file (%s), or reinstall Tor and use the default torrc.",
- get_torrc_fname(0));
- goto err;
- }
if (base16_decode(digest, DIGEST_LEN, fingerprint, HEX_DIGEST_LEN)<0) {
log_warn(LD_CONFIG, "Unable to decode DirAuthority key digest.");
goto err;
@@ -4694,7 +5640,7 @@ parse_dir_authority_line(const char *line, dirinfo_type_t required_type,
* <b>validate_only</b> is 0, and the line is well-formed, then add the
* dirserver described in the line as a fallback directory. Return 0 on
* success, or -1 if the line isn't well-formed or if we can't add it. */
-static int
+int
parse_dir_fallback_line(const char *line,
int validate_only)
{
@@ -4785,12 +5731,13 @@ parse_dir_fallback_line(const char *line,
/** Allocate and return a new port_cfg_t with reasonable defaults. */
static port_cfg_t *
-port_cfg_new(void)
+port_cfg_new(size_t namelen)
{
- port_cfg_t *cfg = tor_malloc_zero(sizeof(port_cfg_t));
- cfg->ipv4_traffic = 1;
- cfg->cache_ipv4_answers = 1;
- cfg->prefer_ipv6_virtaddr = 1;
+ 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.cache_ipv4_answers = 1;
+ cfg->entry_cfg.prefer_ipv6_virtaddr = 1;
return cfg;
}
@@ -4828,12 +5775,33 @@ warn_nonlocal_client_ports(const smartlist_t *ports, const char *portname,
} SMARTLIST_FOREACH_END(port);
}
+/** Warn for every Extended ORPort port in <b>ports</b> that is on a
+ * publicly routable address. */
+static void
+warn_nonlocal_ext_orports(const smartlist_t *ports, const char *portname)
+{
+ SMARTLIST_FOREACH_BEGIN(ports, const port_cfg_t *, port) {
+ if (port->type != CONN_TYPE_EXT_OR_LISTENER)
+ continue;
+ if (port->is_unix_addr)
+ continue;
+ /* XXX maybe warn even if address is RFC1918? */
+ if (!tor_addr_is_internal(&port->addr, 1)) {
+ log_warn(LD_CONFIG, "You specified a public address '%s' for %sPort. "
+ "This is not advised; this address is supposed to only be "
+ "exposed on localhost so that your pluggable transport "
+ "proxies can connect to it.",
+ fmt_addrport(&port->addr, port->port), portname);
+ }
+ } SMARTLIST_FOREACH_END(port);
+}
+
/** Given a list of port_cfg_t in <b>ports</b>, warn any controller port there
- * is listening on any non-loopback address. If <b>forbid</b> is true,
- * then emit a stronger warning and remove the port from the list.
+ * is listening on any non-loopback address. If <b>forbid_nonlocal</b> is
+ * true, then emit a stronger warning and remove the port from the list.
*/
static void
-warn_nonlocal_controller_ports(smartlist_t *ports, unsigned forbid)
+warn_nonlocal_controller_ports(smartlist_t *ports, unsigned forbid_nonlocal)
{
int warned = 0;
SMARTLIST_FOREACH_BEGIN(ports, port_cfg_t *, port) {
@@ -4842,7 +5810,7 @@ warn_nonlocal_controller_ports(smartlist_t *ports, unsigned forbid)
if (port->is_unix_addr)
continue;
if (!tor_addr_is_loopback(&port->addr)) {
- if (forbid) {
+ if (forbid_nonlocal) {
if (!warned)
log_warn(LD_CONFIG,
"You have a ControlPort set to accept "
@@ -4870,12 +5838,63 @@ warn_nonlocal_controller_ports(smartlist_t *ports, unsigned forbid)
} SMARTLIST_FOREACH_END(port);
}
-#define CL_PORT_NO_OPTIONS (1u<<0)
+#define CL_PORT_NO_STREAM_OPTIONS (1u<<0)
#define CL_PORT_WARN_NONLOCAL (1u<<1)
#define CL_PORT_ALLOW_EXTRA_LISTENADDR (1u<<2)
#define CL_PORT_SERVER_OPTIONS (1u<<3)
#define CL_PORT_FORBID_NONLOCAL (1u<<4)
#define CL_PORT_TAKES_HOSTNAMES (1u<<5)
+#define CL_PORT_IS_UNIXSOCKET (1u<<6)
+#define CL_PORT_DFLT_GROUP_WRITABLE (1u<<7)
+
+#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). */
+
+int
+config_parse_unix_port(const char *addrport, char **path_out)
+{
+ tor_assert(path_out);
+ tor_assert(addrport);
+
+ if (strcmpstart(addrport, unix_socket_prefix)) {
+ /* Not a Unix socket path. */
+ return -ENOENT;
+ }
+
+ if (strlen(addrport + strlen(unix_socket_prefix)) == 0) {
+ /* Empty socket path, not very usable. */
+ return -EINVAL;
+ }
+
+ *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)
+{
+ tor_assert(path_out);
+ tor_assert(addrport);
+
+ if (strcmpstart(addrport, unix_socket_prefix)) {
+ /* Not a Unix socket path. */
+ return -ENOENT;
+ }
+
+ 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;
+}
+#endif /* defined(HAVE_SYS_UN_H) */
/**
* Parse port configuration for a single port type.
@@ -4894,12 +5913,12 @@ warn_nonlocal_controller_ports(smartlist_t *ports, unsigned forbid)
* If no address is specified, default to <b>defaultaddr</b>. If no
* FooPort is given, default to defaultport (if 0, there is no default).
*
- * If CL_PORT_NO_OPTIONS is set in <b>flags</b>, do not allow stream
+ * If CL_PORT_NO_STREAM_OPTIONS is set in <b>flags</b>, do not allow stream
* isolation options in the FooPort entries.
*
* If CL_PORT_WARN_NONLOCAL is set in <b>flags</b>, warn if any of the
* ports are not on a local address. If CL_PORT_FORBID_NONLOCAL is set,
- * this is a contrl port with no password set: don't even allow it.
+ * this is a control port with no password set: don't even allow it.
*
* Unless CL_PORT_ALLOW_EXTRA_LISTENADDR is set in <b>flags</b>, warn
* if FooListenAddress is set but FooPort is 0.
@@ -4923,19 +5942,24 @@ parse_port_config(smartlist_t *out,
int listener_type,
const char *defaultaddr,
int defaultport,
- unsigned flags)
+ const unsigned flags)
{
smartlist_t *elts;
int retval = -1;
const unsigned is_control = (listener_type == CONN_TYPE_CONTROL_LISTENER);
- const unsigned allow_no_options = flags & CL_PORT_NO_OPTIONS;
+ const unsigned is_ext_orport = (listener_type == CONN_TYPE_EXT_OR_LISTENER);
+ const unsigned allow_no_stream_options = flags & CL_PORT_NO_STREAM_OPTIONS;
const unsigned use_server_options = flags & CL_PORT_SERVER_OPTIONS;
const unsigned warn_nonlocal = flags & CL_PORT_WARN_NONLOCAL;
const unsigned forbid_nonlocal = flags & CL_PORT_FORBID_NONLOCAL;
+ const unsigned default_to_group_writable =
+ flags & CL_PORT_DFLT_GROUP_WRITABLE;
const unsigned allow_spurious_listenaddr =
flags & CL_PORT_ALLOW_EXTRA_LISTENADDR;
const unsigned takes_hostnames = flags & CL_PORT_TAKES_HOSTNAMES;
+ const unsigned is_unix_socket = flags & CL_PORT_IS_UNIXSOCKET;
int got_zero_port=0, got_nonzero_port=0;
+ char *unix_socket_path = NULL;
/* FooListenAddress is deprecated; let's make it work like it used to work,
* though. */
@@ -4971,14 +5995,14 @@ parse_port_config(smartlist_t *out,
if (use_server_options && out) {
/* Add a no_listen port. */
- port_cfg_t *cfg = port_cfg_new();
+ port_cfg_t *cfg = port_cfg_new(0);
cfg->type = listener_type;
cfg->port = mainport;
tor_addr_make_unspec(&cfg->addr); /* Server ports default to 0.0.0.0 */
- cfg->no_listen = 1;
- cfg->bind_ipv4_only = 1;
- cfg->ipv4_traffic = 1;
- cfg->prefer_ipv6_virtaddr = 1;
+ 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;
smartlist_add(out, cfg);
}
@@ -4991,13 +6015,13 @@ parse_port_config(smartlist_t *out,
return -1;
}
if (out) {
- port_cfg_t *cfg = port_cfg_new();
+ port_cfg_t *cfg = port_cfg_new(0);
cfg->type = listener_type;
cfg->port = port ? port : mainport;
tor_addr_copy(&cfg->addr, &addr);
- cfg->session_group = SESSION_GROUP_UNSET;
- cfg->isolation_flags = ISO_DEFAULT;
- cfg->no_advertise = 1;
+ cfg->entry_cfg.session_group = SESSION_GROUP_UNSET;
+ cfg->entry_cfg.isolation_flags = ISO_DEFAULT;
+ cfg->server_cfg.no_advertise = 1;
smartlist_add(out, cfg);
}
}
@@ -5005,6 +6029,8 @@ parse_port_config(smartlist_t *out,
if (warn_nonlocal && out) {
if (is_control)
warn_nonlocal_controller_ports(out, forbid_nonlocal);
+ else if (is_ext_orport)
+ warn_nonlocal_ext_orports(out, portname);
else
warn_nonlocal_client_ports(out, portname, listener_type);
}
@@ -5014,13 +6040,19 @@ parse_port_config(smartlist_t *out,
/* No ListenAddress lines. If there's no FooPort, then maybe make a default
* one. */
if (! ports) {
- if (defaultport && out) {
- port_cfg_t *cfg = port_cfg_new();
+ if (defaultport && defaultaddr && out) {
+ port_cfg_t *cfg = port_cfg_new(is_unix_socket ? strlen(defaultaddr) : 0);
cfg->type = listener_type;
- cfg->port = defaultport;
- tor_addr_parse(&cfg->addr, defaultaddr);
- cfg->session_group = SESSION_GROUP_UNSET;
- cfg->isolation_flags = ISO_DEFAULT;
+ if (is_unix_socket) {
+ tor_addr_make_unspec(&cfg->addr);
+ memcpy(cfg->unix_addr, defaultaddr, strlen(defaultaddr) + 1);
+ cfg->is_unix_addr = 1;
+ } else {
+ cfg->port = defaultport;
+ tor_addr_parse(&cfg->addr, defaultaddr);
+ }
+ cfg->entry_cfg.session_group = SESSION_GROUP_UNSET;
+ cfg->entry_cfg.isolation_flags = ISO_DEFAULT;
smartlist_add(out, cfg);
}
return 0;
@@ -5032,10 +6064,11 @@ parse_port_config(smartlist_t *out,
for (; ports; ports = ports->next) {
tor_addr_t addr;
- int port;
+ int port, ret;
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;
@@ -5045,7 +6078,7 @@ parse_port_config(smartlist_t *out,
ipv4_traffic = 1, ipv6_traffic = 0, prefer_ipv6 = 0,
cache_ipv4 = 1, use_cached_ipv4 = 0,
cache_ipv6 = 0, use_cached_ipv6 = 0,
- prefer_ipv6_automap = 1;
+ prefer_ipv6_automap = 1, world_writable = 0, group_writable = 0;
smartlist_split_string(elts, ports->value, NULL,
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
@@ -5054,16 +6087,36 @@ parse_port_config(smartlist_t *out,
goto err;
}
- if (allow_no_options && smartlist_len(elts) > 1) {
- log_warn(LD_CONFIG, "Too many options on %sPort line", portname);
+ /* Now parse the addr/port value */
+ addrport = smartlist_get(elts, 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.");
+ }
goto err;
}
- /* Now parse the addr/port value */
- addrport = smartlist_get(elts, 0);
- if (!strcmp(addrport, "auto")) {
+ if (unix_socket_path &&
+ ! conn_listener_type_supports_af_unix(listener_type)) {
+ log_warn(LD_CONFIG, "%sPort does not support unix sockets", portname);
+ goto err;
+ }
+
+ if (unix_socket_path) {
+ port = 1;
+ } else if (is_unix_socket) {
+ unix_socket_path = tor_strdup(addrport);
+ if (!strcmp(addrport, "0"))
+ port = 0;
+ else
+ port = 1;
+ } else if (!strcmp(addrport, "auto")) {
port = CFG_AUTO_PORT;
- tor_addr_parse(&addr, defaultaddr);
+ int af = tor_addr_parse(&addr, defaultaddr);
+ tor_assert(af >= 0);
} else if (!strcasecmpend(addrport, ":auto")) {
char *addrtmp = tor_strndup(addrport, strlen(addrport)-5);
port = CFG_AUTO_PORT;
@@ -5078,7 +6131,8 @@ parse_port_config(smartlist_t *out,
"9050" might be a valid address. */
port = (int) tor_parse_long(addrport, 10, 0, 65535, &ok, NULL);
if (ok) {
- tor_addr_parse(&addr, defaultaddr);
+ int af = tor_addr_parse(&addr, defaultaddr);
+ tor_assert(af >= 0);
} else if (tor_addr_port_lookup(addrport, &addr, &ptmp) == 0) {
if (ptmp == 0) {
log_warn(LD_CONFIG, "%sPort line has address but no port", portname);
@@ -5092,6 +6146,9 @@ parse_port_config(smartlist_t *out,
}
}
+ if (unix_socket_path && default_to_group_writable)
+ group_writable = 1;
+
/* Now parse the rest of the options, if any. */
if (use_server_options) {
/* This is a server port; parse advertising options */
@@ -5148,10 +6205,11 @@ parse_port_config(smartlist_t *out,
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="),
10, 0, INT_MAX, &ok, NULL);
- if (!ok) {
+ if (!ok || !allow_no_stream_options) {
log_warn(LD_CONFIG, "Invalid %sPort option '%s'",
portname, escaped(elt));
goto err;
@@ -5170,6 +6228,20 @@ parse_port_config(smartlist_t *out,
elt += 2;
}
+ if (!strcasecmp(elt, "GroupWritable")) {
+ group_writable = !no;
+ continue;
+ } else if (!strcasecmp(elt, "WorldWritable")) {
+ world_writable = !no;
+ continue;
+ }
+
+ if (allow_no_stream_options) {
+ log_warn(LD_CONFIG, "Unrecognized %sPort option '%s'",
+ portname, escaped(elt));
+ continue;
+ }
+
if (takes_hostnames) {
if (!strcasecmp(elt, "IPv4Traffic")) {
ipv4_traffic = ! no;
@@ -5206,6 +6278,9 @@ parse_port_config(smartlist_t *out,
} else if (!strcasecmp(elt, "PreferSOCKSNoAuth")) {
prefer_no_auth = ! no;
continue;
+ } else if (!strcasecmp(elt, "KeepAliveIsolateSOCKSAuth")) {
+ socks_iso_keep_alive = ! no;
+ continue;
}
if (!strcasecmpend(elt, "s"))
@@ -5245,29 +6320,53 @@ parse_port_config(smartlist_t *out,
goto err;
}
+ if ( (world_writable || group_writable) && ! unix_socket_path) {
+ log_warn(LD_CONFIG, "You have a %sPort entry with GroupWritable "
+ "or WorldWritable set, but it is not a unix socket.", portname);
+ goto err;
+ }
+
+ if (!(isolation & ISO_SOCKSAUTH) && socks_iso_keep_alive) {
+ log_warn(LD_CONFIG, "You have a %sPort entry with both "
+ "NoIsolateSOCKSAuth and KeepAliveIsolateSOCKSAuth set.",
+ portname);
+ goto err;
+ }
+
if (out && port) {
- port_cfg_t *cfg = port_cfg_new();
- tor_addr_copy(&cfg->addr, &addr);
- cfg->port = port;
+ size_t namelen = unix_socket_path ? strlen(unix_socket_path) : 0;
+ port_cfg_t *cfg = port_cfg_new(namelen);
+ if (unix_socket_path) {
+ tor_addr_make_unspec(&cfg->addr);
+ memcpy(cfg->unix_addr, unix_socket_path, namelen + 1);
+ cfg->is_unix_addr = 1;
+ tor_free(unix_socket_path);
+ } else {
+ tor_addr_copy(&cfg->addr, &addr);
+ cfg->port = port;
+ }
cfg->type = listener_type;
- cfg->isolation_flags = isolation;
- cfg->session_group = sessiongroup;
- cfg->no_advertise = no_advertise;
- cfg->no_listen = no_listen;
- cfg->all_addrs = all_addrs;
- cfg->bind_ipv4_only = bind_ipv4_only;
- cfg->bind_ipv6_only = bind_ipv6_only;
- cfg->ipv4_traffic = ipv4_traffic;
- cfg->ipv6_traffic = ipv6_traffic;
- cfg->prefer_ipv6 = prefer_ipv6;
- cfg->cache_ipv4_answers = cache_ipv4;
- cfg->cache_ipv6_answers = cache_ipv6;
- cfg->use_cached_ipv4_answers = use_cached_ipv4;
- cfg->use_cached_ipv6_answers = use_cached_ipv6;
- cfg->prefer_ipv6_virtaddr = prefer_ipv6_automap;
- cfg->socks_prefer_no_auth = prefer_no_auth;
+ cfg->is_world_writable = world_writable;
+ cfg->is_group_writable = group_writable;
+ cfg->entry_cfg.isolation_flags = isolation;
+ cfg->entry_cfg.session_group = sessiongroup;
+ cfg->server_cfg.no_advertise = no_advertise;
+ cfg->server_cfg.no_listen = no_listen;
+ cfg->server_cfg.all_addrs = all_addrs;
+ cfg->server_cfg.bind_ipv4_only = bind_ipv4_only;
+ cfg->server_cfg.bind_ipv6_only = bind_ipv6_only;
+ cfg->entry_cfg.ipv4_traffic = ipv4_traffic;
+ cfg->entry_cfg.ipv6_traffic = ipv6_traffic;
+ cfg->entry_cfg.prefer_ipv6 = prefer_ipv6;
+ 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;
+ cfg->entry_cfg.use_cached_ipv6_answers = use_cached_ipv6;
+ cfg->entry_cfg.prefer_ipv6_virtaddr = prefer_ipv6_automap;
+ cfg->entry_cfg.socks_prefer_no_auth = prefer_no_auth;
if (! (isolation & ISO_SOCKSAUTH))
- cfg->socks_prefer_no_auth = 1;
+ cfg->entry_cfg.socks_prefer_no_auth = 1;
+ cfg->entry_cfg.socks_iso_keep_alive = socks_iso_keep_alive;
smartlist_add(out, cfg);
}
@@ -5278,6 +6377,8 @@ parse_port_config(smartlist_t *out,
if (warn_nonlocal && out) {
if (is_control)
warn_nonlocal_controller_ports(out, forbid_nonlocal);
+ else if (is_ext_orport)
+ warn_nonlocal_ext_orports(out, portname);
else
warn_nonlocal_client_ports(out, portname, listener_type);
}
@@ -5293,32 +6394,10 @@ parse_port_config(smartlist_t *out,
err:
SMARTLIST_FOREACH(elts, char *, cp, tor_free(cp));
smartlist_free(elts);
+ tor_free(unix_socket_path);
return retval;
}
-/** Parse a list of config_line_t for an AF_UNIX unix socket listener option
- * from <b>cfg</b> and add them to <b>out</b>. No fancy options are
- * supported: the line contains nothing but the path to the AF_UNIX socket. */
-static int
-parse_unix_socket_config(smartlist_t *out, const config_line_t *cfg,
- int listener_type)
-{
-
- if (!out)
- return 0;
-
- for ( ; cfg; cfg = cfg->next) {
- size_t len = strlen(cfg->value);
- port_cfg_t *port = tor_malloc_zero(sizeof(port_cfg_t) + len + 1);
- port->is_unix_addr = 1;
- memcpy(port->unix_addr, cfg->value, len+1);
- port->type = listener_type;
- smartlist_add(out, port);
- }
-
- return 0;
-}
-
/** 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. */
@@ -5327,7 +6406,7 @@ count_real_listeners(const smartlist_t *ports, int listenertype)
{
int n = 0;
SMARTLIST_FOREACH_BEGIN(ports, port_cfg_t *, port) {
- if (port->no_listen || port->is_unix_addr)
+ if (port->server_cfg.no_listen || port->is_unix_addr)
continue;
if (port->type != listenertype)
continue;
@@ -5347,7 +6426,8 @@ count_real_listeners(const smartlist_t *ports, int listenertype)
**/
static int
parse_ports(or_options_t *options, int validate_only,
- char **msg, int *n_ports_out)
+ char **msg, int *n_ports_out,
+ int *world_writable_control_socket)
{
smartlist_t *ports;
int retval = -1;
@@ -5356,12 +6436,14 @@ parse_ports(or_options_t *options, int validate_only,
*n_ports_out = 0;
+ const unsigned gw_flag = options->SocksSocketsGroupWritable ?
+ CL_PORT_DFLT_GROUP_WRITABLE : 0;
if (parse_port_config(ports,
options->SocksPort_lines, options->SocksListenAddress,
"Socks", CONN_TYPE_AP_LISTENER,
"127.0.0.1", 9050,
CL_PORT_WARN_NONLOCAL|CL_PORT_ALLOW_EXTRA_LISTENADDR|
- CL_PORT_TAKES_HOSTNAMES) < 0) {
+ CL_PORT_TAKES_HOSTNAMES|gw_flag) < 0) {
*msg = tor_strdup("Invalid SocksPort/SocksListenAddress configuration");
goto err;
}
@@ -5390,12 +6472,15 @@ parse_ports(or_options_t *options, int validate_only,
goto err;
}
{
- unsigned control_port_flags = CL_PORT_NO_OPTIONS | CL_PORT_WARN_NONLOCAL;
+ unsigned control_port_flags = CL_PORT_NO_STREAM_OPTIONS |
+ CL_PORT_WARN_NONLOCAL;
const int any_passwords = (options->HashedControlPassword ||
options->HashedControlSessionPassword ||
options->CookieAuthentication);
if (! any_passwords)
control_port_flags |= CL_PORT_FORBID_NONLOCAL;
+ if (options->ControlSocketsGroupWritable)
+ control_port_flags |= CL_PORT_DFLT_GROUP_WRITABLE;
if (parse_port_config(ports,
options->ControlPort_lines,
@@ -5407,9 +6492,11 @@ parse_ports(or_options_t *options, int validate_only,
"configuration");
goto err;
}
- if (parse_unix_socket_config(ports,
- options->ControlSocket,
- CONN_TYPE_CONTROL_LISTENER) < 0) {
+
+ if (parse_port_config(ports, options->ControlSocket, NULL,
+ "ControlSocket",
+ CONN_TYPE_CONTROL_LISTENER, NULL, 0,
+ control_port_flags | CL_PORT_IS_UNIXSOCKET) < 0) {
*msg = tor_strdup("Invalid ControlSocket configuration");
goto err;
}
@@ -5424,6 +6511,14 @@ parse_ports(or_options_t *options, int validate_only,
goto err;
}
if (parse_port_config(ports,
+ options->ExtORPort_lines, NULL,
+ "ExtOR", CONN_TYPE_EXT_OR_LISTENER,
+ "127.0.0.1", 0,
+ CL_PORT_SERVER_OPTIONS|CL_PORT_WARN_NONLOCAL) < 0) {
+ *msg = tor_strdup("Invalid ExtORPort configuration");
+ goto err;
+ }
+ if (parse_port_config(ports,
options->DirPort_lines, options->DirListenAddress,
"Dir", CONN_TYPE_DIR_LISTENER,
"0.0.0.0", 0,
@@ -5458,6 +6553,18 @@ parse_ports(or_options_t *options, int validate_only,
!! count_real_listeners(ports, CONN_TYPE_DIR_LISTENER);
options->DNSPort_set =
!! count_real_listeners(ports, CONN_TYPE_AP_DNS_LISTENER);
+ options->ExtORPort_set =
+ !! count_real_listeners(ports, CONN_TYPE_EXT_OR_LISTENER);
+
+ if (world_writable_control_socket) {
+ SMARTLIST_FOREACH(ports, port_cfg_t *, p,
+ if (p->type == CONN_TYPE_CONTROL_LISTENER &&
+ p->is_unix_addr &&
+ p->is_world_writable) {
+ *world_writable_control_socket = 1;
+ break;
+ });
+ }
if (!validate_only) {
if (configured_ports) {
@@ -5493,25 +6600,25 @@ check_server_ports(const smartlist_t *ports,
SMARTLIST_FOREACH_BEGIN(ports, const port_cfg_t *, port) {
if (port->type == CONN_TYPE_DIR_LISTENER) {
- if (! port->no_advertise)
+ if (! port->server_cfg.no_advertise)
++n_dirport_advertised;
- if (! port->no_listen)
+ if (! port->server_cfg.no_listen)
++n_dirport_listeners;
} else if (port->type == CONN_TYPE_OR_LISTENER) {
- if (! port->no_advertise) {
+ 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->bind_ipv6_only))
+ !port->server_cfg.bind_ipv6_only))
++n_orport_advertised_ipv4;
}
- if (! port->no_listen)
+ if (! port->server_cfg.no_listen)
++n_orport_listeners;
} else {
continue;
}
#ifndef _WIN32
- if (!port->no_listen && port->port < 1024)
+ if (!port->server_cfg.no_listen && port->port < 1024)
++n_low_port;
#endif
} SMARTLIST_FOREACH_END(port);
@@ -5589,7 +6696,7 @@ get_first_listener_addrport_string(int listener_type)
return NULL;
SMARTLIST_FOREACH_BEGIN(configured_ports, const port_cfg_t *, cfg) {
- if (cfg->no_listen)
+ if (cfg->server_cfg.no_listen)
continue;
if (cfg->type == listener_type &&
@@ -5636,12 +6743,12 @@ get_first_advertised_port_by_type_af(int listener_type, int address_family)
return 0;
SMARTLIST_FOREACH_BEGIN(configured_ports, const port_cfg_t *, cfg) {
if (cfg->type == listener_type &&
- !cfg->no_advertise &&
+ !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->bind_ipv6_only) ||
- (address_family == AF_INET6 && !cfg->bind_ipv4_only)) {
+ (address_family == AF_INET && !cfg->server_cfg.bind_ipv6_only) ||
+ (address_family == AF_INET6 && !cfg->server_cfg.bind_ipv4_only)) {
return cfg->port;
}
}
@@ -5725,10 +6832,13 @@ write_configuration_file(const char *fname, const or_options_t *options)
char *old_val=NULL, *new_val=NULL, *new_conf=NULL;
int rename_old = 0, r;
- tor_assert(fname);
+ if (!fname)
+ return -1;
switch (file_status(fname)) {
+ /* create backups of old config files, even if they're empty */
case FN_FILE:
+ case FN_EMPTY:
old_val = read_file_to_str(fname, 0, NULL);
if (!old_val || strcmpstart(old_val, GENERATED_FILE_PREFIX)) {
rename_old = 1;
@@ -5745,7 +6855,7 @@ write_configuration_file(const char *fname, const or_options_t *options)
return -1;
}
- if (!(new_conf = options_dump(options, 1))) {
+ if (!(new_conf = options_dump(options, OPTIONS_DUMP_MINIMAL))) {
log_warn(LD_BUG, "Couldn't get configuration string");
goto err;
}
@@ -5764,7 +6874,7 @@ write_configuration_file(const char *fname, const or_options_t *options)
++i;
}
log_notice(LD_CONFIG, "Renaming old configuration file to \"%s\"", fn_tmp);
- if (rename(fname, fn_tmp) < 0) {
+ if (tor_rename(fname, fn_tmp) < 0) {//XXXX sandbox doesn't allow
log_warn(LD_FS,
"Couldn't rename configuration file \"%s\" to \"%s\": %s",
fname, fn_tmp, strerror(errno));
@@ -5821,7 +6931,6 @@ get_num_cpus(const or_options_t *options)
static void
init_libevent(const or_options_t *options)
{
- const char *badness=NULL;
tor_libevent_cfg cfg;
tor_assert(options);
@@ -5842,17 +6951,6 @@ init_libevent(const or_options_t *options)
tor_libevent_initialize(&cfg);
suppress_libevent_log_msg(NULL);
-
- tor_check_libevent_version(tor_libevent_get_method(),
- server_mode(get_options()),
- &badness);
- if (badness) {
- const char *v = tor_libevent_get_version_str();
- const char *m = tor_libevent_get_method();
- control_event_general_status(LOG_WARN,
- "BAD_LIBEVENT VERSION=%s METHOD=%s BADNESS=%s RECOVERED=NO",
- v, m, badness);
- }
}
/** Return a newly allocated string holding a filename relative to the data
@@ -5905,6 +7003,43 @@ options_get_datadir_fname2_suffix(const or_options_t *options,
return fname;
}
+/** Check wether the data directory has a private subdirectory
+ * <b>subdir</b>. If not, try to create it. Return 0 on success,
+ * -1 otherwise. */
+int
+check_or_create_data_subdir(const char *subdir)
+{
+ char *statsdir = get_datadir_fname(subdir);
+ int return_val = 0;
+
+ if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0) {
+ log_warn(LD_HIST, "Unable to create %s/ directory!", subdir);
+ return_val = -1;
+ }
+ tor_free(statsdir);
+ return return_val;
+}
+
+/** Create a file named <b>fname</b> with contents <b>str</b> in the
+ * subdirectory <b>subdir</b> of the data directory. <b>descr</b>
+ * should be a short description of the file's content and will be
+ * used for the warning message, if it's present and the write process
+ * fails. Return 0 on success, -1 otherwise.*/
+int
+write_to_data_subdir(const char* subdir, const char* fname,
+ const char* str, const char* descr)
+{
+ char *filename = get_datadir_fname2(subdir, fname);
+ int return_val = 0;
+
+ if (write_str_to_file(filename, str, 0) < 0) {
+ log_warn(LD_HIST, "Unable to write %s to disk!", descr ? descr : fname);
+ return_val = -1;
+ }
+ tor_free(filename);
+ return return_val;
+}
+
/** Given a file name check to see whether the file exists but has not been
* modified for a very long time. If so, remove it. */
void
@@ -5913,12 +7048,17 @@ remove_file_if_very_old(const char *fname, time_t now)
#define VERY_OLD_FILE_AGE (28*24*60*60)
struct stat st;
- if (stat(fname, &st)==0 && st.st_mtime < now-VERY_OLD_FILE_AGE) {
+ log_debug(LD_FS, "stat()ing %s", fname);
+ if (stat(sandbox_intern_string(fname), &st)==0 &&
+ st.st_mtime < now-VERY_OLD_FILE_AGE) {
char buf[ISO_TIME_LEN+1];
format_local_iso_time(buf, st.st_mtime);
log_notice(LD_GENERAL, "Obsolete file %s hasn't been modified since %s. "
"Removing it.", fname, buf);
- unlink(fname);
+ if (unlink(fname) != 0) {
+ log_warn(LD_FS, "Failed to unlink %s: %s",
+ fname, strerror(errno));
+ }
}
}
@@ -5994,6 +7134,7 @@ getinfo_helper_config(control_connection_t *conn,
case CONFIG_TYPE_ISOTIME: type = "Time"; break;
case CONFIG_TYPE_ROUTERSET: type = "RouterList"; break;
case CONFIG_TYPE_CSV: type = "CommaList"; break;
+ case CONFIG_TYPE_CSV_INTERVAL: type = "TimeIntervalCommaList"; break;
case CONFIG_TYPE_LINELIST: type = "LineList"; break;
case CONFIG_TYPE_LINELIST_S: type = "Dependant"; break;
case CONFIG_TYPE_LINELIST_V: type = "Virtual"; break;
@@ -6010,15 +7151,42 @@ getinfo_helper_config(control_connection_t *conn,
smartlist_free(sl);
} else if (!strcmp(question, "config/defaults")) {
smartlist_t *sl = smartlist_new();
- int i;
+ int i, dirauth_lines_seen = 0;
for (i = 0; option_vars_[i].name; ++i) {
const config_var_t *var = &option_vars_[i];
if (var->initvalue != NULL) {
- char *val = esc_for_log(var->initvalue);
- smartlist_add_asprintf(sl, "%s %s\n",var->name,val);
- tor_free(val);
+ if (strcmp(option_vars_[i].name, "DirAuthority") == 0) {
+ /*
+ * Count dirauth lines we have a default for; we'll use the
+ * count later to decide whether to add the defaults manually
+ */
+ ++dirauth_lines_seen;
+ }
+ char *val = esc_for_log(var->initvalue);
+ smartlist_add_asprintf(sl, "%s %s\n",var->name,val);
+ tor_free(val);
+ }
+ }
+
+ if (dirauth_lines_seen == 0) {
+ /*
+ * 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) {
+ char *val = esc_for_log(*i);
+ smartlist_add_asprintf(sl, "DirAuthority %s\n", val);
+ tor_free(val);
}
}
+
*answer = smartlist_join_strings(sl, "", 0, NULL);
SMARTLIST_FOREACH(sl, char *, c, tor_free(c));
smartlist_free(sl);
@@ -6125,3 +7293,71 @@ config_maybe_load_geoip_files_(const or_options_t *options,
config_load_geoip_file_(AF_INET6, options->GeoIPv6File, "geoip6");
}
+/** Initialize cookie authentication (used so far by the ControlPort
+ * and Extended ORPort).
+ *
+ * Allocate memory and create a cookie (of length <b>cookie_len</b>)
+ * in <b>cookie_out</b>.
+ * Then write it down to <b>fname</b> and prepend it with <b>header</b>.
+ *
+ * If <b>group_readable</b> is set, set <b>fname</b> to be readable
+ * by the default GID.
+ *
+ * If the whole procedure was successful, set
+ * <b>cookie_is_set_out</b> to True. */
+int
+init_cookie_authentication(const char *fname, const char *header,
+ int cookie_len, int group_readable,
+ uint8_t **cookie_out, int *cookie_is_set_out)
+{
+ char cookie_file_str_len = strlen(header) + cookie_len;
+ char *cookie_file_str = tor_malloc(cookie_file_str_len);
+ int retval = -1;
+
+ /* We don't want to generate a new cookie every time we call
+ * options_act(). One should be enough. */
+ if (*cookie_is_set_out) {
+ retval = 0; /* we are all set */
+ goto done;
+ }
+
+ /* If we've already set the cookie, free it before re-setting
+ it. This can happen if we previously generated a cookie, but
+ couldn't write it to a disk. */
+ if (*cookie_out)
+ tor_free(*cookie_out);
+
+ /* Generate the cookie */
+ *cookie_out = tor_malloc(cookie_len);
+ if (crypto_rand((char *)*cookie_out, cookie_len) < 0)
+ goto done;
+
+ /* Create the string that should be written on the file. */
+ memcpy(cookie_file_str, header, strlen(header));
+ memcpy(cookie_file_str+strlen(header), *cookie_out, cookie_len);
+ if (write_bytes_to_file(fname, cookie_file_str, cookie_file_str_len, 1)) {
+ log_warn(LD_FS,"Error writing auth cookie to %s.", escaped(fname));
+ goto done;
+ }
+
+#ifndef _WIN32
+ if (group_readable) {
+ if (chmod(fname, 0640)) {
+ log_warn(LD_FS,"Unable to make %s group-readable.", escaped(fname));
+ }
+ }
+#else
+ (void) group_readable;
+#endif
+
+ /* Success! */
+ log_info(LD_GENERAL, "Generated auth cookie file in '%s'.", escaped(fname));
+ *cookie_is_set_out = 1;
+ retval = 0;
+
+ done:
+ memwipe(cookie_file_str, 0, cookie_file_str_len);
+ tor_free(cookie_file_str);
+ return retval;
+}
+