summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--changes/bug124854
-rw-r--r--changes/bug125859
-rw-r--r--changes/bug13111-generate-keys-on-empty-file23
-rw-r--r--changes/bug133974
-rw-r--r--changes/bug134017
-rw-r--r--changes/bug138053
-rw-r--r--changes/bug138068
-rw-r--r--changes/bug14001-clang-warning6
-rw-r--r--changes/bug14067-TestingDirAuthVoteHSDir6
-rw-r--r--changes/bug140904
-rw-r--r--changes/bug141297
-rw-r--r--changes/bug1414111
-rw-r--r--changes/bug14142-parse-virtual-addr7
-rw-r--r--changes/bug141494
-rw-r--r--changes/bug141953
-rw-r--r--changes/bug142073
-rw-r--r--changes/bug142155
-rw-r--r--changes/bug142196
-rw-r--r--changes/bug142204
-rw-r--r--changes/bug142615
-rw-r--r--changes/bug85466
-rw-r--r--changes/remove-bad-fp4
-rw-r--r--changes/ticket130374
-rw-r--r--configure.ac20
-rw-r--r--contrib/dist/tor.service.in20
-rw-r--r--doc/tor.1.txt20
-rw-r--r--src/common/address.c18
-rw-r--r--src/common/compat.c1
-rw-r--r--src/common/compat_libevent.h1
-rw-r--r--src/common/util.c52
-rw-r--r--src/common/util.h4
-rw-r--r--src/or/addressmap.c16
-rw-r--r--src/or/config.c285
-rw-r--r--src/or/connection.c203
-rw-r--r--src/or/connection_edge.c53
-rw-r--r--src/or/control.c8
-rw-r--r--src/or/directory.c9
-rw-r--r--src/or/dirserv.c15
-rw-r--r--src/or/dns.c6
-rw-r--r--src/or/dnsserv.c20
-rw-r--r--src/or/entrynodes.c13
-rw-r--r--src/or/main.c19
-rw-r--r--src/or/or.h179
-rw-r--r--src/or/reasons.c2
-rw-r--r--src/or/relay.c26
-rw-r--r--src/or/rendclient.c14
-rw-r--r--src/or/rendcommon.c135
-rw-r--r--src/or/rendcommon.h4
-rw-r--r--src/or/rendservice.c18
-rw-r--r--src/or/router.c34
-rw-r--r--src/or/routerlist.c1
-rw-r--r--src/or/statefile.c3
-rw-r--r--src/test/include.am4
-rwxr-xr-xsrc/test/test-network.sh2
-rw-r--r--src/test/test_checkdir.c5
-rw-r--r--src/test/test_entryconn.c6
-rw-r--r--src/test/test_relaycell.c12
-rw-r--r--src/test/test_util.c55
-rwxr-xr-xsrc/test/zero_length_keys.sh115
59 files changed, 1094 insertions, 447 deletions
diff --git a/changes/bug12485 b/changes/bug12485
new file mode 100644
index 0000000000..53ce33ef7b
--- /dev/null
+++ b/changes/bug12485
@@ -0,0 +1,4 @@
+ o Minor features (Guard nodes):
+ - Reduce the time delay before saving guard status to disk from 10
+ minute to 30 seconds (or from one hour to 10 minutes if
+ AvoidDiskWrites is set). Closes ticket 12485.
diff --git a/changes/bug12585 b/changes/bug12585
new file mode 100644
index 0000000000..495a2f0d71
--- /dev/null
+++ b/changes/bug12585
@@ -0,0 +1,9 @@
+ o Major features (security)
+ - Implementation of SocksSocket option - SocksSocket implements a SOCKS
+ proxy reachable by Unix Domain Socket. This allows client applications to
+ communicate with Tor without having the ability to create AF_INET or
+ AF_INET6 family sockets. If an application has permission to create a socket
+ with AF_UNIX, it may directly communicate with Tor as if it were an other
+ SOCKS proxy. This should allow high risk applications to be entirely prevented
+ from connecting directly with TCP/IP, they will be able to only connect to the
+ internet through AF_UNIX and only through Tor. Closes ticket 12585.
diff --git a/changes/bug13111-generate-keys-on-empty-file b/changes/bug13111-generate-keys-on-empty-file
new file mode 100644
index 0000000000..20c10c7443
--- /dev/null
+++ b/changes/bug13111-generate-keys-on-empty-file
@@ -0,0 +1,23 @@
+ o Minor bugfixes (file handling):
+ - Stop failing when key files are zero-length. Instead, generate new
+ keys, and overwrite the empty key files.
+ Fixes bug 13111. Patch by "teor".
+ - Stop generating a fresh .old RSA key file when the .old file is missing.
+ - Avoid overwriting .old key files with empty key files.
+ - Stop crashing when a NULL filename is passed to file_status().
+ Fixed as part of bug 13111. Patches by "teor".
+
+ o Minor enhancements (file handling):
+ - Skip loading zero-length extra info store, router store, stats, state,
+ and key files.
+ - Return FN_ERROR when a zero-length filename is passed to file_status().
+ Fixed as part of bug 13111. Patches by "teor".
+
+ o Minor enhancements (testing):
+ - Test that tor does not fail when key files are zero-length.
+ Check that tor generates new keys, and overwrites the empty key files.
+ - Test that tor generates new keys when keys are missing (existing
+ behaviour).
+ - Test that tor does not overwrite key files that already contain data
+ (existing behaviour).
+ Tests bug 13111. Patch by "teor".
diff --git a/changes/bug13397 b/changes/bug13397
new file mode 100644
index 0000000000..502092801f
--- /dev/null
+++ b/changes/bug13397
@@ -0,0 +1,4 @@
+ o Minor bugfixes:
+ - Avoid crashing when trying to reload a torrc specified as a relative
+ path with RunAsDaemon turned on. Fixes bug 13397; bugfix on
+ 0.2.3.11-alpha.
diff --git a/changes/bug13401 b/changes/bug13401
new file mode 100644
index 0000000000..e2834a09d3
--- /dev/null
+++ b/changes/bug13401
@@ -0,0 +1,7 @@
+ o Minor features (testing networks):
+ - Drop the minimum RendPostPeriod on a testing network to 5 seconds,
+ and the default to 2 minutes. Closes ticket 13401. Patch by "nickm".
+ - Drop the MIN_REND_INITIAL_POST_DELAY on a testing network to 5 seconds,
+ but keep the default at 30 seconds. This reduces HS bootstrap time to
+ around 25 seconds. Change src/test/test-network.sh default time to match.
+ Closes ticket 13401. Patch by "teor".
diff --git a/changes/bug13805 b/changes/bug13805
new file mode 100644
index 0000000000..321cd58958
--- /dev/null
+++ b/changes/bug13805
@@ -0,0 +1,3 @@
+ o Minor features (systemd):
+ - Various improvements and modernizations in systemd hardening support.
+ Closes ticket 13805. Patch from Craig Andrews.
diff --git a/changes/bug13806 b/changes/bug13806
new file mode 100644
index 0000000000..0a6b268c02
--- /dev/null
+++ b/changes/bug13806
@@ -0,0 +1,8 @@
+ o Minor features (DOS resistance):
+ - Count the total number of bytes used storing hidden service descriptors
+ against the value of MaxMemInQueues. If we're low on memory, and more
+ than 20% of our memory is used holding hidden service descriptors, free
+ them until no more than 10% of our memory holds hidden service
+ descriptors. Free the least recently fetched descriptors first.
+ Resolves ticket 13806.
+
diff --git a/changes/bug14001-clang-warning b/changes/bug14001-clang-warning
new file mode 100644
index 0000000000..b932af6ab7
--- /dev/null
+++ b/changes/bug14001-clang-warning
@@ -0,0 +1,6 @@
+ o Minor bugfixes:
+ - The address of an array in the middle of a structure will
+ always be non-NULL. clang recognises this and complains.
+ Disable the tautologous and redundant check to silence
+ this warning.
+ Fixes bug 14001.
diff --git a/changes/bug14067-TestingDirAuthVoteHSDir b/changes/bug14067-TestingDirAuthVoteHSDir
new file mode 100644
index 0000000000..52d2bee5e6
--- /dev/null
+++ b/changes/bug14067-TestingDirAuthVoteHSDir
@@ -0,0 +1,6 @@
+ o Minor features (authorities, testing):
+ - Create TestingDirAuthVoteHSDir like TestingDirAuthVoteExit/Guard.
+ Ensures that authorities vote the HSDir flag for the listed
+ relays regardless of uptime or ORPort connectivity.
+ Respects the value of VoteOnHidServDirectoriesV2.
+ Partial fix for bug 14067. Patch by "teor".
diff --git a/changes/bug14090 b/changes/bug14090
new file mode 100644
index 0000000000..d6a6df4860
--- /dev/null
+++ b/changes/bug14090
@@ -0,0 +1,4 @@
+ o Minor bugfixes:
+ - Avoid undefined behavior when sampling huge values from the
+ Laplace distribution. This made unittests fail on Raspberry Pi.
+ Bug found by Device. Fixes bug 14090; bugfix on 0.2.6.2-alpha.
diff --git a/changes/bug14129 b/changes/bug14129
new file mode 100644
index 0000000000..6153cd84fd
--- /dev/null
+++ b/changes/bug14129
@@ -0,0 +1,7 @@
+ o Major bugfixes (exit node stability):
+
+ - Fix an assertion failure that could occur under high DNS load. Fixes
+ bug 14129; bugfix on Tor 0.0.7rc1. Found by "jowr"; diagnosed and fixed
+ by "cypherpunks".
+
+
diff --git a/changes/bug14141 b/changes/bug14141
new file mode 100644
index 0000000000..75cdcd5f3a
--- /dev/null
+++ b/changes/bug14141
@@ -0,0 +1,11 @@
+ o Minor bugfixes (systemd support):
+ - Fix detection and operation of systemd watchdog. Fixes part of
+ bug 14141; bugfix on 0.2.6.2-alpha. Patch from Tomasz Torcz.
+
+ - Run correctly under systemd with the RunAsDaemon option set.
+ Fixes part of bug 14141; bugfix on 0.2.5.7-rc. Patch from Tomasz
+ Torcz.
+
+ o Minor featurs (systemd support):
+ - Inform the systemd supervisor about more changes in the Tor process
+ status. Implements part of ticket 14141. Patch from Tomasz Torcz. \ No newline at end of file
diff --git a/changes/bug14142-parse-virtual-addr b/changes/bug14142-parse-virtual-addr
new file mode 100644
index 0000000000..f78b7c7d81
--- /dev/null
+++ b/changes/bug14142-parse-virtual-addr
@@ -0,0 +1,7 @@
+ o Minor bugfixes (client):
+ - Check for a missing option value in parse_virtual_addr_network
+ before asserting on the NULL in tor_addr_parse_mask_ports.
+ This avoids crashing on torrc lines like
+ Vi[rtualAddrNetworkIPv[4|6]] when no value follows the option.
+ Bugfix on 0.2.3 (de4cc126cbb5 on 24 November 2012), fixes #14142.
+ Patch by "teor".
diff --git a/changes/bug14149 b/changes/bug14149
new file mode 100644
index 0000000000..d655a14354
--- /dev/null
+++ b/changes/bug14149
@@ -0,0 +1,4 @@
+ o Minor features (hidden service parameters):
+ - Make hidden service Sybil attacks harder by changing the minimum
+ time required to become an HSDir from 25 hours up to 96 hours.
+ Addresses ticket #14149. \ No newline at end of file
diff --git a/changes/bug14195 b/changes/bug14195
new file mode 100644
index 0000000000..d2b82f31b0
--- /dev/null
+++ b/changes/bug14195
@@ -0,0 +1,3 @@
+ o Minor bugfixes (client):
+ - Fix a memory leak when using AutomapHostsOnResolve.
+ Fixes bug 14195; bugfix on 0.1.0.1-rc.
diff --git a/changes/bug14207 b/changes/bug14207
new file mode 100644
index 0000000000..987bb25acb
--- /dev/null
+++ b/changes/bug14207
@@ -0,0 +1,3 @@
+ o Minor bugfixes (controller):
+ - Add a code for the END_CIRC_REASON_IP_NOW_REDUNDANT circuit close
+ reason. Fixes bug 12407; bugfix on 0.2.6.2-alpha.
diff --git a/changes/bug14215 b/changes/bug14215
new file mode 100644
index 0000000000..70bcdaaefc
--- /dev/null
+++ b/changes/bug14215
@@ -0,0 +1,5 @@
+ o Minor bugfixes (tests):
+ - Make the checkdir/perms test complete successfully even if the
+ global umask is not 022. Fixes bug 14215; bugfix on 0.2.6.2-alpha.
+
+
diff --git a/changes/bug14219 b/changes/bug14219
new file mode 100644
index 0000000000..9d845db94e
--- /dev/null
+++ b/changes/bug14219
@@ -0,0 +1,6 @@
+ o Minor bugfixes (hidden services):
+
+ - When fetching a hidden service descriptor for a down service that we
+ recently up, do not keep refetching until we try the same replica twice
+ in a row. Fixes bug 14219; bugfix on 0.2.0.10-alpha.
+
diff --git a/changes/bug14220 b/changes/bug14220
new file mode 100644
index 0000000000..51cfa502bc
--- /dev/null
+++ b/changes/bug14220
@@ -0,0 +1,4 @@
+ o Minor bugfixes (compilation):
+ - Build without warnings with the stock OpenSSL srtp.h header,
+ which has a duplicate declaration of SSL_get_selected_srtp_profile().
+ Fixes bug 14220; this is OpenSSL's bug, not ours.
diff --git a/changes/bug14261 b/changes/bug14261
new file mode 100644
index 0000000000..1260ccba1e
--- /dev/null
+++ b/changes/bug14261
@@ -0,0 +1,5 @@
+ O Minor bugfixes (directory authority):
+ - Allow directory authorities to fetch more data from one
+ another if they find themselves missing lots of votes.
+ Previously, they had been bumping against the 10 MB queued
+ data limit. Fixes bug 14261. Bugfix on 0.1.2.5-alpha.
diff --git a/changes/bug8546 b/changes/bug8546
new file mode 100644
index 0000000000..dc6a52a026
--- /dev/null
+++ b/changes/bug8546
@@ -0,0 +1,6 @@
+ o Code simplification and refactoring:
+ - Move fields related to isolating and configuring client ports
+ into a shared structure. Previously, they were duplicated across
+ port_cfg_t, listener_connection_t, and edge_connection_t.
+ Failure to copy one of them correctly had been the cause of at
+ least one bug in the past. \ No newline at end of file
diff --git a/changes/remove-bad-fp b/changes/remove-bad-fp
new file mode 100644
index 0000000000..a07e3ba00c
--- /dev/null
+++ b/changes/remove-bad-fp
@@ -0,0 +1,4 @@
+
+ o Removed features:
+ - Remove a test for a long-defunct broken directory server.
+
diff --git a/changes/ticket13037 b/changes/ticket13037
new file mode 100644
index 0000000000..24c4100454
--- /dev/null
+++ b/changes/ticket13037
@@ -0,0 +1,4 @@
+ o Minor features (build):
+ - New --disable-system-torrc compile-time option to prevent Tor from
+ looking for a system-wide torrc or torrc-defaults tile. Resolves
+ ticket 13037.
diff --git a/configure.ac b/configure.ac
index 1fd5960366..efeea0658e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -45,6 +45,8 @@ AC_ARG_ENABLE(unittests,
AS_HELP_STRING(--disable-unittests, [Don't build unit tests for Tor. Risky!]))
AC_ARG_ENABLE(coverage,
AS_HELP_STRING(--enable-coverage, [Enable coverage support in the unit-test build]))
+AC_ARG_ENABLE(system-torrc,
+ AS_HELP_STRING(--disable-system-torrc, [Don't look for a system-wide torrc file]))
AM_CONDITIONAL(UNITTESTS_ENABLED, test x$enable_unittests != xno)
AM_CONDITIONAL(COVERAGE_ENABLED, test x$enable_coverage = xyes)
@@ -56,6 +58,11 @@ if test "$enable_static_tor" = "yes"; then
CFLAGS="$CFLAGS -static"
fi
+if test "$enable_system_torrc" = "no"; then
+ AC_DEFINE(DISABLE_SYSTEM_TORRC, 1,
+ [Defined if we're not going to look for a torrc in SYSCONF])
+fi
+
if test x$enable_buf_freelists = xyes; then
AC_DEFINE(ENABLE_BUF_FREELISTS, 1,
[Defined if we try to use freelists for buffer RAM chunks])
@@ -126,12 +133,21 @@ else
[libsystemd-daemon],
have_systemd=yes,
have_systemd=no)
+ if test x$have_systemd=xno; then
+ AC_MSG_NOTICE([Okay, checking for systemd a different way...])
+ PKG_CHECK_MODULES(SYSTEMD,
+ [libsystemd],
+ have_systemd=yes,
+ have_systemd=no)
+ fi
fi
if test x$have_systemd = xyes; then
AC_DEFINE(HAVE_SYSTEMD,1,[Have systemd])
TOR_SYSTEMD_CFLAGS="${SYSTEMD_CFLAGS}"
TOR_SYSTEMD_LIBS="${SYSTEMD_LIBS}"
+ PKG_CHECK_MODULES(SYSTEMD209, [systemd >= 209],
+ [AC_DEFINE(HAVE_SYSTEMD_209,1,[Have systemd v209 or more])], [])
fi
AC_SUBST(TOR_SYSTEMD_CFLAGS)
AC_SUBST(TOR_SYSTEMD_LIBS)
@@ -155,10 +171,6 @@ cpu workers lock up here, so I will disable threads.])
esac
fi
-ifdef([HAVE_SYSTEMD], [
-AC_SEARCH_LIBS([sd_watchdog_enabled], [systemd-daemon],
- [AC_DEFINE(HAVE_SYSTEMD_209,1,[Have systemd v209 or more])], [])
-])
case $host in
*-*-solaris* )
diff --git a/contrib/dist/tor.service.in b/contrib/dist/tor.service.in
index 57409a7b0a..c251158d9a 100644
--- a/contrib/dist/tor.service.in
+++ b/contrib/dist/tor.service.in
@@ -3,27 +3,27 @@ Description = Anonymizing overlay network for TCP
After = syslog.target network.target nss-lookup.target
[Service]
-Type = simple
+Type = notify
+NotifyAccess = all
ExecStartPre = @BINDIR@/tor -f @CONFDIR@/torrc --verify-config
-# A torrc that has "RunAsDaemon 1" won't work with the "simple" service type;
-# let's explicitly override it.
-ExecStart = @BINDIR@/tor -f @CONFDIR@/torrc --RunAsDaemon 0
+ExecStart = @BINDIR@/tor -f @CONFDIR@/torrc
ExecReload = /bin/kill -HUP ${MAINPID}
KillSignal = SIGINT
TimeoutSec = 30
Restart = on-failure
+WatchdogSec = 1m
LimitNOFILE = 32768
# Hardening
PrivateTmp = yes
-DeviceAllow = /dev/null rw
-DeviceAllow = /dev/urandom r
-InaccessibleDirectories = /home
+PrivateDevices = yes
+ProtectHome = yes
+ProtectSystem = full
ReadOnlyDirectories = /
-ReadWriteDirectories = @LOCALSTATEDIR@/lib/tor
-ReadWriteDirectories = @LOCALSTATEDIR@/log/tor
-ReadWriteDirectories = @LOCALSTATEDIR@/run/tor
+ReadWriteDirectories = -@LOCALSTATEDIR@/lib/tor
+ReadWriteDirectories = -@LOCALSTATEDIR@/log/tor
NoNewPrivileges = yes
+CapabilityBoundingSet = CAP_SETUID CAP_SETGID CAP_NET_BIND_SERVICE
[Install]
WantedBy = multi-user.target
diff --git a/doc/tor.1.txt b/doc/tor.1.txt
index 9e86a67359..a6f3b6dad4 100644
--- a/doc/tor.1.txt
+++ b/doc/tor.1.txt
@@ -294,7 +294,7 @@ GENERAL OPTIONS
[[ControlSocket]] **ControlSocket** __Path__::
Like ControlPort, but listens on a Unix domain socket, rather than a TCP
- socket. (Unix and Unix-like systems only.)
+ socket. '0' disables ControlSocket (Unix and Unix-like systems only.)
[[ControlSocketsGroupWritable]] **ControlSocketsGroupWritable** **0**|**1**::
If this option is set to 0, don't allow the filesystem group to read and
@@ -483,6 +483,15 @@ GENERAL OPTIONS
in accordance to RFC 1929. Both username and password must be between 1 and
255 characters.
+[[SocksSocket]] **SocksSocket** __Path__::
+ Like SocksPort, but listens on a Unix domain socket, rather than a TCP
+ socket. '0' disables SocksSocket (Unix and Unix-like systems only.)
+
+[[SocksSocketsGroupWritable]] **SocksSocketsGroupWritable** **0**|**1**::
+ If this option is set to 0, don't allow the filesystem group to read and
+ write unix sockets (e.g. SocksSocket). If the option is set to 1, make
+ the SocksSocket socket readable and writable by the default GID. (Default: 0)
+
[[KeepalivePeriod]] **KeepalivePeriod** __NUM__::
To keep firewalls from expiring connections, send a padding keepalive cell
every NUM seconds on open connections that are in use. If the connection
@@ -2245,6 +2254,15 @@ The following options are used for running a testing Tor network.
In order for this option to have any effect, **TestingTorNetwork**
has to be set.
+[[TestingDirAuthVoteHSDir]] **TestingDirAuthVoteHSDir** __node__,__node__,__...__::
+ A list of identity fingerprints and country codes and
+ address patterns of nodes to vote HSDir for regardless of their
+ uptime and ORPort connectivity. See the **ExcludeNodes** option for more
+ information on how to specify nodes.
+ +
+ In order for this option to have any effect, **TestingTorNetwork**
+ and **VoteOnHidServDirectoriesV2** both have to be set.
+
[[TestingEnableConnBwEvent]] **TestingEnableConnBwEvent** **0**|**1**::
If this option is set, then Tor controllers may register for CONN_BW
events. Changing this requires that **TestingTorNetwork** is set.
diff --git a/src/common/address.c b/src/common/address.c
index a80926049a..1c3777fa82 100644
--- a/src/common/address.c
+++ b/src/common/address.c
@@ -121,6 +121,15 @@ tor_addr_to_sockaddr(const tor_addr_t *a,
}
}
+/** Set address <b>a</b> to zero. This address belongs to
+ * the AF_UNIX family. */
+static void
+tor_addr_make_af_unix(tor_addr_t *a)
+{
+ memset(a, 0, sizeof(*a));
+ a->family = AF_UNIX;
+}
+
/** Set the tor_addr_t in <b>a</b> to contain the socket address contained in
* <b>sa</b>. */
int
@@ -142,6 +151,9 @@ tor_addr_from_sockaddr(tor_addr_t *a, const struct sockaddr *sa,
tor_addr_from_in6(a, &sin6->sin6_addr);
if (port_out)
*port_out = ntohs(sin6->sin6_port);
+ } else if (sa->sa_family == AF_UNIX) {
+ tor_addr_make_af_unix(a);
+ return 0;
} else {
tor_addr_make_unspec(a);
return -1;
@@ -421,6 +433,10 @@ tor_addr_to_str(char *dest, const tor_addr_t *addr, size_t len, int decorate)
ptr = dest;
}
break;
+ case AF_UNIX:
+ tor_snprintf(dest, len, "AF_UNIX");
+ ptr = dest;
+ break;
default:
return NULL;
}
@@ -816,6 +832,8 @@ tor_addr_is_null(const tor_addr_t *addr)
}
case AF_INET:
return (tor_addr_to_ipv4n(addr) == 0);
+ case AF_UNIX:
+ return 1;
case AF_UNSPEC:
return 1;
default:
diff --git a/src/common/compat.c b/src/common/compat.c
index 11e2545709..6d36321193 100644
--- a/src/common/compat.c
+++ b/src/common/compat.c
@@ -823,6 +823,7 @@ replace_file(const char *from, const char *to)
case FN_NOENT:
break;
case FN_FILE:
+ case FN_EMPTY:
if (unlink(to)) return -1;
break;
case FN_ERROR:
diff --git a/src/common/compat_libevent.h b/src/common/compat_libevent.h
index 69259e7ed6..6bbfae0056 100644
--- a/src/common/compat_libevent.h
+++ b/src/common/compat_libevent.h
@@ -5,6 +5,7 @@
#define TOR_COMPAT_LIBEVENT_H
#include "orconfig.h"
+#include "testsupport.h"
struct event;
struct event_base;
diff --git a/src/common/util.c b/src/common/util.c
index edd0ae895f..be866a5fe6 100644
--- a/src/common/util.c
+++ b/src/common/util.c
@@ -527,15 +527,25 @@ round_int64_to_next_multiple_of(int64_t number, int64_t divisor)
/** Transform a random value <b>p</b> from the uniform distribution in
* [0.0, 1.0[ into a Laplace distributed value with location parameter
- * <b>mu</b> and scale parameter <b>b</b> in [-Inf, Inf[. */
-double
+ * <b>mu</b> and scale parameter <b>b</b>. Truncate the final result
+ * to be an integer in [INT64_MIN, INT64_MAX]. */
+int64_t
sample_laplace_distribution(double mu, double b, double p)
{
+ double result;
+
tor_assert(p >= 0.0 && p < 1.0);
/* This is the "inverse cumulative distribution function" from:
* http://en.wikipedia.org/wiki/Laplace_distribution */
- return mu - b * (p > 0.5 ? 1.0 : -1.0)
- * tor_mathlog(1.0 - 2.0 * fabs(p - 0.5));
+ result = mu - b * (p > 0.5 ? 1.0 : -1.0)
+ * tor_mathlog(1.0 - 2.0 * fabs(p - 0.5));
+
+ if (result >= INT64_MAX)
+ return INT64_MAX;
+ else if (result <= INT64_MIN)
+ return INT64_MIN;
+ else
+ return (int64_t) result;
}
/** Add random noise between INT64_MIN and INT64_MAX coming from a
@@ -546,10 +556,10 @@ int64_t
add_laplace_noise(int64_t signal, double random, double delta_f,
double epsilon)
{
- /* cast to int64_t intended */
int64_t noise = sample_laplace_distribution(
0.0, /* just add noise, no further signal */
delta_f / epsilon, random);
+
if (noise > 0 && INT64_MAX - noise < signal)
return INT64_MAX;
else if (noise < 0 && INT64_MIN - noise > signal)
@@ -2018,15 +2028,24 @@ clean_name_for_stat(char *name)
#endif
}
-/** Return FN_ERROR if filename can't be read, FN_NOENT if it doesn't
- * exist, FN_FILE if it is a regular file, or FN_DIR if it's a
- * directory. On FN_ERROR, sets errno. */
+/** Return:
+ * FN_ERROR if filename can't be read, is NULL, or is zero-length,
+ * FN_NOENT if it doesn't exist,
+ * FN_FILE if it is a non-empty regular file, or a FIFO on unix-like systems,
+ * FN_EMPTY for zero-byte regular files,
+ * FN_DIR if it's a directory, and
+ * FN_ERROR for any other file type.
+ * On FN_ERROR and FN_NOENT, sets errno. (errno is not set when FN_ERROR
+ * is returned due to an unhandled file type.) */
file_status_t
file_status(const char *fname)
{
struct stat st;
char *f;
int r;
+ if (!fname || strlen(fname) == 0) {
+ return FN_ERROR;
+ }
f = tor_strdup(fname);
clean_name_for_stat(f);
log_debug(LD_FS, "stat()ing %s", f);
@@ -2038,16 +2057,23 @@ file_status(const char *fname)
}
return FN_ERROR;
}
- if (st.st_mode & S_IFDIR)
+ if (st.st_mode & S_IFDIR) {
return FN_DIR;
- else if (st.st_mode & S_IFREG)
- return FN_FILE;
+ } else if (st.st_mode & S_IFREG) {
+ if (st.st_size > 0) {
+ return FN_FILE;
+ } else if (st.st_size == 0) {
+ return FN_EMPTY;
+ } else {
+ return FN_ERROR;
+ }
#ifndef _WIN32
- else if (st.st_mode & S_IFIFO)
+ } else if (st.st_mode & S_IFIFO) {
return FN_FILE;
#endif
- else
+ } else {
return FN_ERROR;
+ }
}
/** Check whether <b>dirname</b> exists and is private. If yes return 0. If
diff --git a/src/common/util.h b/src/common/util.h
index ee40949b61..89c140032a 100644
--- a/src/common/util.h
+++ b/src/common/util.h
@@ -173,7 +173,7 @@ unsigned round_to_next_multiple_of(unsigned number, unsigned divisor);
uint32_t round_uint32_to_next_multiple_of(uint32_t number, uint32_t divisor);
uint64_t round_uint64_to_next_multiple_of(uint64_t number, uint64_t divisor);
int64_t round_int64_to_next_multiple_of(int64_t number, int64_t divisor);
-double sample_laplace_distribution(double mu, double b, double p);
+int64_t sample_laplace_distribution(double mu, double b, double p);
int64_t add_laplace_noise(int64_t signal, double random, double delta_f,
double epsilon);
int n_bits_set_u8(uint8_t v);
@@ -342,7 +342,7 @@ enum stream_status get_string_from_pipe(FILE *stream, char *buf, size_t count);
/** Return values from file_status(); see that function's documentation
* for details. */
-typedef enum { FN_ERROR, FN_NOENT, FN_FILE, FN_DIR } file_status_t;
+typedef enum { FN_ERROR, FN_NOENT, FN_FILE, FN_DIR, FN_EMPTY } file_status_t;
file_status_t file_status(const char *filename);
/** Possible behaviors for check_private_dir() on encountering a nonexistent
diff --git a/src/or/addressmap.c b/src/or/addressmap.c
index ea01894634..9c29fb2acb 100644
--- a/src/or/addressmap.c
+++ b/src/or/addressmap.c
@@ -700,10 +700,10 @@ client_dns_set_addressmap(entry_connection_t *for_conn,
return; /* If address was an IP address already, don't add a mapping. */
if (tor_addr_family(val) == AF_INET) {
- if (! for_conn->cache_ipv4_answers)
+ if (! for_conn->entry_cfg.cache_ipv4_answers)
return;
} else if (tor_addr_family(val) == AF_INET6) {
- if (! for_conn->cache_ipv6_answers)
+ if (! for_conn->entry_cfg.cache_ipv6_answers)
return;
}
@@ -732,8 +732,8 @@ client_dns_set_reverse_addressmap(entry_connection_t *for_conn,
{
tor_addr_t tmp_addr;
sa_family_t f = tor_addr_parse(&tmp_addr, address);
- if ((f == AF_INET && ! for_conn->cache_ipv4_answers) ||
- (f == AF_INET6 && ! for_conn->cache_ipv6_answers))
+ if ((f == AF_INET && ! for_conn->entry_cfg.cache_ipv4_answers) ||
+ (f == AF_INET6 && ! for_conn->entry_cfg.cache_ipv6_answers))
return;
}
tor_asprintf(&s, "REVERSE[%s]", address);
@@ -768,6 +768,12 @@ parse_virtual_addr_network(const char *val, sa_family_t family,
const int max_bits = ipv6 ? 40 : 16;
virtual_addr_conf_t *conf = ipv6 ? &virtaddr_conf_ipv6 : &virtaddr_conf_ipv4;
+ if (!val || val[0] == '\0') {
+ if (msg)
+ tor_asprintf(msg, "Value not present (%s) after VirtualAddressNetwork%s",
+ val?"Empty":"NULL", ipv6?"IPv6":"");
+ return -1;
+ }
if (tor_addr_parse_mask_ports(val, 0, &addr, &bits, NULL, NULL) < 0) {
if (msg)
tor_asprintf(msg, "Error parsing VirtualAddressNetwork%s %s",
@@ -975,7 +981,7 @@ addressmap_register_virtual_address(int type, char *new_address)
!strcasecmp(new_address, ent->new_address)) {
tor_free(new_address);
tor_assert(!vent_needs_to_be_added);
- return tor_strdup(*addrp);
+ return *addrp;
} else {
log_warn(LD_BUG,
"Internal confusion: I thought that '%s' was mapped to by "
diff --git a/src/or/config.c b/src/or/config.c
index 2fa077e146..64bc54b3dd 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -55,6 +55,16 @@
#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;
@@ -190,6 +200,8 @@ static config_var_t option_vars_[] = {
V(ControlPortWriteToFile, FILENAME, NULL),
V(ControlSocket, LINELIST, NULL),
V(ControlSocketsGroupWritable, BOOL, "0"),
+ V(SocksSocket, LINELIST, NULL),
+ V(SocksSocketsGroupWritable, BOOL, "0"),
V(CookieAuthentication, BOOL, "0"),
V(CookieAuthFileGroupReadable, BOOL, "0"),
V(CookieAuthFile, STRING, NULL),
@@ -427,7 +439,7 @@ static config_var_t option_vars_[] = {
VAR("__HashedControlSessionPassword", LINELIST, HashedControlSessionPassword,
NULL),
VAR("__OwningControllerProcess",STRING,OwningControllerProcess, NULL),
- V(MinUptimeHidServDirectoryV2, INTERVAL, "25 hours"),
+ V(MinUptimeHidServDirectoryV2, INTERVAL, "96 hours"),
V(VoteOnHidServDirectoriesV2, BOOL, "1"),
V(TestingServerDownloadSchedule, CSV_INTERVAL, "0, 0, 0, 60, 60, 120, "
"300, 900, 2147483647"),
@@ -448,6 +460,7 @@ static config_var_t option_vars_[] = {
V(TestingCertMaxDownloadTries, UINT, "8"),
V(TestingDirAuthVoteExit, ROUTERSET, NULL),
V(TestingDirAuthVoteGuard, ROUTERSET, NULL),
+ V(TestingDirAuthVoteHSDir, ROUTERSET, NULL),
VAR("___UsingTestNetworkDefaults", BOOL, UsingTestNetworkDefaults_, "0"),
{ NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
@@ -496,6 +509,7 @@ static const config_var_t testing_tor_network_defaults[] = {
V(TestingEnableCellStatsEvent, BOOL, "1"),
V(TestingEnableTbEmptyEvent, BOOL, "1"),
VAR("___UsingTestNetworkDefaults", BOOL, UsingTestNetworkDefaults_, "1"),
+ V(RendPostPeriod, INTERVAL, "2 minutes"),
{ NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
};
@@ -1016,6 +1030,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 "
@@ -1030,6 +1049,20 @@ options_act_reversible(const or_options_t *old_options, char **msg)
}
#endif
+#ifndef HAVE_SYS_UN_H
+ if (options->SocksSocket || options->SocksSocketsGroupWritable) {
+ *msg = tor_strdup("Unix domain sockets (SocksSocket) not supported "
+ "on this OS/with this build.");
+ goto rollback;
+ }
+#else
+ if (options->SocksSocketsGroupWritable && !options->SocksSocket) {
+ *msg = tor_strdup("Setting SocksSocketGroupWritable without setting"
+ "a SocksSocket makes no sense.");
+ goto rollback;
+ }
+#endif
+
if (running_tor) {
int n_ports=0;
/* We need to set the connection limit before we can open the listeners. */
@@ -2492,6 +2525,7 @@ 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
@@ -2616,11 +2650,6 @@ 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. "
@@ -2976,10 +3005,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) {
@@ -4013,7 +4045,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",
@@ -4140,21 +4175,28 @@ find_torrc_filename(config_line_t *cmd_arg,
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
}
}
@@ -4177,16 +4219,20 @@ load_torrc_from_disk(config_line_t *cmd_arg, int defaults_file)
int ignore_missing_torrc = 0;
char **fname_var = defaults_file ? &torrc_defaults_fname : &torrc_fname;
- fname = find_torrc_filename(cmd_arg, 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)
@@ -4475,7 +4521,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)
@@ -5329,14 +5375,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;
@@ -5469,9 +5507,9 @@ static port_cfg_t *
port_cfg_new(void)
{
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;
+ cfg->entry_cfg.ipv4_traffic = 1;
+ cfg->entry_cfg.cache_ipv4_answers = 1;
+ cfg->entry_cfg.prefer_ipv6_virtaddr = 1;
return cfg;
}
@@ -5678,10 +5716,10 @@ parse_port_config(smartlist_t *out,
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);
}
@@ -5698,9 +5736,9 @@ parse_port_config(smartlist_t *out,
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);
}
}
@@ -5724,8 +5762,8 @@ parse_port_config(smartlist_t *out,
cfg->type = listener_type;
cfg->port = defaultport;
tor_addr_parse(&cfg->addr, defaultaddr);
- cfg->session_group = SESSION_GROUP_UNSET;
- cfg->isolation_flags = ISO_DEFAULT;
+ cfg->entry_cfg.session_group = SESSION_GROUP_UNSET;
+ cfg->entry_cfg.isolation_flags = ISO_DEFAULT;
smartlist_add(out, cfg);
}
return 0;
@@ -5955,24 +5993,24 @@ parse_port_config(smartlist_t *out,
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->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;
smartlist_add(out, cfg);
}
@@ -6005,22 +6043,87 @@ parse_port_config(smartlist_t *out,
/** 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. */
+ * supported: the line contains nothing but the path to the AF_UNIX socket.
+ * We support a *Socket 0 syntax to explicitly disable if we enable by
+ * default. To use this, pass a non-NULL list containing the default
+ * paths into this function as the 2nd parameter, and if no config lines at all
+ * are present they will be added to the output list. If the only config line
+ * present is '0' the input list will be unmodified.
+ */
static int
-parse_unix_socket_config(smartlist_t *out, const config_line_t *cfg,
- int listener_type)
+parse_unix_socket_config(smartlist_t *out, smartlist_t *defaults,
+ const config_line_t *cfg, int listener_type)
{
+ /* We can say things like SocksSocket 0 or ControlSocket 0 to explicitly
+ * disable this feature; use this to track if we've seen a disable line
+ */
+
+ int unix_socket_disable = 0;
+ size_t len;
+ smartlist_t *ports_to_add = NULL;
if (!out)
return 0;
+ ports_to_add = smartlist_new();
+
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);
+ if (strcmp(cfg->value, "0") != 0) {
+ /* We have a non-disable; add it */
+ 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;
+ if (listener_type == CONN_TYPE_AP_LISTENER) {
+ /* Some more bits to twiddle for this case
+ *
+ * XXX this should support parsing the same options
+ * parse_port_config() does, and probably that code should be
+ * factored out into a function we can call from here. For
+ * now, some reasonable defaults.
+ */
+
+ port->entry_cfg.ipv4_traffic = 1;
+ port->entry_cfg.ipv6_traffic = 1;
+ port->entry_cfg.cache_ipv4_answers = 0;
+ port->entry_cfg.cache_ipv6_answers = 0;
+ }
+ smartlist_add(ports_to_add, port);
+ } else {
+ /* Keep track that we've seen a disable */
+ unix_socket_disable = 1;
+ }
+ }
+
+ if (unix_socket_disable) {
+ if (smartlist_len(ports_to_add) > 0) {
+ /* We saw a disable line and a path; bad news */
+ SMARTLIST_FOREACH(ports_to_add, port_cfg_t *, port, tor_free(port));
+ smartlist_free(ports_to_add);
+ return -1;
+ }
+ /* else we have a disable and nothing else, so add nothing to out */
+ } else {
+ /* No disable; do we have any ports to add that we parsed? */
+ if (smartlist_len(ports_to_add) > 0) {
+ SMARTLIST_FOREACH_BEGIN(ports_to_add, port_cfg_t *, port) {
+ smartlist_add(out, port);
+ } SMARTLIST_FOREACH_END(port);
+ } else if (defaults != NULL && smartlist_len(defaults) > 0) {
+ /* No, but we have some defaults to copy */
+ SMARTLIST_FOREACH_BEGIN(defaults, const port_cfg_t *, defport) {
+ tor_assert(defport->is_unix_addr);
+ tor_assert(defport->unix_addr);
+ len = sizeof(port_cfg_t) + strlen(defport->unix_addr) + 1;
+ port_cfg_t *port = tor_malloc_zero(len);
+ memcpy(port, defport, len);
+ smartlist_add(out, port);
+ } SMARTLIST_FOREACH_END(defport);
+ }
+
+ /* Free the temporary smartlist we used */
+ smartlist_free(ports_to_add);
}
return 0;
@@ -6034,7 +6137,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;
@@ -6114,12 +6217,19 @@ parse_ports(or_options_t *options, int validate_only,
"configuration");
goto err;
}
- if (parse_unix_socket_config(ports,
+
+ if (parse_unix_socket_config(ports, NULL,
options->ControlSocket,
CONN_TYPE_CONTROL_LISTENER) < 0) {
*msg = tor_strdup("Invalid ControlSocket configuration");
goto err;
}
+ if (parse_unix_socket_config(ports, NULL,
+ options->SocksSocket,
+ CONN_TYPE_AP_LISTENER) < 0) {
+ *msg = tor_strdup("Invalid SocksSocket configuration");
+ goto err;
+ }
}
if (! options->ClientOnly) {
if (parse_port_config(ports,
@@ -6163,6 +6273,8 @@ parse_ports(or_options_t *options, int validate_only,
!! count_real_listeners(ports, CONN_TYPE_OR_LISTENER);
options->SocksPort_set =
!! count_real_listeners(ports, CONN_TYPE_AP_LISTENER);
+ options->SocksSocket_set =
+ !! count_real_listeners(ports, CONN_TYPE_AP_LISTENER);
options->TransPort_set =
!! count_real_listeners(ports, CONN_TYPE_AP_TRANS_LISTENER);
options->NATDPort_set =
@@ -6210,25 +6322,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);
@@ -6306,7 +6418,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 &&
@@ -6353,12 +6465,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;
}
}
@@ -6442,10 +6554,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;
diff --git a/src/or/connection.c b/src/or/connection.c
index c67cc3c111..ccd823131d 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -305,9 +305,11 @@ entry_connection_new(int type, int socket_family)
* in a little while. Otherwise, we're doing this as a linked connection
* of some kind, and we should set it up here based on the socket family */
if (socket_family == AF_INET)
- entry_conn->ipv4_traffic_ok = 1;
+ entry_conn->entry_cfg.ipv4_traffic = 1;
else if (socket_family == AF_INET6)
- entry_conn->ipv6_traffic_ok = 1;
+ entry_conn->entry_cfg.ipv6_traffic = 1;
+ else if (socket_family == AF_UNIX)
+ entry_conn->is_socks_socket = 1;
return entry_conn;
}
@@ -516,9 +518,10 @@ connection_free_(connection_t *conn)
buf_free(conn->outbuf);
} else {
if (conn->socket_family == AF_UNIX) {
- /* For now only control ports can be Unix domain sockets
+ /* For now only control and SOCKS ports can be Unix domain sockets
* and listeners at the same time */
- tor_assert(conn->type == CONN_TYPE_CONTROL_LISTENER);
+ tor_assert(conn->type == CONN_TYPE_CONTROL_LISTENER ||
+ conn->type == CONN_TYPE_AP_LISTENER);
if (unlink(conn->address) < 0 && errno != ENOENT) {
log_warn(LD_NET, "Could not unlink %s: %s", conn->address,
@@ -915,13 +918,57 @@ warn_too_many_conns(void)
}
#ifdef HAVE_SYS_UN_H
+
+#define UNIX_SOCKET_PURPOSE_CONTROL_SOCKET 0
+#define UNIX_SOCKET_PURPOSE_SOCKS_SOCKET 1
+
+/** Check if the purpose isn't one of the ones we know what to do with */
+
+static int
+is_valid_unix_socket_purpose(int purpose)
+{
+ int valid = 0;
+
+ switch (purpose) {
+ case UNIX_SOCKET_PURPOSE_CONTROL_SOCKET:
+ case UNIX_SOCKET_PURPOSE_SOCKS_SOCKET:
+ valid = 1;
+ break;
+ }
+
+ return valid;
+}
+
+/** Return a string description of a unix socket purpose */
+static const char *
+unix_socket_purpose_to_string(int purpose)
+{
+ const char *s = "unknown-purpose socket";
+
+ switch (purpose) {
+ case UNIX_SOCKET_PURPOSE_CONTROL_SOCKET:
+ s = "control socket";
+ break;
+ case UNIX_SOCKET_PURPOSE_SOCKS_SOCKET:
+ s = "SOCKS socket";
+ break;
+ }
+
+ return s;
+}
+
/** Check whether we should be willing to open an AF_UNIX socket in
* <b>path</b>. Return 0 if we should go ahead and -1 if we shouldn't. */
static int
-check_location_for_unix_socket(const or_options_t *options, const char *path)
+check_location_for_unix_socket(const or_options_t *options, const char *path,
+ int purpose)
{
int r = -1;
- char *p = tor_strdup(path);
+ char *p = NULL;
+
+ tor_assert(is_valid_unix_socket_purpose(purpose));
+
+ p = tor_strdup(path);
cpd_check_t flags = CPD_CHECK_MODE_ONLY;
if (get_parent_directory(p)<0 || p[0] != '/') {
log_warn(LD_GENERAL, "Bad unix socket address '%s'. Tor does not support "
@@ -929,18 +976,23 @@ check_location_for_unix_socket(const or_options_t *options, const char *path)
goto done;
}
- if (options->ControlSocketsGroupWritable)
+ if ((purpose == UNIX_SOCKET_PURPOSE_CONTROL_SOCKET &&
+ options->ControlSocketsGroupWritable) ||
+ (purpose == UNIX_SOCKET_PURPOSE_SOCKS_SOCKET &&
+ options->SocksSocketsGroupWritable)) {
flags |= CPD_GROUP_OK;
+ }
if (check_private_dir(p, flags, options->User) < 0) {
char *escpath, *escdir;
escpath = esc_for_log(path);
escdir = esc_for_log(p);
- log_warn(LD_GENERAL, "Before Tor can create a control socket in %s, the "
- "directory %s needs to exist, and to be accessible only by the "
- "user%s account that is running Tor. (On some Unix systems, "
- "anybody who can list a socket can connect to it, so Tor is "
- "being careful.)", escpath, escdir,
+ log_warn(LD_GENERAL, "Before Tor can create a %s in %s, the directory "
+ "%s needs to exist, and to be accessible only by the user%s "
+ "account that is running Tor. (On some Unix systems, anybody "
+ "who can list a socket can connect to it, so Tor is being "
+ "careful.)",
+ unix_socket_purpose_to_string(purpose), escpath, escdir,
options->ControlSocketsGroupWritable ? " and group" : "");
tor_free(escpath);
tor_free(escdir);
@@ -1023,15 +1075,15 @@ connection_listener_new(const struct sockaddr *listensockaddr,
static int global_next_session_group = SESSION_GROUP_FIRST_AUTO;
tor_addr_t addr;
- if (get_n_open_sockets() >= get_options()->ConnLimit_-1) {
+ if (get_n_open_sockets() >= options->ConnLimit_-1) {
warn_too_many_conns();
return NULL;
}
if (listensockaddr->sa_family == AF_INET ||
listensockaddr->sa_family == AF_INET6) {
- int is_tcp = (type != CONN_TYPE_AP_DNS_LISTENER);
- if (is_tcp)
+ int is_stream = (type != CONN_TYPE_AP_DNS_LISTENER);
+ if (is_stream)
start_reading = 1;
tor_addr_from_sockaddr(&addr, listensockaddr, &usePort);
@@ -1040,10 +1092,10 @@ connection_listener_new(const struct sockaddr *listensockaddr,
conn_type_to_string(type), fmt_addrport(&addr, usePort));
s = tor_open_socket_nonblocking(tor_addr_family(&addr),
- is_tcp ? SOCK_STREAM : SOCK_DGRAM,
- is_tcp ? IPPROTO_TCP: IPPROTO_UDP);
+ is_stream ? SOCK_STREAM : SOCK_DGRAM,
+ is_stream ? IPPROTO_TCP: IPPROTO_UDP);
if (!SOCKET_OK(s)) {
- log_warn(LD_NET,"Socket creation failed: %s",
+ log_warn(LD_NET, "Socket creation failed: %s",
tor_socket_strerror(tor_socket_errno(-1)));
goto err;
}
@@ -1100,7 +1152,7 @@ connection_listener_new(const struct sockaddr *listensockaddr,
goto err;
}
- if (is_tcp) {
+ if (is_stream) {
if (tor_listen(s) < 0) {
log_warn(LD_NET, "Could not listen on %s:%u: %s", address, usePort,
tor_socket_strerror(tor_socket_errno(s)));
@@ -1123,15 +1175,25 @@ connection_listener_new(const struct sockaddr *listensockaddr,
tor_addr_from_sockaddr(&addr2, (struct sockaddr*)&ss, &gotPort);
}
#ifdef HAVE_SYS_UN_H
+ /*
+ * AF_UNIX generic setup stuff (this covers both CONN_TYPE_CONTROL_LISTENER
+ * and CONN_TYPE_AP_LISTENER cases)
+ */
} else if (listensockaddr->sa_family == AF_UNIX) {
+ /* We want to start reading for both AF_UNIX cases */
start_reading = 1;
- /* For now only control ports can be Unix domain sockets
+ /* For now only control ports or SOCKS ports can be Unix domain sockets
* and listeners at the same time */
- tor_assert(type == CONN_TYPE_CONTROL_LISTENER);
+ tor_assert(type == CONN_TYPE_CONTROL_LISTENER ||
+ type == CONN_TYPE_AP_LISTENER);
- if (check_location_for_unix_socket(options, address) < 0)
- goto err;
+ if (check_location_for_unix_socket(options, address,
+ (type == CONN_TYPE_CONTROL_LISTENER) ?
+ UNIX_SOCKET_PURPOSE_CONTROL_SOCKET :
+ UNIX_SOCKET_PURPOSE_SOCKS_SOCKET) < 0) {
+ goto err;
+ }
log_notice(LD_NET, "Opening %s on %s",
conn_type_to_string(type), address);
@@ -1143,17 +1205,20 @@ connection_listener_new(const struct sockaddr *listensockaddr,
strerror(errno));
goto err;
}
+
s = tor_open_socket_nonblocking(AF_UNIX, SOCK_STREAM, 0);
if (! SOCKET_OK(s)) {
log_warn(LD_NET,"Socket creation failed: %s.", strerror(errno));
goto err;
}
- if (bind(s, listensockaddr, (socklen_t)sizeof(struct sockaddr_un)) == -1) {
+ if (bind(s, listensockaddr,
+ (socklen_t)sizeof(struct sockaddr_un)) == -1) {
log_warn(LD_NET,"Bind to %s failed: %s.", address,
tor_socket_strerror(tor_socket_errno(s)));
goto err;
}
+
#ifdef HAVE_PWD_H
if (options->User) {
pw = tor_getpwnam(options->User);
@@ -1168,13 +1233,27 @@ connection_listener_new(const struct sockaddr *listensockaddr,
}
}
#endif
- if (options->ControlSocketsGroupWritable) {
+
+ if ((type == CONN_TYPE_CONTROL_LISTENER &&
+ options->ControlSocketsGroupWritable) ||
+ (type == CONN_TYPE_AP_LISTENER &&
+ options->SocksSocketsGroupWritable)) {
/* We need to use chmod; fchmod doesn't work on sockets on all
* platforms. */
if (chmod(address, 0660) < 0) {
log_warn(LD_FS,"Unable to make %s group-writable.", address);
goto err;
}
+ } else if ((type == CONN_TYPE_CONTROL_LISTENER &&
+ !(options->ControlSocketsGroupWritable)) ||
+ (type == CONN_TYPE_AP_LISTENER &&
+ !(options->SocksSocketsGroupWritable))) {
+ /* We need to use chmod; fchmod doesn't work on sockets on all
+ * platforms. */
+ if (chmod(address, 0600) < 0) {
+ log_warn(LD_FS,"Unable to make %s group-writable.", address);
+ goto err;
+ }
}
if (listen(s, SOMAXCONN) < 0) {
@@ -1182,8 +1261,6 @@ connection_listener_new(const struct sockaddr *listensockaddr,
tor_socket_strerror(tor_socket_errno(s)));
goto err;
}
-#else
- (void)options;
#endif /* HAVE_SYS_UN_H */
} else {
log_err(LD_BUG, "Got unexpected address family %d.",
@@ -1200,10 +1277,10 @@ connection_listener_new(const struct sockaddr *listensockaddr,
conn->port = gotPort;
tor_addr_copy(&conn->addr, &addr);
- if (port_cfg->isolation_flags) {
- lis_conn->isolation_flags = port_cfg->isolation_flags;
- if (port_cfg->session_group >= 0) {
- lis_conn->session_group = port_cfg->session_group;
+ if (port_cfg->entry_cfg.isolation_flags) {
+ lis_conn->entry_cfg.isolation_flags = port_cfg->entry_cfg.isolation_flags;
+ if (port_cfg->entry_cfg.session_group >= 0) {
+ lis_conn->entry_cfg.session_group = port_cfg->entry_cfg.session_group;
} else {
/* This can wrap after around INT_MAX listeners are opened. But I don't
* believe that matters, since you would need to open a ridiculous
@@ -1211,23 +1288,17 @@ connection_listener_new(const struct sockaddr *listensockaddr,
* hit this. An OR with a dozen ports open, for example, would have to
* close and re-open its listeners every second for 4 years nonstop.
*/
- lis_conn->session_group = global_next_session_group--;
+ lis_conn->entry_cfg.session_group = global_next_session_group--;
}
}
- if (type == CONN_TYPE_AP_LISTENER) {
- lis_conn->socks_ipv4_traffic = port_cfg->ipv4_traffic;
- lis_conn->socks_ipv6_traffic = port_cfg->ipv6_traffic;
- lis_conn->socks_prefer_ipv6 = port_cfg->prefer_ipv6;
- } else {
- lis_conn->socks_ipv4_traffic = 1;
- lis_conn->socks_ipv6_traffic = 1;
+
+ memcpy(&lis_conn->entry_cfg, &port_cfg->entry_cfg, sizeof(entry_port_cfg_t));
+
+ if (type != CONN_TYPE_AP_LISTENER) {
+ lis_conn->entry_cfg.ipv4_traffic = 1;
+ lis_conn->entry_cfg.ipv6_traffic = 1;
+ lis_conn->entry_cfg.prefer_ipv6 = 0;
}
- lis_conn->cache_ipv4_answers = port_cfg->cache_ipv4_answers;
- lis_conn->cache_ipv6_answers = port_cfg->cache_ipv6_answers;
- lis_conn->use_cached_ipv4_answers = port_cfg->use_cached_ipv4_answers;
- lis_conn->use_cached_ipv6_answers = port_cfg->use_cached_ipv6_answers;
- lis_conn->prefer_ipv6_virtaddr = port_cfg->prefer_ipv6_virtaddr;
- lis_conn->socks_prefer_no_auth = port_cfg->socks_prefer_no_auth;
if (connection_add(conn) < 0) { /* no space, forget it */
log_warn(LD_NET,"connection_add for listener failed. Giving up.");
@@ -1294,6 +1365,8 @@ check_sockaddr(const struct sockaddr *sa, int len, int level)
"Address for new connection has address/port equal to zero.");
ok = 0;
}
+ } else if (sa->sa_family == AF_UNIX) {
+ ok = 1;
} else {
ok = 0;
}
@@ -1378,7 +1451,8 @@ connection_handle_listener_read(connection_t *conn, int new_type)
return 0;
}
- if (conn->socket_family == AF_INET || conn->socket_family == AF_INET6) {
+ if (conn->socket_family == AF_INET || conn->socket_family == AF_INET6 ||
+ (conn->socket_family == AF_UNIX && new_type == CONN_TYPE_AP)) {
tor_addr_t addr;
uint16_t port;
if (check_sockaddr(remote, remotelen, LOG_INFO)<0) {
@@ -1419,18 +1493,21 @@ connection_handle_listener_read(connection_t *conn, int new_type)
newconn->port = port;
newconn->address = tor_dup_addr(&addr);
- if (new_type == CONN_TYPE_AP) {
- TO_ENTRY_CONN(newconn)->socks_request->socks_prefer_no_auth =
- TO_LISTENER_CONN(conn)->socks_prefer_no_auth;
+ if (new_type == CONN_TYPE_AP && conn->socket_family != AF_UNIX) {
+ log_info(LD_NET, "New SOCKS connection opened from %s.",
+ fmt_and_decorate_addr(&addr));
+ }
+ if (new_type == CONN_TYPE_AP && conn->socket_family == AF_UNIX) {
+ newconn->port = 0;
+ newconn->address = tor_strdup(conn->address);
+ log_info(LD_NET, "New SOCKS SocksSocket connection opened");
}
if (new_type == CONN_TYPE_CONTROL) {
log_notice(LD_CONTROL, "New control connection opened from %s.",
fmt_and_decorate_addr(&addr));
}
- } else if (conn->socket_family == AF_UNIX) {
- /* For now only control ports can be Unix domain sockets
- * and listeners at the same time */
+ } else if (conn->socket_family == AF_UNIX && conn->type != CONN_TYPE_AP) {
tor_assert(conn->type == CONN_TYPE_CONTROL_LISTENER);
tor_assert(new_type == CONN_TYPE_CONTROL);
log_notice(LD_CONTROL, "New control connection opened.");
@@ -1485,25 +1562,16 @@ connection_init_accepted_conn(connection_t *conn,
return rv;
break;
case CONN_TYPE_AP:
- TO_ENTRY_CONN(conn)->isolation_flags = listener->isolation_flags;
- TO_ENTRY_CONN(conn)->session_group = listener->session_group;
+ memcpy(&TO_ENTRY_CONN(conn)->entry_cfg, &listener->entry_cfg,
+ sizeof(entry_port_cfg_t));
TO_ENTRY_CONN(conn)->nym_epoch = get_signewnym_epoch();
TO_ENTRY_CONN(conn)->socks_request->listener_type = listener->base_.type;
- TO_ENTRY_CONN(conn)->ipv4_traffic_ok = listener->socks_ipv4_traffic;
- TO_ENTRY_CONN(conn)->ipv6_traffic_ok = listener->socks_ipv6_traffic;
- TO_ENTRY_CONN(conn)->prefer_ipv6_traffic = listener->socks_prefer_ipv6;
- TO_ENTRY_CONN(conn)->cache_ipv4_answers = listener->cache_ipv4_answers;
- TO_ENTRY_CONN(conn)->cache_ipv6_answers = listener->cache_ipv6_answers;
- TO_ENTRY_CONN(conn)->use_cached_ipv4_answers =
- listener->use_cached_ipv4_answers;
- TO_ENTRY_CONN(conn)->use_cached_ipv6_answers =
- listener->use_cached_ipv6_answers;
- TO_ENTRY_CONN(conn)->prefer_ipv6_virtaddr =
- listener->prefer_ipv6_virtaddr;
switch (TO_CONN(listener)->type) {
case CONN_TYPE_AP_LISTENER:
conn->state = AP_CONN_STATE_SOCKS_WAIT;
+ TO_ENTRY_CONN(conn)->socks_request->socks_prefer_no_auth =
+ listener->entry_cfg.socks_prefer_no_auth;
break;
case CONN_TYPE_AP_TRANS_LISTENER:
TO_ENTRY_CONN(conn)->is_transparent_ap = 1;
@@ -2186,7 +2254,7 @@ retry_listener_ports(smartlist_t *old_conns,
(conn->socket_family == AF_UNIX && ! wanted->is_unix_addr))
continue;
- if (wanted->no_listen)
+ if (wanted->server_cfg.no_listen)
continue; /* We don't want to open a listener for this one */
if (wanted->is_unix_addr) {
@@ -2227,7 +2295,7 @@ retry_listener_ports(smartlist_t *old_conns,
connection_t *conn;
int real_port = port->port == CFG_AUTO_PORT ? 0 : port->port;
tor_assert(real_port <= UINT16_MAX);
- if (port->no_listen)
+ if (port->server_cfg.no_listen)
continue;
if (port->is_unix_addr) {
@@ -2392,6 +2460,7 @@ connection_is_rate_limited(connection_t *conn)
return 0; /* Internal connection */
else if (! options->CountPrivateBandwidth &&
(tor_addr_family(&conn->addr) == AF_UNSPEC || /* no address */
+ tor_addr_family(&conn->addr) == AF_UNIX || /* no address */
tor_addr_is_internal(&conn->addr, 0)))
return 0; /* Internal address */
else
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c
index 06d35462ba..13053a3847 100644
--- a/src/or/connection_edge.c
+++ b/src/or/connection_edge.c
@@ -987,9 +987,9 @@ connection_ap_handshake_rewrite(entry_connection_t *conn,
* are allowed to do so. */
int addr_type = RESOLVED_TYPE_IPV4;
if (conn->socks_request->socks_version != 4) {
- if (!conn->ipv4_traffic_ok ||
- (conn->ipv6_traffic_ok && conn->prefer_ipv6_traffic) ||
- conn->prefer_ipv6_virtaddr)
+ if (!conn->entry_cfg.ipv4_traffic ||
+ (conn->entry_cfg.ipv6_traffic && conn->entry_cfg.prefer_ipv6) ||
+ conn->entry_cfg.prefer_ipv6_virtaddr)
addr_type = RESOLVED_TYPE_IPV6;
}
/* Okay, register the target address as automapped, and find the new
@@ -1016,9 +1016,9 @@ connection_ap_handshake_rewrite(entry_connection_t *conn,
* happen too often, since client-side DNS caching is off by default. */
if (socks->command == SOCKS_COMMAND_RESOLVE_PTR) {
unsigned rewrite_flags = 0;
- if (conn->use_cached_ipv4_answers)
+ if (conn->entry_cfg.use_cached_ipv4_answers)
rewrite_flags |= AMR_FLAG_USE_IPV4_DNS;
- if (conn->use_cached_ipv6_answers)
+ if (conn->entry_cfg.use_cached_ipv6_answers)
rewrite_flags |= AMR_FLAG_USE_IPV6_DNS;
if (addressmap_rewrite_reverse(socks->address, sizeof(socks->address),
@@ -1068,9 +1068,9 @@ connection_ap_handshake_rewrite(entry_connection_t *conn,
!out->automap) {
unsigned rewrite_flags = AMR_FLAG_USE_AUTOMAP | AMR_FLAG_USE_TRACKEXIT;
addressmap_entry_source_t exit_source2;
- if (conn->use_cached_ipv4_answers)
+ if (conn->entry_cfg.use_cached_ipv4_answers)
rewrite_flags |= AMR_FLAG_USE_IPV4_DNS;
- if (conn->use_cached_ipv6_answers)
+ if (conn->entry_cfg.use_cached_ipv6_answers)
rewrite_flags |= AMR_FLAG_USE_IPV6_DNS;
if (addressmap_rewrite(socks->address, sizeof(socks->address),
rewrite_flags, &out->map_expires, &exit_source2)) {
@@ -1364,8 +1364,9 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
/* If we reach this point, it's an IPv4 or an IPv6 address. */
sa_family_t family = tor_addr_family(&addr);
- if ((family == AF_INET && ! conn->ipv4_traffic_ok) ||
- (family == AF_INET6 && ! conn->ipv4_traffic_ok)) {
+ /* XXXX bug: the second one should be "ipv6_traffic" */
+ if ((family == AF_INET && ! conn->entry_cfg.ipv4_traffic) ||
+ (family == AF_INET6 && ! conn->entry_cfg.ipv4_traffic)) {
/* You can't do an IPv4 address on a v6-only socks listener,
* or vice versa. */
log_warn(LD_NET, "Rejecting SOCKS request for an IP address "
@@ -1378,7 +1379,7 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
log_warn(LD_NET, "Rejecting SOCKS4 request for an IPv6 address.");
connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY);
return -1;
- } else if (socks->socks_version == 4 && !conn->ipv4_traffic_ok) {
+ } else if (socks->socks_version == 4 && !conn->entry_cfg.ipv4_traffic) {
/* You can't do any kind of Socks4 request when IPv4 is forbidden.
*
* XXX raise this check outside the enclosing block? */
@@ -1389,17 +1390,17 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
} else if (family == AF_INET6) {
/* Tell the exit: we won't accept any ipv4 connection to an IPv6
* address. */
- conn->ipv4_traffic_ok = 0;
+ conn->entry_cfg.ipv4_traffic = 0;
} else if (family == AF_INET) {
/* Tell the exit: we won't accept any ipv6 connection to an IPv4
* address. */
- conn->ipv6_traffic_ok = 0;
+ conn->entry_cfg.ipv6_traffic = 0;
}
}
}
if (socks->socks_version == 4)
- conn->ipv6_traffic_ok = 0;
+ conn->entry_cfg.ipv6_traffic = 0;
/* Still handling CONNECT. Now, check for exit enclaves. (Which we
* don't do on BEGINDIR, or there is a chosen exit.)
@@ -2003,19 +2004,19 @@ connection_ap_get_begincell_flags(entry_connection_t *ap_conn)
return 0;
/* If only IPv4 is supported, no flags */
- if (ap_conn->ipv4_traffic_ok && !ap_conn->ipv6_traffic_ok)
+ if (ap_conn->entry_cfg.ipv4_traffic && !ap_conn->entry_cfg.ipv6_traffic)
return 0;
if (! cpath_layer ||
! cpath_layer->extend_info)
return 0;
- if (!ap_conn->ipv4_traffic_ok)
+ if (!ap_conn->entry_cfg.ipv4_traffic)
flags |= BEGIN_FLAG_IPV4_NOT_OK;
exitnode = node_get_by_id(cpath_layer->extend_info->identity_digest);
- if (ap_conn->ipv6_traffic_ok && exitnode) {
+ if (ap_conn->entry_cfg.ipv6_traffic && exitnode) {
tor_addr_t a;
tor_addr_make_null(&a, AF_INET6);
if (compare_tor_addr_to_node_policy(&a, ap_conn->socks_request->port,
@@ -2030,7 +2031,7 @@ connection_ap_get_begincell_flags(entry_connection_t *ap_conn)
if (flags == BEGIN_FLAG_IPV6_OK) {
/* When IPv4 and IPv6 are both allowed, consider whether to say we
* prefer IPv6. Otherwise there's no point in declaring a preference */
- if (ap_conn->prefer_ipv6_traffic)
+ if (ap_conn->entry_cfg.prefer_ipv6)
flags |= BEGIN_FLAG_IPV6_PREFERRED;
}
@@ -2267,8 +2268,8 @@ connection_ap_make_link(connection_t *partner,
/* Populate isolation fields. */
conn->socks_request->listener_type = CONN_TYPE_DIR_LISTENER;
conn->original_dest_address = tor_strdup(address);
- conn->session_group = session_group;
- conn->isolation_flags = isolation_flags;
+ conn->entry_cfg.session_group = session_group;
+ conn->entry_cfg.isolation_flags = isolation_flags;
base_conn->address = tor_strdup("(Tor_internal)");
tor_addr_make_unspec(&base_conn->addr);
@@ -3124,10 +3125,10 @@ connection_ap_can_use_exit(const entry_connection_t *conn, const node_t *exit)
addr_policy_result_t r;
if (0 == tor_addr_parse(&addr, conn->socks_request->address)) {
addrp = &addr;
- } else if (!conn->ipv4_traffic_ok && conn->ipv6_traffic_ok) {
+ } else if (!conn->entry_cfg.ipv4_traffic && conn->entry_cfg.ipv6_traffic) {
tor_addr_make_null(&addr, AF_INET6);
addrp = &addr;
- } else if (conn->ipv4_traffic_ok && !conn->ipv6_traffic_ok) {
+ } else if (conn->entry_cfg.ipv4_traffic && !conn->entry_cfg.ipv6_traffic) {
tor_addr_make_null(&addr, AF_INET);
addrp = &addr;
}
@@ -3233,7 +3234,7 @@ int
connection_edge_compatible_with_circuit(const entry_connection_t *conn,
const origin_circuit_t *circ)
{
- const uint8_t iso = conn->isolation_flags;
+ const uint8_t iso = conn->entry_cfg.isolation_flags;
const socks_request_t *sr = conn->socks_request;
/* If circ has never been used for an isolated connection, we can
@@ -3282,7 +3283,7 @@ connection_edge_compatible_with_circuit(const entry_connection_t *conn,
if ((iso & ISO_CLIENTADDR) &&
!tor_addr_eq(&ENTRY_TO_CONN(conn)->addr, &circ->client_addr))
return 0;
- if ((iso & ISO_SESSIONGRP) && conn->session_group != circ->session_group)
+ if ((iso & ISO_SESSIONGRP) && conn->entry_cfg.session_group != circ->session_group)
return 0;
if ((iso & ISO_NYM_EPOCH) && conn->nym_epoch != circ->nym_epoch)
return 0;
@@ -3321,7 +3322,7 @@ connection_edge_update_circuit_isolation(const entry_connection_t *conn,
circ->client_proto_type = conn->socks_request->listener_type;
circ->client_proto_socksver = conn->socks_request->socks_version;
tor_addr_copy(&circ->client_addr, &ENTRY_TO_CONN(conn)->addr);
- circ->session_group = conn->session_group;
+ circ->session_group = conn->entry_cfg.session_group;
circ->nym_epoch = conn->nym_epoch;
circ->socks_username = sr->username ?
tor_memdup(sr->username, sr->usernamelen) : NULL;
@@ -3348,7 +3349,7 @@ connection_edge_update_circuit_isolation(const entry_connection_t *conn,
mixed |= ISO_CLIENTPROTO;
if (!tor_addr_eq(&ENTRY_TO_CONN(conn)->addr, &circ->client_addr))
mixed |= ISO_CLIENTADDR;
- if (conn->session_group != circ->session_group)
+ if (conn->entry_cfg.session_group != circ->session_group)
mixed |= ISO_SESSIONGRP;
if (conn->nym_epoch != circ->nym_epoch)
mixed |= ISO_NYM_EPOCH;
@@ -3356,7 +3357,7 @@ connection_edge_update_circuit_isolation(const entry_connection_t *conn,
if (dry_run)
return mixed;
- if ((mixed & conn->isolation_flags) != 0) {
+ if ((mixed & conn->entry_cfg.isolation_flags) != 0) {
log_warn(LD_BUG, "Updating a circuit with seemingly incompatible "
"isolation flags.");
}
diff --git a/src/or/control.c b/src/or/control.c
index 9ff71c9541..00cb4311fb 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -1441,9 +1441,13 @@ getinfo_helper_misc(control_connection_t *conn, const char *question,
} else if (!strcmp(question, "bw-event-cache")) {
*answer = get_bw_samples();
} else if (!strcmp(question, "config-file")) {
- *answer = tor_strdup(get_torrc_fname(0));
+ const char *a = get_torrc_fname(0);
+ if (a)
+ *answer = tor_strdup(a);
} else if (!strcmp(question, "config-defaults-file")) {
- *answer = tor_strdup(get_torrc_fname(1));
+ const char *a = get_torrc_fname(1);
+ if (a)
+ *answer = tor_strdup(a);
} else if (!strcmp(question, "config-text")) {
*answer = options_dump(get_options(), OPTIONS_DUMP_MINIMAL);
} else if (!strcmp(question, "info/names")) {
diff --git a/src/or/directory.c b/src/or/directory.c
index 7b4020080c..4f24f84d9c 100644
--- a/src/or/directory.c
+++ b/src/or/directory.c
@@ -2201,12 +2201,15 @@ connection_dir_reached_eof(dir_connection_t *conn)
*/
#define MAX_DIRECTORY_OBJECT_SIZE (10*(1<<20))
+#define MAX_VOTE_DL_SIZE (MAX_DIRECTORY_OBJECT_SIZE * 5)
+
/** Read handler for directory connections. (That's connections <em>to</em>
* directory servers and connections <em>at</em> directory servers.)
*/
int
connection_dir_process_inbuf(dir_connection_t *conn)
{
+ size_t max_size;
tor_assert(conn);
tor_assert(conn->base_.type == CONN_TYPE_DIR);
@@ -2225,7 +2228,11 @@ connection_dir_process_inbuf(dir_connection_t *conn)
return 0;
}
- if (connection_get_inbuf_len(TO_CONN(conn)) > MAX_DIRECTORY_OBJECT_SIZE) {
+ max_size =
+ (TO_CONN(conn)->purpose == DIR_PURPOSE_FETCH_STATUS_VOTE) ?
+ MAX_VOTE_DL_SIZE : MAX_DIRECTORY_OBJECT_SIZE;
+
+ if (connection_get_inbuf_len(TO_CONN(conn)) > max_size) {
log_warn(LD_HTTP,
"Too much data received from directory connection (%s): "
"denial of service attempt, or you need to upgrade?",
diff --git a/src/or/dirserv.c b/src/or/dirserv.c
index d668749c5b..b694f8af77 100644
--- a/src/or/dirserv.c
+++ b/src/or/dirserv.c
@@ -2113,9 +2113,10 @@ set_routerstatus_from_routerinfo(routerstatus_t *rs,
rs->ipv6_orport = ri->ipv6_orport;
}
- /* Iff we are in a testing network, use TestingDirAuthVoteExit to
- give out Exit flags, and TestingDirAuthVoteGuard to
- give out Guard flags. */
+ /* Iff we are in a testing network, use TestingDirAuthVoteExit,
+ TestingDirAuthVoteGuard, and TestingDirAuthVoteHSDir to
+ give out the Exit, Guard, and HSDir flags, respectively.
+ But don't set the corresponding node flags. */
if (options->TestingTorNetwork) {
if (routerset_contains_routerstatus(options->TestingDirAuthVoteExit,
rs, 0)) {
@@ -2123,9 +2124,15 @@ set_routerstatus_from_routerinfo(routerstatus_t *rs,
}
if (routerset_contains_routerstatus(options->TestingDirAuthVoteGuard,
- rs, 0)) {
+ rs, 0)) {
rs->is_possible_guard = 1;
}
+
+ if (routerset_contains_routerstatus(options->TestingDirAuthVoteHSDir,
+ rs, 0)) {
+ /* TestingDirAuthVoteHSDir respects VoteOnHidServDirectoriesV2 */
+ rs->is_hs_dir = vote_on_hsdirs;
+ }
}
}
diff --git a/src/or/dns.c b/src/or/dns.c
index 129ca395b6..cc4a169422 100644
--- a/src/or/dns.c
+++ b/src/or/dns.c
@@ -558,6 +558,8 @@ purge_expired_resolves(time_t now)
/* Connections should only be pending if they have no socket. */
tor_assert(!SOCKET_OK(pend->conn->base_.s));
pendconn = pend->conn;
+ /* Prevent double-remove */
+ pendconn->base_.state = EXIT_CONN_STATE_RESOLVEFAILED;
if (!pendconn->base_.marked_for_close) {
connection_edge_end(pendconn, END_STREAM_REASON_TIMEOUT);
circuit_detach_stream(circuit_get_by_edge_conn(pendconn), pendconn);
@@ -1133,7 +1135,9 @@ connection_dns_remove(edge_connection_t *conn)
return; /* more are pending */
}
}
- tor_assert(0); /* not reachable unless onlyconn not in pending list */
+ log_warn(LD_BUG, "Connection (fd "TOR_SOCKET_T_FORMAT") was not waiting "
+ "for a resolve of %s, but we tried to remove it.",
+ conn->base_.s, escaped_safe_str(conn->base_.address));
}
}
diff --git a/src/or/dnsserv.c b/src/or/dnsserv.c
index 7b5068199b..f7710908bd 100644
--- a/src/or/dnsserv.c
+++ b/src/or/dnsserv.c
@@ -141,13 +141,13 @@ evdns_server_callback(struct evdns_server_request *req, void *data_)
}
if (q->type == EVDNS_TYPE_A || q->type == EVDNS_QTYPE_ALL) {
- entry_conn->ipv4_traffic_ok = 1;
- entry_conn->ipv6_traffic_ok = 0;
- entry_conn->prefer_ipv6_traffic = 0;
+ entry_conn->entry_cfg.ipv4_traffic = 1;
+ entry_conn->entry_cfg.ipv6_traffic = 0;
+ entry_conn->entry_cfg.prefer_ipv6 = 0;
} else if (q->type == EVDNS_TYPE_AAAA) {
- entry_conn->ipv4_traffic_ok = 0;
- entry_conn->ipv6_traffic_ok = 1;
- entry_conn->prefer_ipv6_traffic = 1;
+ entry_conn->entry_cfg.ipv4_traffic = 0;
+ entry_conn->entry_cfg.ipv6_traffic = 1;
+ entry_conn->entry_cfg.prefer_ipv6 = 1;
}
strlcpy(entry_conn->socks_request->address, q->name,
@@ -155,8 +155,8 @@ evdns_server_callback(struct evdns_server_request *req, void *data_)
entry_conn->socks_request->listener_type = listener->base_.type;
entry_conn->dns_server_request = req;
- entry_conn->isolation_flags = listener->isolation_flags;
- entry_conn->session_group = listener->session_group;
+ entry_conn->entry_cfg.isolation_flags = listener->entry_cfg.isolation_flags;
+ entry_conn->entry_cfg.session_group = listener->entry_cfg.session_group;
entry_conn->nym_epoch = get_signewnym_epoch();
if (connection_add(ENTRY_TO_CONN(entry_conn)) < 0) {
@@ -232,9 +232,9 @@ dnsserv_launch_request(const char *name, int reverse,
entry_conn->socks_request->listener_type = CONN_TYPE_CONTROL_LISTENER;
entry_conn->original_dest_address = tor_strdup(name);
- entry_conn->session_group = SESSION_GROUP_CONTROL_RESOLVE;
+ entry_conn->entry_cfg.session_group = SESSION_GROUP_CONTROL_RESOLVE;
entry_conn->nym_epoch = get_signewnym_epoch();
- entry_conn->isolation_flags = ISO_DEFAULT;
+ entry_conn->entry_cfg.isolation_flags = ISO_DEFAULT;
if (connection_add(TO_CONN(conn))<0) {
log_warn(LD_APP, "Couldn't register dummy connection for RESOLVE request");
diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c
index 968a993999..5b0e342662 100644
--- a/src/or/entrynodes.c
+++ b/src/or/entrynodes.c
@@ -1523,6 +1523,13 @@ entry_guards_parse_state(or_state_t *state, int set, char **msg)
return *msg ? -1 : 0;
}
+/** How long will we let a change in our guard nodes stay un-saved
+ * when we are trying to avoid disk writes? */
+#define SLOW_GUARD_STATE_FLUSH_TIME 600
+/** How long will we let a change in our guard nodes stay un-saved
+ * when we are not trying to avoid disk writes? */
+#define FAST_GUARD_STATE_FLUSH_TIME 30
+
/** Our list of entry guards has changed, or some element of one
* of our entry guards has changed. Write the changes to disk within
* the next few minutes.
@@ -1533,8 +1540,12 @@ entry_guards_changed(void)
time_t when;
entry_guards_dirty = 1;
+ if (get_options()->AvoidDiskWrites)
+ when = time(NULL) + SLOW_GUARD_STATE_FLUSH_TIME;
+ else
+ when = time(NULL) + FAST_GUARD_STATE_FLUSH_TIME;
+
/* or_state_save() will call entry_guards_update_state(). */
- when = get_options()->AvoidDiskWrites ? time(NULL) + 3600 : time(NULL)+600;
or_state_mark_dirty(get_or_state(), when);
}
diff --git a/src/or/main.c b/src/or/main.c
index 9e5a916b16..abf3230c4c 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -391,6 +391,10 @@ connection_remove(connection_t *conn)
(int)conn->s, conn_type_to_string(conn->type),
smartlist_len(connection_array));
+ if (conn->type == CONN_TYPE_AP && conn->socket_family == AF_UNIX) {
+ log_info(LD_NET, "Closing SOCKS SocksSocket connection");
+ }
+
control_event_conn_bandwidth(conn);
tor_assert(conn->conn_array_index >= 0);
@@ -1443,7 +1447,7 @@ run_scheduled_events(time_t now)
if (time_to_clean_caches < now) {
rep_history_clean(now - options->RephistTrackTime);
rend_cache_clean(now);
- rend_cache_clean_v2_descs_as_dir(now);
+ rend_cache_clean_v2_descs_as_dir(now, 0);
microdesc_cache_rebuild(NULL, 0);
#define CLEAN_CACHES_INTERVAL (30*60)
time_to_clean_caches = now + CLEAN_CACHES_INTERVAL;
@@ -1776,7 +1780,9 @@ static periodic_timer_t *systemd_watchdog_timer = NULL;
static void
systemd_watchdog_callback(periodic_timer_t *timer, void *arg)
{
- sd_notify(1, "WATCHDOG=1");
+ (void)timer;
+ (void)arg;
+ sd_notify(0, "WATCHDOG=1");
}
#endif
@@ -2169,6 +2175,9 @@ process_signal(uintptr_t sig)
tor_cleanup();
exit(0);
}
+#ifdef HAVE_SYSTEMD
+ sd_notify(0, "STOPPING=1");
+#endif
hibernate_begin_shutdown();
break;
#ifdef SIGPIPE
@@ -2188,11 +2197,17 @@ process_signal(uintptr_t sig)
control_event_signal(sig);
break;
case SIGHUP:
+#ifdef HAVE_SYSTEMD
+ sd_notify(0, "RELOADING=1");
+#endif
if (do_hup() < 0) {
log_warn(LD_CONFIG,"Restart failed (config error?). Exiting.");
tor_cleanup();
exit(1);
}
+#ifdef HAVE_SYSTEMD
+ sd_notify(0, "READY=1");
+#endif
control_event_signal(sig);
break;
#ifdef SIGCHLD
diff --git a/src/or/or.h b/src/or/or.h
index 58e2164665..f821d0b405 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -1143,6 +1143,51 @@ typedef struct socks_request_t socks_request_t;
#define generic_buffer_t buf_t
#endif
+typedef struct entry_port_cfg_t {
+ /* Client port types (socks, dns, trans, natd) only: */
+ uint8_t isolation_flags; /**< Zero or more isolation flags */
+ int session_group; /**< A session group, or -1 if this port is not in a
+ * session group. */
+
+ /* Socks only: */
+ /** When both no-auth and user/pass are advertised by a SOCKS client, select
+ * no-auth. */
+ unsigned int socks_prefer_no_auth : 1;
+
+ /* Client port types only: */
+ unsigned int ipv4_traffic : 1;
+ unsigned int ipv6_traffic : 1;
+ unsigned int prefer_ipv6 : 1;
+
+ /** For a socks listener: should we cache IPv4/IPv6 DNS information that
+ * exit nodes tell us?
+ *
+ * @{ */
+ unsigned int cache_ipv4_answers : 1;
+ unsigned int cache_ipv6_answers : 1;
+ /** @} */
+ /** For a socks listeners: if we find an answer in our client-side DNS cache,
+ * should we use it?
+ *
+ * @{ */
+ unsigned int use_cached_ipv4_answers : 1;
+ unsigned int use_cached_ipv6_answers : 1;
+ /** @} */
+ /** For socks listeners: When we can automap an address to IPv4 or IPv6,
+ * do we prefer IPv6? */
+ unsigned int prefer_ipv6_virtaddr : 1;
+
+} entry_port_cfg_t;
+
+typedef struct server_port_cfg_t {
+ /* Server port types (or, dir) only: */
+ unsigned int no_advertise : 1;
+ unsigned int no_listen : 1;
+ unsigned int all_addrs : 1;
+ unsigned int bind_ipv4_only : 1;
+ unsigned int bind_ipv6_only : 1;
+} server_port_cfg_t;
+
/* Values for connection_t.magic: used to make sure that downcasts (casts from
* connection_t to foo_connection_t) are safe. */
#define BASE_CONNECTION_MAGIC 0x7C3C304Eu
@@ -1278,52 +1323,7 @@ typedef struct listener_connection_t {
* to the evdns_server_port it uses to listen to and answer connections. */
struct evdns_server_port *dns_server_port;
- /** @name Isolation parameters
- *
- * For an AP listener, these fields describe how to isolate streams that
- * arrive on the listener.
- *
- * @{
- */
- /** The session group for this listener. */
- int session_group;
- /** One or more ISO_ flags to describe how to isolate streams. */
- uint8_t isolation_flags;
- /**@}*/
- /** For SOCKS connections only: If this is set, we will choose "no
- * authentication" instead of "username/password" authentication if both
- * are offered. Used as input to parse_socks. */
- unsigned int socks_prefer_no_auth : 1;
-
- /** For a SOCKS listeners, these fields describe whether we should
- * allow IPv4 and IPv6 addresses from our exit nodes, respectively.
- *
- * @{
- */
- unsigned int socks_ipv4_traffic : 1;
- unsigned int socks_ipv6_traffic : 1;
- /** @} */
- /** For a socks listener: should we tell the exit that we prefer IPv6
- * addresses? */
- unsigned int socks_prefer_ipv6 : 1;
-
- /** For a socks listener: should we cache IPv4/IPv6 DNS information that
- * exit nodes tell us?
- *
- * @{ */
- unsigned int cache_ipv4_answers : 1;
- unsigned int cache_ipv6_answers : 1;
- /** @} */
- /** For a socks listeners: if we find an answer in our client-side DNS cache,
- * should we use it?
- *
- * @{ */
- unsigned int use_cached_ipv4_answers : 1;
- unsigned int use_cached_ipv6_answers : 1;
- /** @} */
- /** For socks listeners: When we can automap an address to IPv4 or IPv6,
- * do we prefer IPv6? */
- unsigned int prefer_ipv6_virtaddr : 1;
+ entry_port_cfg_t entry_cfg;
} listener_connection_t;
@@ -1611,12 +1611,10 @@ typedef struct entry_connection_t {
* only.) */
/* === Isolation related, AP only. === */
- /** AP only: based on which factors do we isolate this stream? */
- uint8_t isolation_flags;
- /** AP only: what session group is this stream in? */
- int session_group;
+ entry_port_cfg_t entry_cfg;
/** AP only: The newnym epoch in which we created this connection. */
unsigned nym_epoch;
+
/** AP only: The original requested address before we rewrote it. */
char *original_dest_address;
/* Other fields to isolate on already exist. The ClientAddr is addr. The
@@ -1675,33 +1673,8 @@ typedef struct entry_connection_t {
*/
unsigned int may_use_optimistic_data : 1;
- /** Should we permit IPv4 and IPv6 traffic to use this connection?
- *
- * @{ */
- unsigned int ipv4_traffic_ok : 1;
- unsigned int ipv6_traffic_ok : 1;
- /** @} */
- /** Should we say we prefer IPv6 traffic? */
- unsigned int prefer_ipv6_traffic : 1;
-
- /** For a socks listener: should we cache IPv4/IPv6 DNS information that
- * exit nodes tell us?
- *
- * @{ */
- unsigned int cache_ipv4_answers : 1;
- unsigned int cache_ipv6_answers : 1;
- /** @} */
- /** For a socks listeners: if we find an answer in our client-side DNS cache,
- * should we use it?
- *
- * @{ */
- unsigned int use_cached_ipv4_answers : 1;
- unsigned int use_cached_ipv6_answers : 1;
- /** @} */
- /** For socks listeners: When we can automap an address to IPv4 or IPv6,
- * do we prefer IPv6? */
- unsigned int prefer_ipv6_virtaddr : 1;
-
+ /** Are we a socks SocksSocket listener? */
+ unsigned int is_socks_socket:1;
} entry_connection_t;
typedef enum {
@@ -3342,44 +3315,9 @@ typedef struct port_cfg_t {
uint8_t type; /**< One of CONN_TYPE_*_LISTENER */
unsigned is_unix_addr : 1; /**< True iff this is an AF_UNIX address. */
- /* Client port types (socks, dns, trans, natd) only: */
- uint8_t isolation_flags; /**< Zero or more isolation flags */
- int session_group; /**< A session group, or -1 if this port is not in a
- * session group. */
- /* Socks only: */
- /** When both no-auth and user/pass are advertised by a SOCKS client, select
- * no-auth. */
- unsigned int socks_prefer_no_auth : 1;
+ entry_port_cfg_t entry_cfg;
- /* Server port types (or, dir) only: */
- unsigned int no_advertise : 1;
- unsigned int no_listen : 1;
- unsigned int all_addrs : 1;
- unsigned int bind_ipv4_only : 1;
- unsigned int bind_ipv6_only : 1;
-
- /* Client port types only: */
- unsigned int ipv4_traffic : 1;
- unsigned int ipv6_traffic : 1;
- unsigned int prefer_ipv6 : 1;
-
- /** For a socks listener: should we cache IPv4/IPv6 DNS information that
- * exit nodes tell us?
- *
- * @{ */
- unsigned int cache_ipv4_answers : 1;
- unsigned int cache_ipv6_answers : 1;
- /** @} */
- /** For a socks listeners: if we find an answer in our client-side DNS cache,
- * should we use it?
- *
- * @{ */
- unsigned int use_cached_ipv4_answers : 1;
- unsigned int use_cached_ipv6_answers : 1;
- /** @} */
- /** For socks listeners: When we can automap an address to IPv4 or IPv6,
- * do we prefer IPv6? */
- unsigned int prefer_ipv6_virtaddr : 1;
+ server_port_cfg_t server_cfg;
/* Unix sockets only: */
/** Path for an AF_UNIX address */
@@ -3528,6 +3466,10 @@ typedef struct {
* for control connections. */
int ControlSocketsGroupWritable; /**< Boolean: Are control sockets g+rw? */
+ config_line_t *SocksSocket; /**< List of Unix Domain Sockets to listen on
+ * for SOCKS connections. */
+
+ int SocksSocketsGroupWritable; /**< Boolean: Are SOCKS sockets g+rw? */
/** Ports to listen on for directory connections. */
config_line_t *DirPort_lines;
config_line_t *DNSPort_lines; /**< Ports to listen on for DNS requests. */
@@ -3550,6 +3492,7 @@ typedef struct {
*/
unsigned int ORPort_set : 1;
unsigned int SocksPort_set : 1;
+ unsigned int SocksSocket_set : 1;
unsigned int TransPort_set : 1;
unsigned int NATDPort_set : 1;
unsigned int ControlPort_set : 1;
@@ -4105,6 +4048,11 @@ typedef struct {
* regardless of uptime and bandwidth. */
routerset_t *TestingDirAuthVoteGuard;
+ /** Relays in a testing network which should be voted HSDir
+ * regardless of uptime and ORPort connectivity.
+ * Respects VoteOnHidServDirectoriesV2. */
+ routerset_t *TestingDirAuthVoteHSDir;
+
/** Enable CONN_BW events. Only altered on testing networks. */
int TestingEnableConnBwEvent;
@@ -4949,7 +4897,8 @@ typedef struct rend_service_descriptor_t {
/** A cached rendezvous descriptor. */
typedef struct rend_cache_entry_t {
size_t len; /**< Length of <b>desc</b> */
- time_t received; /**< When was the descriptor received? */
+ time_t last_served; /**< When did we last write this one to somebody?
+ * (HSDir only) */
char *desc; /**< Service descriptor */
rend_service_descriptor_t *parsed; /**< Parsed value of 'desc' */
} rend_cache_entry_t;
diff --git a/src/or/reasons.c b/src/or/reasons.c
index c65acb54ae..23ab6041a6 100644
--- a/src/or/reasons.c
+++ b/src/or/reasons.c
@@ -350,6 +350,8 @@ circuit_end_reason_to_control_string(int reason)
return "NOSUCHSERVICE";
case END_CIRC_REASON_MEASUREMENT_EXPIRED:
return "MEASUREMENT_EXPIRED";
+ case END_CIRC_REASON_IP_NOW_REDUNDANT:
+ return "IP_NOW_REDUNDANT";
default:
if (is_remote) {
/*
diff --git a/src/or/relay.c b/src/or/relay.c
index 2d11096309..350353e452 100644
--- a/src/or/relay.c
+++ b/src/or/relay.c
@@ -804,8 +804,8 @@ connection_ap_process_end_not_open(
return 0;
}
- if ((tor_addr_family(&addr) == AF_INET && !conn->ipv4_traffic_ok) ||
- (tor_addr_family(&addr) == AF_INET6 && !conn->ipv6_traffic_ok)) {
+ if ((tor_addr_family(&addr) == AF_INET && !conn->entry_cfg.ipv4_traffic) ||
+ (tor_addr_family(&addr) == AF_INET6 && !conn->entry_cfg.ipv6_traffic)) {
log_fn(LOG_PROTOCOL_WARN, LD_APP,
"Got an EXITPOLICY failure on a connection with a "
"mismatched family. Closing.");
@@ -1156,11 +1156,11 @@ connection_ap_handshake_socks_got_resolved_cell(entry_connection_t *conn,
addr_hostname = addr;
}
} else if (tor_addr_family(&addr->addr) == AF_INET) {
- if (!addr_ipv4 && conn->ipv4_traffic_ok) {
+ if (!addr_ipv4 && conn->entry_cfg.ipv4_traffic) {
addr_ipv4 = addr;
}
} else if (tor_addr_family(&addr->addr) == AF_INET6) {
- if (!addr_ipv6 && conn->ipv6_traffic_ok) {
+ if (!addr_ipv6 && conn->entry_cfg.ipv6_traffic) {
addr_ipv6 = addr;
}
}
@@ -1181,7 +1181,7 @@ connection_ap_handshake_socks_got_resolved_cell(entry_connection_t *conn,
return;
}
- if (conn->prefer_ipv6_traffic) {
+ if (conn->entry_cfg.prefer_ipv6) {
addr_best = addr_ipv6 ? addr_ipv6 : addr_ipv4;
} else {
addr_best = addr_ipv4 ? addr_ipv4 : addr_ipv6;
@@ -1327,8 +1327,8 @@ connection_edge_process_relay_cell_not_open(
return 0;
}
- if ((family == AF_INET && ! entry_conn->ipv4_traffic_ok) ||
- (family == AF_INET6 && ! entry_conn->ipv6_traffic_ok)) {
+ if ((family == AF_INET && ! entry_conn->entry_cfg.ipv4_traffic) ||
+ (family == AF_INET6 && ! entry_conn->entry_cfg.ipv6_traffic)) {
log_fn(LOG_PROTOCOL_WARN, LD_APP,
"Got a connected cell to %s with unsupported address family."
" Closing.", fmt_addr(&addr));
@@ -2447,9 +2447,21 @@ cell_queues_check_size(void)
size_t alloc = cell_queues_get_total_allocation();
alloc += buf_get_total_allocation();
alloc += tor_zlib_get_total_allocation();
+ const size_t rend_cache_total = rend_cache_get_total_allocation();
+ alloc += rend_cache_total;
if (alloc >= get_options()->MaxMemInQueues_low_threshold) {
last_time_under_memory_pressure = approx_time();
if (alloc >= get_options()->MaxMemInQueues) {
+ /* If we're spending over 20% of the memory limit on hidden service
+ * descriptors, free them until we're down to 10%.
+ */
+ if (rend_cache_total > get_options()->MaxMemInQueues / 5) {
+ const size_t bytes_to_remove =
+ rend_cache_total - (size_t)(get_options()->MaxMemInQueues / 10);
+ rend_cache_clean_v2_descs_as_dir(time(NULL), bytes_to_remove);
+ alloc -= rend_cache_total;
+ alloc += rend_cache_get_total_allocation();
+ }
circuits_handle_oom(alloc);
return 1;
}
diff --git a/src/or/rendclient.c b/src/or/rendclient.c
index 8cace92b2c..4b7d85a5e0 100644
--- a/src/or/rendclient.c
+++ b/src/or/rendclient.c
@@ -547,7 +547,12 @@ directory_clean_last_hid_serv_requests(time_t now)
/** Remove all requests related to the hidden service named
* <b>onion_address</b> from the history of times of requests to
- * hidden service directories. */
+ * hidden service directories.
+ *
+ * This is called from rend_client_note_connection_attempt_ended(), which
+ * must be idempotent, so any future changes to this function must leave
+ * it idempotent too.
+ */
static void
purge_hid_serv_from_last_hid_serv_requests(const char *onion_address)
{
@@ -1076,8 +1081,11 @@ rend_client_desc_trynow(const char *query)
/** Clear temporary state used only during an attempt to connect to
* the hidden service named <b>onion_address</b>. Called when a
- * connection attempt has ended; may be called occasionally at other
- * times, and should be reasonably harmless. */
+ * connection attempt has ended; it is possible for this to be called
+ * multiple times while handling an ended connection attempt, and
+ * any future changes to this function must ensure it remains
+ * idempotent.
+ */
void
rend_client_note_connection_attempt_ended(const char *onion_address)
{
diff --git a/src/or/rendcommon.c b/src/or/rendcommon.c
index 0f75118be2..866f4fb026 100644
--- a/src/or/rendcommon.c
+++ b/src/or/rendcommon.c
@@ -704,6 +704,9 @@ static strmap_t *rend_cache = NULL;
* directories. */
static digestmap_t *rend_cache_v2_dir = NULL;
+/** DOCDOC */
+static size_t rend_cache_total_allocation = 0;
+
/** Initializes the service descriptor cache.
*/
void
@@ -713,12 +716,64 @@ rend_cache_init(void)
rend_cache_v2_dir = digestmap_new();
}
+/** Return the approximate number of bytes needed to hold <b>e</b>. */
+static size_t
+rend_cache_entry_allocation(const rend_cache_entry_t *e)
+{
+ if (!e)
+ return 0;
+
+ /* This doesn't count intro_nodes or key size */
+ return sizeof(*e) + e->len + sizeof(*e->parsed);
+}
+
+/** DOCDOC */
+size_t
+rend_cache_get_total_allocation(void)
+{
+ return rend_cache_total_allocation;
+}
+
+/** Decrement the total bytes attributed to the rendezvous cache by n. */
+static void
+rend_cache_decrement_allocation(size_t n)
+{
+ static int have_underflowed = 0;
+
+ if (rend_cache_total_allocation >= n) {
+ rend_cache_total_allocation -= n;
+ } else {
+ rend_cache_total_allocation = 0;
+ if (! have_underflowed) {
+ have_underflowed = 1;
+ log_warn(LD_BUG, "Underflow in rend_cache_decrement_allocation");
+ }
+ }
+}
+
+/** Increase the total bytes attributed to the rendezvous cache by n. */
+static void
+rend_cache_increment_allocation(size_t n)
+{
+ static int have_overflowed = 0;
+ if (rend_cache_total_allocation <= SIZE_MAX - n) {
+ rend_cache_total_allocation += n;
+ } else {
+ rend_cache_total_allocation = SIZE_MAX;
+ if (! have_overflowed) {
+ have_overflowed = 1;
+ log_warn(LD_BUG, "Overflow in rend_cache_increment_allocation");
+ }
+ }
+}
+
/** Helper: free storage held by a single service descriptor cache entry. */
static void
rend_cache_entry_free(rend_cache_entry_t *e)
{
if (!e)
return;
+ rend_cache_decrement_allocation(rend_cache_entry_allocation(e));
rend_service_descriptor_free(e->parsed);
tor_free(e->desc);
tor_free(e);
@@ -740,6 +795,7 @@ rend_cache_free_all(void)
digestmap_free(rend_cache_v2_dir, rend_cache_entry_free_);
rend_cache = NULL;
rend_cache_v2_dir = NULL;
+ rend_cache_total_allocation = 0;
}
/** Removes all old entries from the service descriptor cache.
@@ -777,31 +833,46 @@ rend_cache_purge(void)
}
/** Remove all old v2 descriptors and those for which this hidden service
- * directory is not responsible for any more. */
+ * directory is not responsible for any more.
+ *
+ * If at all possible, remove at least <b>force_remove</b> bytes of data.
+ */
void
-rend_cache_clean_v2_descs_as_dir(time_t now)
+rend_cache_clean_v2_descs_as_dir(time_t now, size_t force_remove)
{
digestmap_iter_t *iter;
time_t cutoff = now - REND_CACHE_MAX_AGE - REND_CACHE_MAX_SKEW;
- for (iter = digestmap_iter_init(rend_cache_v2_dir);
- !digestmap_iter_done(iter); ) {
- const char *key;
- void *val;
- rend_cache_entry_t *ent;
- digestmap_iter_get(iter, &key, &val);
- ent = val;
- if (ent->parsed->timestamp < cutoff ||
- !hid_serv_responsible_for_desc_id(key)) {
- char key_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
- base32_encode(key_base32, sizeof(key_base32), key, DIGEST_LEN);
- log_info(LD_REND, "Removing descriptor with ID '%s' from cache",
- safe_str_client(key_base32));
- iter = digestmap_iter_next_rmv(rend_cache_v2_dir, iter);
- rend_cache_entry_free(ent);
- } else {
- iter = digestmap_iter_next(rend_cache_v2_dir, iter);
+ const int LAST_SERVED_CUTOFF_STEP = 1800;
+ time_t last_served_cutoff = cutoff;
+ size_t bytes_removed = 0;
+ do {
+ for (iter = digestmap_iter_init(rend_cache_v2_dir);
+ !digestmap_iter_done(iter); ) {
+ const char *key;
+ void *val;
+ rend_cache_entry_t *ent;
+ digestmap_iter_get(iter, &key, &val);
+ ent = val;
+ if (ent->parsed->timestamp < cutoff ||
+ ent->last_served < last_served_cutoff ||
+ !hid_serv_responsible_for_desc_id(key)) {
+ char key_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
+ base32_encode(key_base32, sizeof(key_base32), key, DIGEST_LEN);
+ log_info(LD_REND, "Removing descriptor with ID '%s' from cache",
+ safe_str_client(key_base32));
+ bytes_removed += rend_cache_entry_allocation(ent);
+ iter = digestmap_iter_next_rmv(rend_cache_v2_dir, iter);
+ rend_cache_entry_free(ent);
+ } else {
+ iter = digestmap_iter_next(rend_cache_v2_dir, iter);
+ }
}
- }
+
+ /* In case we didn't remove enough bytes, advance the cutoff a little. */
+ last_served_cutoff += LAST_SERVED_CUTOFF_STEP;
+ if (last_served_cutoff > now)
+ break;
+ } while (bytes_removed < force_remove);
}
/** Determines whether <b>a</b> is in the interval of <b>b</b> (excluded) and
@@ -903,6 +974,7 @@ rend_cache_lookup_v2_desc_as_dir(const char *desc_id, const char **desc)
e = digestmap_get(rend_cache_v2_dir, desc_id_digest);
if (e) {
*desc = e->desc;
+ e->last_served = approx_time();
return 1;
}
return 0;
@@ -986,21 +1058,26 @@ rend_cache_store_v2_desc_as_dir(const char *desc)
if (e && !strcmp(desc, e->desc)) {
log_info(LD_REND, "We already have this service descriptor with desc "
"ID %s.", safe_str(desc_id_base32));
- e->received = time(NULL);
goto skip;
}
/* Store received descriptor. */
if (!e) {
e = tor_malloc_zero(sizeof(rend_cache_entry_t));
digestmap_set(rend_cache_v2_dir, desc_id, e);
+ /* Treat something just uploaded as having been served a little
+ * while ago, so that flooding with new descriptors doesn't help
+ * too much.
+ */
+ e->last_served = approx_time() - 3600;
} else {
+ rend_cache_decrement_allocation(rend_cache_entry_allocation(e));
rend_service_descriptor_free(e->parsed);
tor_free(e->desc);
}
- e->received = time(NULL);
e->parsed = parsed;
e->desc = tor_strndup(current_desc, encoded_size);
e->len = encoded_size;
+ rend_cache_increment_allocation(rend_cache_entry_allocation(e));
log_info(LD_REND, "Successfully stored service descriptor with desc ID "
"'%s' and len %d.",
safe_str(desc_id_base32), (int)encoded_size);
@@ -1172,31 +1249,25 @@ rend_cache_store_v2_desc_as_client(const char *desc,
/* Do we already have a newer descriptor? */
tor_snprintf(key, sizeof(key), "2%s", service_id);
e = (rend_cache_entry_t*) strmap_get_lc(rend_cache, key);
- if (e && e->parsed->timestamp > parsed->timestamp) {
- log_info(LD_REND, "We already have a newer service descriptor for "
+ if (e && e->parsed->timestamp >= parsed->timestamp) {
+ log_info(LD_REND, "We already have a new enough service descriptor for "
"service ID %s with the same desc ID and version.",
safe_str_client(service_id));
goto okay;
}
- /* Do we already have this descriptor? */
- if (e && !strcmp(desc, e->desc)) {
- log_info(LD_REND,"We already have this service descriptor %s.",
- safe_str_client(service_id));
- e->received = time(NULL);
- goto okay;
- }
if (!e) {
e = tor_malloc_zero(sizeof(rend_cache_entry_t));
strmap_set_lc(rend_cache, key, e);
} else {
+ rend_cache_decrement_allocation(rend_cache_entry_allocation(e));
rend_service_descriptor_free(e->parsed);
tor_free(e->desc);
}
- e->received = time(NULL);
e->parsed = parsed;
e->desc = tor_malloc_zero(encoded_size + 1);
strlcpy(e->desc, desc, encoded_size + 1);
e->len = encoded_size;
+ rend_cache_increment_allocation(rend_cache_entry_allocation(e));
log_debug(LD_REND,"Successfully stored rend desc '%s', len %d.",
safe_str_client(service_id), (int)encoded_size);
return RCS_OKAY;
diff --git a/src/or/rendcommon.h b/src/or/rendcommon.h
index 4b910d2729..8396cc3551 100644
--- a/src/or/rendcommon.h
+++ b/src/or/rendcommon.h
@@ -33,7 +33,7 @@ void rend_intro_point_free(rend_intro_point_t *intro);
void rend_cache_init(void);
void rend_cache_clean(time_t now);
-void rend_cache_clean_v2_descs_as_dir(time_t now);
+void rend_cache_clean_v2_descs_as_dir(time_t now, size_t min_to_remove);
void rend_cache_purge(void);
void rend_cache_free_all(void);
int rend_valid_service_id(const char *query);
@@ -51,7 +51,6 @@ rend_cache_store_status_t rend_cache_store_v2_desc_as_dir(const char *desc);
rend_cache_store_status_t rend_cache_store_v2_desc_as_client(const char *desc,
const char *desc_id_base32,
const rend_data_t *rend_query);
-
int rend_encode_v2_descriptors(smartlist_t *descs_out,
rend_service_descriptor_t *desc, time_t now,
uint8_t period, rend_auth_type_t auth_type,
@@ -64,6 +63,7 @@ int rend_id_is_in_interval(const char *a, const char *b, const char *c);
void rend_get_descriptor_id_bytes(char *descriptor_id_out,
const char *service_id,
const char *secret_id_part);
+size_t rend_cache_get_total_allocation(void);
#endif
diff --git a/src/or/rendservice.c b/src/or/rendservice.c
index 3b73674691..ca9b380d7d 100644
--- a/src/or/rendservice.c
+++ b/src/or/rendservice.c
@@ -3270,6 +3270,9 @@ rend_services_introduce(void)
smartlist_free(exclude_nodes);
}
+#define MIN_REND_INITIAL_POST_DELAY (30)
+#define MIN_REND_INITIAL_POST_DELAY_TESTING (5)
+
/** Regenerate and upload rendezvous service descriptors for all
* services, if necessary. If the descriptor has been dirty enough
* for long enough, definitely upload; else only upload when the
@@ -3284,6 +3287,9 @@ rend_consider_services_upload(time_t now)
int i;
rend_service_t *service;
int rendpostperiod = get_options()->RendPostPeriod;
+ int rendinitialpostdelay = (get_options()->TestingTorNetwork ?
+ MIN_REND_INITIAL_POST_DELAY_TESTING :
+ MIN_REND_INITIAL_POST_DELAY);
if (!get_options()->PublishHidServDescriptors)
return;
@@ -3291,17 +3297,17 @@ rend_consider_services_upload(time_t now)
for (i=0; i < smartlist_len(rend_service_list); ++i) {
service = smartlist_get(rend_service_list, i);
if (!service->next_upload_time) { /* never been uploaded yet */
- /* The fixed lower bound of 30 seconds ensures that the descriptor
- * is stable before being published. See comment below. */
+ /* The fixed lower bound of rendinitialpostdelay seconds ensures that
+ * the descriptor is stable before being published. See comment below. */
service->next_upload_time =
- now + 30 + crypto_rand_int(2*rendpostperiod);
+ now + rendinitialpostdelay + crypto_rand_int(2*rendpostperiod);
}
if (service->next_upload_time < now ||
(service->desc_is_dirty &&
- service->desc_is_dirty < now-30)) {
+ service->desc_is_dirty < now-rendinitialpostdelay)) {
/* if it's time, or if the directory servers have a wrong service
- * descriptor and ours has been stable for 30 seconds, upload a
- * new one of each format. */
+ * descriptor and ours has been stable for rendinitialpostdelay seconds,
+ * upload a new one of each format. */
rend_service_update_descriptor(service);
upload_service_descriptor(service);
}
diff --git a/src/or/router.c b/src/or/router.c
index 00c365ffa5..2ddaa895fc 100644
--- a/src/or/router.c
+++ b/src/or/router.c
@@ -313,6 +313,7 @@ rotate_onion_key(void)
time_t now;
fname = get_datadir_fname2("keys", "secret_onion_key");
fname_prev = get_datadir_fname2("keys", "secret_onion_key.old");
+ /* There isn't much point replacing an old key with an empty file */
if (file_status(fname) == FN_FILE) {
if (replace_file(fname, fname_prev))
goto error;
@@ -335,6 +336,7 @@ rotate_onion_key(void)
fname_prev = get_datadir_fname2("keys", "secret_onion_key_ntor.old");
if (curve25519_keypair_generate(&new_curve25519_keypair, 1) < 0)
goto error;
+ /* There isn't much point replacing an old key with an empty file */
if (file_status(fname) == FN_FILE) {
if (replace_file(fname, fname_prev))
goto error;
@@ -411,7 +413,11 @@ init_key_from_file(const char *fname, int generate, int severity,
case FN_ERROR:
tor_log(severity, LD_FS,"Can't read key from \"%s\"", fname);
goto error;
+ /* treat empty key files as if the file doesn't exist, and,
+ * if generate is set, replace the empty file in
+ * crypto_pk_write_private_key_to_filename() */
case FN_NOENT:
+ case FN_EMPTY:
if (generate) {
if (!have_lockfile()) {
if (try_locking(get_options(), 0)<0) {
@@ -464,10 +470,10 @@ init_key_from_file(const char *fname, int generate, int severity,
}
/** Load a curve25519 keypair from the file <b>fname</b>, writing it into
- * <b>keys_out</b>. If the file isn't found and <b>generate</b> is true,
- * create a new keypair and write it into the file. If there are errors, log
- * them at level <b>severity</b>. Generate files using <b>tag</b> in their
- * ASCII wrapper. */
+ * <b>keys_out</b>. If the file isn't found, or is empty, and <b>generate</b>
+ * is true, create a new keypair and write it into the file. If there are
+ * errors, log them at level <b>severity</b>. Generate files using <b>tag</b>
+ * in their ASCII wrapper. */
static int
init_curve25519_keypair_from_file(curve25519_keypair_t *keys_out,
const char *fname,
@@ -480,7 +486,10 @@ init_curve25519_keypair_from_file(curve25519_keypair_t *keys_out,
case FN_ERROR:
tor_log(severity, LD_FS,"Can't read key from \"%s\"", fname);
goto error;
+ /* treat empty key files as if the file doesn't exist, and, if generate
+ * is set, replace the empty file in curve25519_keypair_write_to_file() */
case FN_NOENT:
+ case FN_EMPTY:
if (generate) {
if (!have_lockfile()) {
if (try_locking(get_options(), 0)<0) {
@@ -880,7 +889,9 @@ init_keys(void)
keydir = get_datadir_fname2("keys", "secret_onion_key.old");
if (!lastonionkey && file_status(keydir) == FN_FILE) {
- prkey = init_key_from_file(keydir, 1, LOG_ERR, 0); /* XXXX Why 1? */
+ /* Load keys from non-empty files only.
+ * Missing old keys won't be replaced with freshly generated keys. */
+ prkey = init_key_from_file(keydir, 0, LOG_ERR, 0);
if (prkey)
lastonionkey = prkey;
}
@@ -901,6 +912,8 @@ init_keys(void)
last_curve25519_onion_key.pubkey.public_key,
CURVE25519_PUBKEY_LEN) &&
file_status(keydir) == FN_FILE) {
+ /* Load keys from non-empty files only.
+ * Missing old keys won't be replaced with freshly generated keys. */
init_curve25519_keypair_from_file(&last_curve25519_onion_key,
keydir, 0, LOG_ERR, "onion");
}
@@ -1835,8 +1848,8 @@ router_rebuild_descriptor(int force)
const port_cfg_t *ipv6_orport = NULL;
SMARTLIST_FOREACH_BEGIN(get_configured_ports(), const port_cfg_t *, p) {
if (p->type == CONN_TYPE_OR_LISTENER &&
- ! p->no_advertise &&
- ! p->bind_ipv4_only &&
+ ! p->server_cfg.no_advertise &&
+ ! p->server_cfg.bind_ipv4_only &&
tor_addr_family(&p->addr) == AF_INET6) {
if (! tor_addr_is_internal(&p->addr, 0)) {
ipv6_orport = p;
@@ -2577,8 +2590,9 @@ router_has_orport(const routerinfo_t *router, const tor_addr_port_t *orport)
* <b>end_line</b>, ensure that its timestamp is not more than 25 hours in
* the past or more than 1 hour in the future with respect to <b>now</b>,
* and write the file contents starting with that line to *<b>out</b>.
- * Return 1 for success, 0 if the file does not exist, or -1 if the file
- * does not contain a line matching these criteria or other failure. */
+ * Return 1 for success, 0 if the file does not exist or is empty, or -1
+ * if the file does not contain a line matching these criteria or other
+ * failure. */
static int
load_stats_file(const char *filename, const char *end_line, time_t now,
char **out)
@@ -2612,7 +2626,9 @@ load_stats_file(const char *filename, const char *end_line, time_t now,
notfound:
tor_free(contents);
break;
+ /* treat empty stats files as if the file doesn't exist */
case FN_NOENT:
+ case FN_EMPTY:
r = 0;
break;
case FN_ERROR:
diff --git a/src/or/routerlist.c b/src/or/routerlist.c
index 6cb052c03e..d3734238eb 100644
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@ -1206,6 +1206,7 @@ router_reload_router_list_impl(desc_store_t *store)
tor_free(fname);
fname = get_datadir_fname_suffix(store->fname_base, ".new");
+ /* don't load empty files - we wouldn't get any data, even if we tried */
if (file_status(fname) == FN_FILE)
contents = read_file_to_str(fname, RFTS_BIN|RFTS_IGNORE_MISSING, &st);
if (contents) {
diff --git a/src/or/statefile.c b/src/or/statefile.c
index c279858de6..dd1894beb7 100644
--- a/src/or/statefile.c
+++ b/src/or/statefile.c
@@ -323,7 +323,10 @@ or_state_load(void)
goto done;
}
break;
+ /* treat empty state files as if the file doesn't exist, and generate
+ * a new state file, overwriting the empty file in or_state_save() */
case FN_NOENT:
+ case FN_EMPTY:
break;
case FN_ERROR:
case FN_DIR:
diff --git a/src/test/include.am b/src/test/include.am
index 46db801d27..134c2ff56c 100644
--- a/src/test/include.am
+++ b/src/test/include.am
@@ -123,9 +123,11 @@ if USEPYTHON
./src/test/test-bt-cl assert | $(PYTHON) $(top_srcdir)/src/test/bt_test.py
./src/test/test-bt-cl crash | $(PYTHON) $(top_srcdir)/src/test/bt_test.py
endif
+ $(top_srcdir)/src/test/zero_length_keys.sh
EXTRA_DIST += \
src/test/bt_test.py \
src/test/ntor_ref.py \
src/test/slownacl_curve25519.py \
- src/test/test_cmdline_args.py
+ src/test/test_cmdline_args.py \
+ src/test/zero_length_keys.sh
diff --git a/src/test/test-network.sh b/src/test/test-network.sh
index d28fbde80f..be57cafb7f 100755
--- a/src/test/test-network.sh
+++ b/src/test/test-network.sh
@@ -45,7 +45,7 @@ PATH="$TOR_DIR/src/or:$TOR_DIR/src/tools:$PATH"
# Sleep some, waiting for the network to bootstrap.
# TODO: Add chutney command 'bootstrap-status' and use that instead.
-BOOTSTRAP_TIME=${BOOTSTRAP_TIME:-18}
+BOOTSTRAP_TIME=${BOOTSTRAP_TIME:-25}
$ECHO_N "$myname: sleeping for $BOOTSTRAP_TIME seconds"
n=$BOOTSTRAP_TIME; while [ $n -gt 0 ]; do
sleep 1; n=$(expr $n - 1); $ECHO_N .
diff --git a/src/test/test_checkdir.c b/src/test/test_checkdir.c
index 882e3b3a61..ae859449cb 100644
--- a/src/test/test_checkdir.c
+++ b/src/test/test_checkdir.c
@@ -11,6 +11,7 @@
#ifdef _WIN32
#define mkdir(a,b) mkdir(a)
#define tt_int_op_nowin(a,op,b) do { (void)(a); (void)(b); } while (0)
+#define umask(mask) ((void)0)
#else
#define tt_int_op_nowin(a,op,b) tt_int_op((a),op,(b))
#endif
@@ -28,6 +29,8 @@ test_checkdir_perms(void *testdata)
cpd_check_t unix_verify_optsmask;
struct stat st;
+ umask(022);
+
/* setup data directory before tests. */
tor_free(options->DataDirectory);
options->DataDirectory = tor_strdup(get_fname(subdir));
@@ -134,7 +137,7 @@ test_checkdir_perms(void *testdata)
{ #name, test_checkdir_##name, (flags), NULL, NULL }
struct testcase_t checkdir_tests[] = {
- CHECKDIR(perms, 0),
+ CHECKDIR(perms, TT_FORK),
END_OF_TESTCASES
};
diff --git a/src/test/test_entryconn.c b/src/test/test_entryconn.c
index 4c14edefd7..146cddc331 100644
--- a/src/test/test_entryconn.c
+++ b/src/test/test_entryconn.c
@@ -269,7 +269,7 @@ test_entryconn_rewrite_automap_reverse(void *arg)
strlcpy(ec2->socks_request->address, ec->socks_request->address,
sizeof(ec2->socks_request->address));
- ec2->use_cached_ipv4_answers = 1; // XXXX REMOVE. This is only there to hide a bug.
+ ec2->entry_cfg.use_cached_ipv4_answers = 1; // XXXX REMOVE. This is only there to hide a bug.
ec2->socks_request->command = SOCKS_COMMAND_RESOLVE_PTR;
connection_ap_handshake_rewrite(ec2, &rr);
@@ -310,7 +310,7 @@ test_entryconn_rewrite_cached_dns_ipv4(void *arg)
ec->socks_request->command = SOCKS_COMMAND_CONNECT;
ec2->socks_request->command = SOCKS_COMMAND_CONNECT;
- ec2->use_cached_ipv4_answers = 1; /* only ec2 gets this flag */
+ ec2->entry_cfg.use_cached_ipv4_answers = 1; /* only ec2 gets this flag */
connection_ap_handshake_rewrite(ec, &rr);
tt_int_op(rr.automap, OP_EQ, 0);
@@ -362,7 +362,7 @@ test_entryconn_rewrite_cached_dns_ipv6(void *arg)
ec->socks_request->command = SOCKS_COMMAND_CONNECT;
ec2->socks_request->command = SOCKS_COMMAND_CONNECT;
- ec2->use_cached_ipv6_answers = 1; /* only ec2 gets this flag */
+ ec2->entry_cfg.use_cached_ipv6_answers = 1; /* only ec2 gets this flag */
connection_ap_handshake_rewrite(ec, &rr);
tt_int_op(rr.automap, OP_EQ, 0);
diff --git a/src/test/test_relaycell.c b/src/test/test_relaycell.c
index 28c8f4e8ef..0a6fef729c 100644
--- a/src/test/test_relaycell.c
+++ b/src/test/test_relaycell.c
@@ -137,9 +137,9 @@ test_relaycell_resolved(void *arg)
/* Now put it in the right state. */
ENTRY_TO_CONN(entryconn)->state = AP_CONN_STATE_RESOLVE_WAIT;
entryconn->socks_request->command = SOCKS_COMMAND_RESOLVE;
- entryconn->ipv4_traffic_ok = 1;
- entryconn->ipv6_traffic_ok = 1;
- entryconn->prefer_ipv6_traffic = 0;
+ entryconn->entry_cfg.ipv4_traffic = 1;
+ entryconn->entry_cfg.ipv6_traffic = 1;
+ entryconn->entry_cfg.prefer_ipv6 = 0;
/* We prefer ipv4, so we should get the first ipv4 answer */
MOCK_RESET();
@@ -159,7 +159,7 @@ test_relaycell_resolved(void *arg)
ASSERT_RESOLVED_CALLED(RESOLVED_TYPE_IPV4, "\x12\x00\x00\x01", 512, -1);
/* now prefer ipv6, and get the first ipv6 answer */
- entryconn->prefer_ipv6_traffic = 1;
+ entryconn->entry_cfg.prefer_ipv6 = 1;
MOCK_RESET();
r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh);
tt_int_op(r, OP_EQ, 0);
@@ -182,7 +182,7 @@ test_relaycell_resolved(void *arg)
/* But if we don't allow IPv4, we report nothing if the cell contains only
* ipv4 */
MOCK_RESET();
- entryconn->ipv4_traffic_ok = 0;
+ entryconn->entry_cfg.ipv4_traffic = 0;
r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh);
tt_int_op(r, OP_EQ, 0);
ASSERT_MARK_CALLED(END_STREAM_REASON_DONE|
@@ -191,7 +191,7 @@ test_relaycell_resolved(void *arg)
/* If we wanted hostnames, we report nothing, since we only had IPs. */
MOCK_RESET();
- entryconn->ipv4_traffic_ok = 1;
+ entryconn->entry_cfg.ipv4_traffic = 1;
entryconn->socks_request->command = SOCKS_COMMAND_RESOLVE_PTR;
r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh);
tt_int_op(r, OP_EQ, 0);
diff --git a/src/test/test_util.c b/src/test/test_util.c
index 15470e8efa..2ee1d6dfc1 100644
--- a/src/test/test_util.c
+++ b/src/test/test_util.c
@@ -4614,26 +4614,26 @@ test_util_round_to_next_multiple_of(void *arg)
{
(void)arg;
- tt_assert(round_uint64_to_next_multiple_of(0,1) == 0);
- tt_assert(round_uint64_to_next_multiple_of(0,7) == 0);
+ tt_u64_op(round_uint64_to_next_multiple_of(0,1), ==, 0);
+ tt_u64_op(round_uint64_to_next_multiple_of(0,7), ==, 0);
- tt_assert(round_uint64_to_next_multiple_of(99,1) == 99);
- tt_assert(round_uint64_to_next_multiple_of(99,7) == 105);
- tt_assert(round_uint64_to_next_multiple_of(99,9) == 99);
+ tt_u64_op(round_uint64_to_next_multiple_of(99,1), ==, 99);
+ tt_u64_op(round_uint64_to_next_multiple_of(99,7), ==, 105);
+ tt_u64_op(round_uint64_to_next_multiple_of(99,9), ==, 99);
- tt_assert(round_int64_to_next_multiple_of(0,1) == 0);
- tt_assert(round_int64_to_next_multiple_of(0,7) == 0);
+ tt_i64_op(round_int64_to_next_multiple_of(0,1), ==, 0);
+ tt_i64_op(round_int64_to_next_multiple_of(0,7), ==, 0);
- tt_assert(round_int64_to_next_multiple_of(99,1) == 99);
- tt_assert(round_int64_to_next_multiple_of(99,7) == 105);
- tt_assert(round_int64_to_next_multiple_of(99,9) == 99);
+ tt_i64_op(round_int64_to_next_multiple_of(99,1), ==, 99);
+ tt_i64_op(round_int64_to_next_multiple_of(99,7), ==, 105);
+ tt_i64_op(round_int64_to_next_multiple_of(99,9), ==, 99);
- tt_assert(round_int64_to_next_multiple_of(-99,1) == -99);
- tt_assert(round_int64_to_next_multiple_of(-99,7) == -98);
- tt_assert(round_int64_to_next_multiple_of(-99,9) == -99);
+ tt_i64_op(round_int64_to_next_multiple_of(-99,1), ==, -99);
+ tt_i64_op(round_int64_to_next_multiple_of(-99,7), ==, -98);
+ tt_i64_op(round_int64_to_next_multiple_of(-99,9), ==, -99);
- tt_assert(round_int64_to_next_multiple_of(INT64_MIN,2) == INT64_MIN);
- tt_assert(round_int64_to_next_multiple_of(INT64_MAX,2) ==
+ tt_i64_op(round_int64_to_next_multiple_of(INT64_MIN,2), ==, INT64_MIN);
+ tt_i64_op(round_int64_to_next_multiple_of(INT64_MAX,2), ==,
INT64_MAX-INT64_MAX%2);
done:
;
@@ -4654,25 +4654,26 @@ test_util_laplace(void *arg)
const double delta_f = 15.0, epsilon = 0.3; /* b = 15.0 / 0.3 = 50.0 */
(void)arg;
- tt_assert(isinf(sample_laplace_distribution(mu, b, 0.0)));
- test_feq(-69.88855213, sample_laplace_distribution(mu, b, 0.01));
- test_feq(24.0, sample_laplace_distribution(mu, b, 0.5));
- test_feq(24.48486498, sample_laplace_distribution(mu, b, 0.51));
- test_feq(117.88855213, sample_laplace_distribution(mu, b, 0.99));
+ tt_i64_op(INT64_MIN, ==, sample_laplace_distribution(mu, b, 0.0));
+ tt_i64_op(-69, ==, sample_laplace_distribution(mu, b, 0.01));
+ tt_i64_op(24, ==, sample_laplace_distribution(mu, b, 0.5));
+ tt_i64_op(24, ==, sample_laplace_distribution(mu, b, 0.51));
+ tt_i64_op(117, ==, sample_laplace_distribution(mu, b, 0.99));
/* >>> laplace.ppf([0.0, 0.1, 0.25, 0.5, 0.75, 0.9, 0.99],
* ... loc = 0, scale = 50)
* array([ -inf, -80.47189562, -34.65735903, 0. ,
* 34.65735903, 80.47189562, 195.60115027])
*/
- tt_assert(INT64_MIN + 20 ==
+ tt_i64_op(INT64_MIN + 20, ==,
add_laplace_noise(20, 0.0, delta_f, epsilon));
- tt_assert(-60 == add_laplace_noise(20, 0.1, delta_f, epsilon));
- tt_assert(-14 == add_laplace_noise(20, 0.25, delta_f, epsilon));
- tt_assert(20 == add_laplace_noise(20, 0.5, delta_f, epsilon));
- tt_assert(54 == add_laplace_noise(20, 0.75, delta_f, epsilon));
- tt_assert(100 == add_laplace_noise(20, 0.9, delta_f, epsilon));
- tt_assert(215 == add_laplace_noise(20, 0.99, delta_f, epsilon));
+ tt_i64_op(-60, ==, add_laplace_noise(20, 0.1, delta_f, epsilon));
+ tt_i64_op(-14, ==, add_laplace_noise(20, 0.25, delta_f, epsilon));
+ tt_i64_op(20, ==, add_laplace_noise(20, 0.5, delta_f, epsilon));
+ tt_i64_op(54, ==, add_laplace_noise(20, 0.75, delta_f, epsilon));
+ tt_i64_op(100, ==, add_laplace_noise(20, 0.9, delta_f, epsilon));
+ tt_i64_op(215, ==, add_laplace_noise(20, 0.99, delta_f, epsilon));
+
done:
;
}
diff --git a/src/test/zero_length_keys.sh b/src/test/zero_length_keys.sh
new file mode 100755
index 0000000000..3a99ca1f1d
--- /dev/null
+++ b/src/test/zero_length_keys.sh
@@ -0,0 +1,115 @@
+#!/bin/sh
+# Check that tor regenerates keys when key files are zero-length
+# Test for bug #13111 - Tor fails to start if onion keys are zero length
+#
+# Usage:
+# ./zero_length_keys.sh
+# Run all the tests below
+# ./zero_length_keys.sh -z
+# Check tor will launch and regenerate zero-length keys
+# ./zero_length_keys.sh -d
+# Check tor regenerates deleted keys (existing behaviour)
+# ./zero_length_keys.sh -e
+# Check tor does not overwrite existing keys (existing behaviour)
+#
+# Exit Statuses:
+# -2: test failed - tor did not generate the key files on first run
+# -1: a command failed - the test could not be completed
+# 0: test succeeded - tor regenerated/kept the files
+# 1: test failed - tor did not regenerate/keep the files
+#
+
+if [ $# -lt 1 ]; then
+ echo "Testing that tor correctly handles zero-length keys"
+ "$0" -z && "$0" -d && "$0" -e
+ exit $?
+fi
+
+export DATA_DIR=`mktemp -d -t tor_zero_length_keys.XXXXXX`
+# DisableNetwork means that the ORPort won't actually be opened.
+# 'ExitRelay 0' suppresses a warning.
+TOR="./src/or/tor --hush --DisableNetwork 1 --ShutdownWaitLength 0 --ORPort 12345 --ExitRelay 0"
+
+if [ -s "$DATA_DIR"/keys/secret_id_key -a -s "$DATA_DIR"/keys/secret_onion_key -a -s "$DATA_DIR"/keys/secret_onion_key_ntor ]; then
+ echo "Failure: Previous tor keys present in tor data directory"
+ exit -1
+else
+ echo "Generating initial tor keys"
+ $TOR --DataDirectory "$DATA_DIR" --PidFile "$DATA_DIR"/pid &
+ TOR_PID=$!
+ # generate SIGTERM, hopefully after the keys have been regenerated
+ sleep 5
+ kill $TOR_PID
+ wait $TOR_PID
+
+ # tor must successfully generate non-zero-length key files
+ if [ -s "$DATA_DIR"/keys/secret_id_key -a -s "$DATA_DIR"/keys/secret_onion_key -a -s "$DATA_DIR"/keys/secret_onion_key_ntor ]; then
+ true #echo "tor generated the initial key files"
+ else
+ echo "Failure: tor failed to generate the initial key files"
+ exit -2
+ fi
+fi
+
+#ls -lh "$DATA_DIR"/keys/ || exit -1
+
+# backup and keep/delete/create zero-length files for the keys
+
+FILE_DESC="keeps existing"
+# make a backup
+cp -r "$DATA_DIR"/keys "$DATA_DIR"/keys.old
+
+# delete keys for -d or -z
+if [ "$1" != "-e" ]; then
+ FILE_DESC="regenerates deleted"
+ rm "$DATA_DIR"/keys/secret_id_key || exit -1
+ rm "$DATA_DIR"/keys/secret_onion_key || exit -1
+ rm "$DATA_DIR"/keys/secret_onion_key_ntor || exit -1
+fi
+
+# create empty files for -z
+if [ "$1" = "-z" ]; then
+ FILE_DESC="regenerates zero-length"
+ touch "$DATA_DIR"/keys/secret_id_key || exit -1
+ touch "$DATA_DIR"/keys/secret_onion_key || exit -1
+ touch "$DATA_DIR"/keys/secret_onion_key_ntor || exit -1
+fi
+
+echo "Running tor again to check if it $FILE_DESC keys"
+$TOR --DataDirectory "$DATA_DIR" --PidFile "$DATA_DIR"/pid &
+TOR_PID=$!
+# generate SIGTERM, hopefully after the keys have been regenerated
+sleep 5
+kill $TOR_PID
+wait $TOR_PID
+
+#ls -lh "$DATA_DIR"/keys/ || exit -1
+
+# tor must always have non-zero-length key files
+if [ -s "$DATA_DIR"/keys/secret_id_key -a -s "$DATA_DIR"/keys/secret_onion_key -a -s "$DATA_DIR"/keys/secret_onion_key_ntor ]; then
+ # check if the keys are different to the old ones
+ diff -q -r "$DATA_DIR"/keys "$DATA_DIR"/keys.old > /dev/null
+ SAME_KEYS=$?
+ # if we're not testing existing keys,
+ # the current keys should be different to the old ones
+ if [ "$1" != "-e" ]; then
+ if [ $SAME_KEYS -ne 0 ]; then
+ echo "Success: test that tor $FILE_DESC key files: different keys"
+ exit 0
+ else
+ echo "Failure: test that tor $FILE_DESC key files: same keys"
+ exit 1
+ fi
+ else #[ "$1" == "-e" ]; then
+ if [ $SAME_KEYS -eq 0 ]; then
+ echo "Success: test that tor $FILE_DESC key files: same keys"
+ exit 0
+ else
+ echo "Failure: test that tor $FILE_DESC key files: different keys"
+ exit 1
+ fi
+ fi
+else
+ echo "Failure: test that tor $FILE_DESC key files: no key files"
+ exit 1
+fi