summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog77
-rw-r--r--Makefile.am7
-rw-r--r--changes/bug24745
-rw-r--r--changes/bug42305
-rw-r--r--changes/bug45544
-rw-r--r--changes/bug45844
-rw-r--r--changes/checkSpaces5
-rw-r--r--changes/config26
-rw-r--r--changes/disable_network9
-rw-r--r--changes/proposal1786
-rw-r--r--doc/tor.1.txt20
-rw-r--r--src/common/Makefile.am4
-rw-r--r--src/common/address.h4
-rw-r--r--src/common/aes.c208
-rw-r--r--src/common/aes.h2
-rw-r--r--src/common/compat.c59
-rw-r--r--src/common/compat.h13
-rw-r--r--src/common/compat_libevent.c54
-rw-r--r--src/common/compat_libevent.h6
-rw-r--r--src/common/container.h28
-rw-r--r--src/common/crypto.c3
-rw-r--r--src/common/tortls.c184
-rw-r--r--src/common/tortls.h5
-rw-r--r--src/common/util.c230
-rw-r--r--src/common/util.h81
-rw-r--r--src/or/Makefile.am9
-rw-r--r--src/or/config.c338
-rw-r--r--src/or/config.h8
-rw-r--r--src/or/connection.c68
-rw-r--r--src/or/connection.h3
-rw-r--r--src/or/connection_or.c42
-rw-r--r--src/or/control.c8
-rw-r--r--src/or/dirserv.c2
-rw-r--r--src/or/dirvote.c32
-rw-r--r--src/or/dirvote.h3
-rw-r--r--src/or/dns.c7
-rw-r--r--src/or/hibernate.c11
-rw-r--r--src/or/main.c57
-rw-r--r--src/or/or.h27
-rw-r--r--src/or/router.c12
-rw-r--r--src/or/router.h2
-rw-r--r--src/or/routerlist.c6
-rw-r--r--src/or/transports.c326
-rw-r--r--src/or/transports.h7
-rw-r--r--src/test/test_crypto.c33
-rw-r--r--src/test/test_dir.c76
-rw-r--r--src/test/test_pt.c2
-rw-r--r--src/test/test_util.c56
-rw-r--r--src/tools/tor-gencert.c2
49 files changed, 1640 insertions, 546 deletions
diff --git a/ChangeLog b/ChangeLog
index 4b9d9f05de..9a7d50af8d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,80 @@
+Changes in version 0.2.3.9-alpha - 2011-1?-??
+ o Major features:
+ - When using OpenSSL 1.0.0 or later, use OpenSSL's counter mode
+ implementation. It makes AES_CTR about 7% faster than our old one
+ (which was about 10% faster than the one OpenSSL used to provide).
+ Resolves ticket 4526.
+ - Tor clients and bridges can now be easily configured to use a
+ separate 'transport' proxy. This approach helps to resist
+ censorship by allowing bridges to use protocol obfuscation
+ plugins. It implements the 'managed proxy' part of proposal
+ 180. Implements ticket 3472.
+ - Block excess renegotiations even if they are RFC5746 compliant.
+ This security fix mitigates potential SSL Denial of Service attacks
+ that use SSL renegotiation as a way of forcing the server to perform
+ unneeded computationally expensive SSL handshakes. Implements
+ ticket 4312.
+
+ o Major bugfixes:
+ - Teach Tor how to notice excess renegotiation attempts before it
+ receives the first data SSL record. Fixes part of ticket 4312.
+ - Only use the EVP interface when AES acceleration is enabled,
+ to avoid a 5-7% performance regression. Resolves issue 4525;
+ bugfix on 0.2.3.8-alpha.
+
+ o Minor features:
+ - Experimental support for running on Windows with IOCP and no
+ kernel-space socket buffers. This feature is controlled by a new
+ UserspaceIOCPBuffers feature (off by default), which has no
+ effect unless Tor has been built with support for bufferevents,
+ is running on Windows, and has enabled IOCP. This may, in the
+ long run, help solve or mitigate bug 98.
+ - Try to make the introductory warning message that Tor prints on
+ startup more useful for actually finding help and information.
+ Resolves ticket 2474.
+ - Running "make version" now displays the version of Tor that
+ we're about to build. Idea from katmagic; resolves issue 4400.
+ - If set to 1, Tor will attempt to prevent basic debugging
+ attachment attempts by other processes. It has no impact for
+ users who wish to attach if they have CAP_SYS_PTRACE or if they
+ are root. We believe that this feature works on modern
+ Gnu/Linux distributions, and that it may also work on OSX and
+ some *BSD systems (untested). Some modern Gnu/Linux systems
+ such as Ubuntu have the kernel.yama.ptrace_scope sysctl and by
+ default enable it as an attempt to limit the PTRACE scope for
+ all user processes by default. This feature will attempt to
+ limit the PTRACE scope for Tor specifically - it will not
+ attempt to alter the system wide ptrace scope as it may not even
+ exist. If you wish to attach to Tor with a debugger such as gdb
+ or strace you will want to set this to 0 for the duration of
+ your debugging. Normal users should leave it on. (Default: 1)
+
+ o Minor bugfixes:
+ - Resolve an integer overflow bug in smartlist_ensure_capacity().
+ Fixes bug 4230; bugfix on Tor 0.1.0.1-rc. Based on a patch by
+ Mansour Moufid.
+ - Fix a compile warning in tor_inet_pton(). Bugfix on 0.2.3.8-alpha;
+ fixes bug 4554.
+ - Fix a minor formatting issue in one of tor-gencert's error messages.
+ Fixes bug 4574.
+ - Prevent a false positive from the check-spaces script, by disabling
+ the "whitespace between function name and (" check for functions
+ named 'op()'.
+
+ o Build fixes:
+ - Properly handle the case where the build-tree is not the same
+ as the source tree when generating src/common/common_sha1.i,
+ src/or/micro-revision.i, and src/or/or_sha1.i. Fixes bug 3953;
+ bugfix on 0.2.0.1-alpha.
+
+ o Code simplifications and refactorings:
+ - Remove the pure attribute from all functions that used it
+ previously. In many cases we assigned it incorrectly, because the
+ functions might assert or call impure functions, and we don't have
+ evidence that keeping the pure attribute is worthwhile. Implements
+ changes suggested in ticket 4421.
+
+
Changes in version 0.2.3.8-alpha - 2011-11-22
Tor 0.2.3.8-alpha fixes some crash and assert bugs, including a
socketpair-related bug that has been bothering Windows users. It adds
diff --git a/Makefile.am b/Makefile.am
index cd0d8833c6..b8d18d4c0b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -70,3 +70,10 @@ check-logs:
./contrib/checkLogs.pl \
src/*/*.[ch] | sort -n
+version:
+ @echo "Tor @VERSION@"
+ @if test -d "$(top_srcdir)/.git" && test -x "`which git 2>&1;true`"; then \
+ echo -n "git: " ;\
+ (cd "$(top_srcdir)" && git rev-parse --short=16 HEAD); \
+ fi
+
diff --git a/changes/bug2474 b/changes/bug2474
deleted file mode 100644
index 02d3eb7ba9..0000000000
--- a/changes/bug2474
+++ /dev/null
@@ -1,5 +0,0 @@
- o Minor features
- - Try to make the introductory warning message that Tor prints on
- startup more useful for actually finding help and information.
- Resolves bug2474.
-
diff --git a/changes/bug4230 b/changes/bug4230
deleted file mode 100644
index c1ba5847fc..0000000000
--- a/changes/bug4230
+++ /dev/null
@@ -1,5 +0,0 @@
- o Minor bugfixes:
- - Resolve an integer overflow bug in smartlist_ensure_capacity.
- Fixes bug 4230; bugfix on Tor 0.1.0.1-rc. Based on a patch by
- Mansour Moufid.
-
diff --git a/changes/bug4554 b/changes/bug4554
deleted file mode 100644
index e4754c29e9..0000000000
--- a/changes/bug4554
+++ /dev/null
@@ -1,4 +0,0 @@
- o Minor bugfixes:
- - Fix a compile warning in tor_inet_pton(). Bugfix on 0.2.3.8-alpha;
- fixes bug 4554.
-
diff --git a/changes/bug4584 b/changes/bug4584
new file mode 100644
index 0000000000..38cf2d6da6
--- /dev/null
+++ b/changes/bug4584
@@ -0,0 +1,4 @@
+ o Privacy/anonymity features (bridge detection):
+ - Make bridge SSL certificates a bit more stealthy by using random
+ serial numbers, in the same fashion as OpenSSL when generating
+ self-signed certificates. Implements ticket 4584.
diff --git a/changes/checkSpaces b/changes/checkSpaces
deleted file mode 100644
index 91f79ed0fa..0000000000
--- a/changes/checkSpaces
+++ /dev/null
@@ -1,5 +0,0 @@
- o Minor bugfixes:
- - Prevent a false positive from the check-spaces script by disabling
- the "whitespace between function name and (" check for functions
- named 'op()'.
-
diff --git a/changes/config b/changes/config
new file mode 100644
index 0000000000..3a1c7d113e
--- /dev/null
+++ b/changes/config
@@ -0,0 +1,26 @@
+ o Minor features
+ - Slightly change behavior of "list" options (that is, options that
+ can appear more than once) when they appear both in torrc and on
+ the command line. Previously, the command-line options would be
+ appended to the ones from torrc. Now, the command-line options
+ override the torrc options entirely. This new behavior allows
+ the user to override list options (like exit policies and
+ ports to listen on) from the command line, rather than simply
+ appending to the list.
+ - You can get the old (appending) command-line behavior for "list"
+ "list" options, by prefixing the option name with a "+".
+ - You can remove all the values for a "list" option from the command
+ line without adding any new ones by prefixing the option name
+ with a "/".
+ - Add *experimental* support for a "defaults" torrc file to be parsed
+ before the regular torrc. Torrc options override the defaults file's
+ options in the same way that the command line overrides the torrc.
+ The SAVECONF controller command saves only those options which differ
+ between the current configuration and the defaults file. HUP reloads
+ both files. (Note: This is an experimental feature; its behavior will
+ probably be refined in future 0.2.3.x-alpha versions to better meet
+ packagers' needs.)
+
+ o Minor bugfixes:
+ - Restore behavior of overriding SocksPort, ORPort, and similar
+ options from the command line. Bugfix on 0.2.3.3-alpha.
diff --git a/changes/disable_network b/changes/disable_network
new file mode 100644
index 0000000000..e6e7259ea4
--- /dev/null
+++ b/changes/disable_network
@@ -0,0 +1,9 @@
+ o Minor features:
+
+ - New "DisableNetwork" option to prevent Tor from launching any
+ connections or accepting any connections except on a control
+ port. Some bundles and controllers want to use this so they can
+ configure Tor before letting Tor talk to the rest of the
+ network--for example, to prevent any connections from being made
+ to a non-bridge address.
+
diff --git a/changes/proposal178 b/changes/proposal178
new file mode 100644
index 0000000000..ee706952ae
--- /dev/null
+++ b/changes/proposal178
@@ -0,0 +1,6 @@
+ o Major features:
+ - Implement a more secure consensus parameter voting algorithm that
+ ensures that at least three directory authorities or a majority of
+ them voted on a given parameter before including it in the
+ consensus. Implements proposal 178.
+
diff --git a/doc/tor.1.txt b/doc/tor.1.txt
index 8859c3776c..009ba412a6 100644
--- a/doc/tor.1.txt
+++ b/doc/tor.1.txt
@@ -125,6 +125,12 @@ Other options can be specified either on the command-line (--option
You probably don't need to adjust this. It has no effect on Windows
since that platform lacks getrlimit(). (Default: 1000)
+**DisableNetwork** **0**|**1**::
+ When this option is set, we don't listen for or accept any connections
+ other than controller connections, and we don't make any outbound
+ connections. Controllers sometimes use this option to avoid using
+ the network until Tor is fully configured. (Default: 0)
+
**ConstrainedSockets** **0**|**1**::
If set, Tor will tell the kernel to attempt to shrink the buffers for all
sockets to the size specified in **ConstrainedSockSize**. This is useful for
@@ -264,6 +270,20 @@ Other options can be specified either on the command-line (--option
option requires that you start your Tor as root, and you should use the
**User** option to properly reduce Tor's privileges. (Default: 0)
+**DisableDebuggerAttachment** **0**|**1**::
+ If set to 1, Tor will attempt to prevent basic debugging attachment attempts
+ by other processes. It has no impact for users who wish to attach if they
+ have CAP_SYS_PTRACE or if they are root. We believe that this feature
+ works on modern Gnu/Linux distributions, and that it may also work on *BSD
+ systems (untested). Some modern Gnu/Linux systems such as Ubuntu have the
+ kernel.yama.ptrace_scope sysctl and by default enable it as an attempt to
+ limit the PTRACE scope for all user processes by default. This feature will
+ attempt to limit the PTRACE scope for Tor specifically - it will not attempt
+ to alter the system wide ptrace scope as it may not even exist. If you wish
+ to attach to Tor with a debugger such as gdb or strace you will want to set
+ this to 0 for the duration of your debugging. Normal users should leave it
+ on. (Default: 1)
+
**FetchDirInfoEarly** **0**|**1**::
If set to 1, Tor will always fetch directory information like other
directory caches, even if you don't meet the normal criteria for fetching
diff --git a/src/common/Makefile.am b/src/common/Makefile.am
index 2244fe58d3..2920e73d2e 100644
--- a/src/common/Makefile.am
+++ b/src/common/Makefile.am
@@ -56,9 +56,9 @@ noinst_HEADERS = \
common_sha1.i: $(libor_SOURCES) $(libor_crypto_a_SOURCES) $(noinst_HEADERS)
if test "@SHA1SUM@" != none; then \
- @SHA1SUM@ $(libor_SOURCES) $(libor_crypto_a_SOURCES) $(noinst_HEADERS) | @SED@ -n 's/^\(.*\)$$/"\1\\n"/p' > common_sha1.i; \
+ (cd "$(srcdir)" && @SHA1SUM@ $(libor_SOURCES) $(libor_crypto_a_SOURCES) $(noinst_HEADERS)) | @SED@ -n 's/^\(.*\)$$/"\1\\n"/p' > common_sha1.i; \
elif test "@OPENSSL@" != none; then \
- @OPENSSL@ sha1 $(libor_SOURCES) $(libor_crypto_a_SOURCES) $(noinst_HEADERS) | @SED@ -n 's/SHA1(\(.*\))= \(.*\)/"\2 \1\\n"/p' > common_sha1.i; \
+ (cd "$(srcdir)" && @OPENSSL@ sha1 $(libor_SOURCES) $(libor_crypto_a_SOURCES) $(noinst_HEADERS)) | @SED@ -n 's/SHA1(\(.*\))= \(.*\)/"\2 \1\\n"/p' > common_sha1.i; \
else \
rm common_sha1.i; \
touch common_sha1.i; \
diff --git a/src/common/address.h b/src/common/address.h
index 359b0264d2..bc225a65ea 100644
--- a/src/common/address.h
+++ b/src/common/address.h
@@ -149,7 +149,7 @@ int tor_addr_compare_masked(const tor_addr_t *addr1, const tor_addr_t *addr2,
unsigned int tor_addr_hash(const tor_addr_t *addr);
int tor_addr_is_v4(const tor_addr_t *addr);
-int tor_addr_is_internal(const tor_addr_t *ip, int for_listening) ATTR_PURE;
+int tor_addr_is_internal(const tor_addr_t *ip, int for_listening);
/** Longest length that can be required for a reverse lookup name. */
/* 32 nybbles, 32 dots, 8 characters of "ip6.arpa", 1 NUL: 73 characters. */
@@ -185,7 +185,7 @@ int tor_addr_port_split(int severity, const char *addrport,
char **address_out, uint16_t *port_out);
/* IPv4 helpers */
-int is_internal_IP(uint32_t ip, int for_listening) ATTR_PURE;
+int is_internal_IP(uint32_t ip, int for_listening);
int addr_port_lookup(int severity, const char *addrport, char **address,
uint32_t *addr, uint16_t *port_out);
int parse_port_range(const char *port, uint16_t *port_min_out,
diff --git a/src/common/aes.c b/src/common/aes.c
index 9c03b8085c..cec6899817 100644
--- a/src/common/aes.c
+++ b/src/common/aes.c
@@ -14,34 +14,39 @@
#include <assert.h>
#include <stdlib.h>
#include <string.h>
+#include <openssl/aes.h>
+#include <openssl/evp.h>
+#include <openssl/engine.h>
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+/* See comments about which counter mode implementation to use below. */
+#include <openssl/modes.h>
+#define USE_OPENSSL_CTR
+#endif
#include "compat.h"
#include "aes.h"
#include "util.h"
#include "torlog.h"
-/* We have 2 strategies for getting AES: Via OpenSSL's AES_encrypt function,
- * via OpenSSL's EVP_EncryptUpdate function. */
-
-/** Defined iff we're using OpenSSL's AES functions for AES. */
-#undef USE_OPENSSL_AES
-/** Defined iff we're using OpenSSL's EVP code for AES. */
-#undef USE_OPENSSL_EVP
-
-/* Here we pick which to use, if none is force-defined above */
-#if (!defined(USE_OPENSSL_AES) && \
- !defined(USE_OPENSSL_EVP))
-
-#define USE_OPENSSL_EVP
-
+#ifdef ANDROID
+/* Android's OpenSSL seems to have removed all of its Engine support. */
+#define DISABLE_ENGINES
#endif
-/* Include OpenSSL headers as needed. */
-#ifdef USE_OPENSSL_AES
-# include <openssl/aes.h>
-#endif
-#ifdef USE_OPENSSL_EVP
-# include <openssl/evp.h>
-#endif
+/* We have 2 strategies for getting AES: Via OpenSSL's AES_encrypt function,
+ * via OpenSSL's EVP_EncryptUpdate function.
+ *
+ * If there's any hardware acceleration in play, we want to be using EVP_* so
+ * we can get it. Otherwise, we'll want AES_*, which seems to be about 5%
+ * faster than indirecting through the EVP layer.
+ */
+
+/* We have 2 strategies for counter mode: use our own, or use OpenSSL's.
+ *
+ * Here we have a counter mode that's faster than the one shipping with
+ * OpenSSL pre-1.0 (by about 10%!). But OpenSSL 1.0.0 added a counter mode
+ * implementation faster than the one here (by about 7%). So we pick which
+ * one to used based on the Openssl version above.
+ */
/*======================================================================*/
/* Interface to AES code, and counter implementation */
@@ -49,13 +54,12 @@
/** Implements an AES counter-mode cipher. */
struct aes_cnt_cipher {
/** This next element (however it's defined) is the AES key. */
-#if defined(USE_OPENSSL_EVP)
- EVP_CIPHER_CTX key;
-#elif defined(USE_OPENSSL_AES)
- AES_KEY key;
-#endif
+ union {
+ EVP_CIPHER_CTX evp;
+ AES_KEY aes;
+ } key;
-#if !defined(WORDS_BIGENDIAN)
+#if !defined(WORDS_BIGENDIAN) && !defined(USE_OPENSSL_CTR)
#define USING_COUNTER_VARS
/** These four values, together, implement a 128-bit counter, with
* counter0 as the low-order word and counter3 as the high-order word. */
@@ -77,9 +81,51 @@ struct aes_cnt_cipher {
/** The encrypted value of ctr_buf. */
uint8_t buf[16];
/** Our current stream position within buf. */
+#ifdef USE_OPENSSL_CTR
+ unsigned int pos;
+#else
uint8_t pos;
+#endif
+
+ /** True iff we're using the evp implementation of this cipher. */
+ uint8_t using_evp;
};
+/** True if we should prefer the EVP implementation for AES, either because
+ * we're testing it or because we have hardware acceleration configured */
+static int should_use_EVP = 0;
+
+/** Check whether we should use the EVP interface for AES. If <b>force_val</b>
+ * is nonnegative, we use use EVP iff it is true. Otherwise, we use EVP
+ * if there is an engine enabled for aes-ecb. */
+int
+evaluate_evp_for_aes(int force_val)
+{
+ ENGINE *e;
+
+ if (force_val >= 0) {
+ should_use_EVP = force_val;
+ return 0;
+ }
+#ifdef DISABLE_ENGINES
+ should_use_EVP = 0;
+#else
+ e = ENGINE_get_cipher_engine(NID_aes_128_ecb);
+
+ if (e) {
+ log_notice(LD_CRYPTO, "AES engine \"%s\" found; using EVP_* functions.",
+ ENGINE_get_name(e));
+ should_use_EVP = 1;
+ } else {
+ log_notice(LD_CRYPTO, "No AES engine found; using AES_* functions.");
+ should_use_EVP = 0;
+ }
+#endif
+
+ return 0;
+}
+
+#ifndef USE_OPENSSL_CTR
#if !defined(USING_COUNTER_VARS)
#define COUNTER(c, n) ((c)->ctr_buf.buf32[3-(n)])
#else
@@ -100,16 +146,15 @@ _aes_fill_buf(aes_cnt_cipher_t *cipher)
* None of these issues are insurmountable in principle.
*/
-#if defined(USE_OPENSSL_EVP)
- {
+ if (cipher->using_evp) {
int outl=16, inl=16;
- EVP_EncryptUpdate(&cipher->key, cipher->buf, &outl,
+ EVP_EncryptUpdate(&cipher->key.evp, cipher->buf, &outl,
cipher->ctr_buf.buf, inl);
+ } else {
+ AES_encrypt(cipher->ctr_buf.buf, cipher->buf, &cipher->key.aes);
}
-#elif defined(USE_OPENSSL_AES)
- AES_encrypt(cipher->ctr_buf.buf, cipher->buf, &cipher->key);
-#endif
}
+#endif
/**
* Return a newly allocated counter-mode AES128 cipher implementation.
@@ -129,18 +174,21 @@ aes_new_cipher(void)
void
aes_set_key(aes_cnt_cipher_t *cipher, const char *key, int key_bits)
{
-#if defined(USE_OPENSSL_EVP)
- const EVP_CIPHER *c;
- switch (key_bits) {
- case 128: c = EVP_aes_128_ecb(); break;
- case 192: c = EVP_aes_192_ecb(); break;
- case 256: c = EVP_aes_256_ecb(); break;
- default: tor_assert(0);
+ if (should_use_EVP) {
+ const EVP_CIPHER *c;
+ switch (key_bits) {
+ case 128: c = EVP_aes_128_ecb(); break;
+ case 192: c = EVP_aes_192_ecb(); break;
+ case 256: c = EVP_aes_256_ecb(); break;
+ default: tor_assert(0);
+ }
+ EVP_EncryptInit(&cipher->key.evp, c, (const unsigned char*)key, NULL);
+ cipher->using_evp = 1;
+ } else {
+ AES_set_encrypt_key((const unsigned char *)key, key_bits, &cipher->key.aes);
+ cipher->using_evp = 0;
}
- EVP_EncryptInit(&cipher->key, c, (const unsigned char*)key, NULL);
-#elif defined(USE_OPENSSL_AES)
- AES_set_encrypt_key((const unsigned char *)key, key_bits, &(cipher->key));
-#endif
+
#ifdef USING_COUNTER_VARS
cipher->counter0 = 0;
cipher->counter1 = 0;
@@ -151,7 +199,12 @@ aes_set_key(aes_cnt_cipher_t *cipher, const char *key, int key_bits)
memset(cipher->ctr_buf.buf, 0, sizeof(cipher->ctr_buf.buf));
cipher->pos = 0;
+
+#ifdef USE_OPENSSL_CTR
+ memset(cipher->buf, 0, sizeof(cipher->buf));
+#else
_aes_fill_buf(cipher);
+#endif
}
/** Release storage held by <b>cipher</b>
@@ -161,9 +214,9 @@ aes_free_cipher(aes_cnt_cipher_t *cipher)
{
if (!cipher)
return;
-#ifdef USE_OPENSSL_EVP
- EVP_CIPHER_CTX_cleanup(&cipher->key);
-#endif
+ if (cipher->using_evp) {
+ EVP_CIPHER_CTX_cleanup(&cipher->key.evp);
+ }
memset(cipher, 0, sizeof(aes_cnt_cipher_t));
tor_free(cipher);
}
@@ -176,6 +229,18 @@ aes_free_cipher(aes_cnt_cipher_t *cipher)
#define UPDATE_CTR_BUF(c, n)
#endif
+#ifdef USE_OPENSSL_CTR
+/* Helper function to use EVP with openssl's counter-mode wrapper. */
+static void evp_block128_fn(const uint8_t in[16],
+ uint8_t out[16],
+ const void *key)
+{
+ EVP_CIPHER_CTX *ctx = (void*)key;
+ int inl=16, outl=16;
+ EVP_EncryptUpdate(ctx, out, &outl, in, inl);
+}
+#endif
+
/** Encrypt <b>len</b> bytes from <b>input</b>, storing the result in
* <b>output</b>. Uses the key in <b>cipher</b>, and advances the counter
* by <b>len</b> bytes as it encrypts.
@@ -184,20 +249,29 @@ void
aes_crypt(aes_cnt_cipher_t *cipher, const char *input, size_t len,
char *output)
{
- /* This function alone is up to 5% of our runtime in some profiles; anything
- * we could do to make it faster would be great.
- *
- * Experimenting suggests that unrolling the inner loop into a switch
- * statement doesn't help. What does seem to help is making the input and
- * output buffers word aligned, and never crypting anything besides an
- * integer number of words at a time -- it shaves maybe 4-5% of the per-byte
- * encryption time measured by bench_aes. We can't do that with the current
- * Tor protocol, though: Tor really likes to crypt things in 509-byte
- * chunks.
- *
- * If we were really ambitous, we'd force len to be a multiple of the block
- * size, and shave maybe another 4-5% off.
- */
+#ifdef USE_OPENSSL_CTR
+ if (cipher->using_evp) {
+ /* In openssl 1.0.0, there's an if'd out EVP_aes_128_ctr in evp.h. If
+ * it weren't disabled, it might be better just to use that.
+ */
+ CRYPTO_ctr128_encrypt((const unsigned char *)input,
+ (unsigned char *)output,
+ len,
+ &cipher->key.evp,
+ cipher->ctr_buf.buf,
+ cipher->buf,
+ &cipher->pos,
+ evp_block128_fn);
+ } else {
+ AES_ctr128_encrypt((const unsigned char *)input,
+ (unsigned char *)output,
+ len,
+ &cipher->key.aes,
+ cipher->ctr_buf.buf,
+ cipher->buf,
+ &cipher->pos);
+ }
+#else
int c = cipher->pos;
if (PREDICT_UNLIKELY(!len)) return;
@@ -220,6 +294,7 @@ aes_crypt(aes_cnt_cipher_t *cipher, const char *input, size_t len,
UPDATE_CTR_BUF(cipher, 0);
_aes_fill_buf(cipher);
}
+#endif
}
/** Encrypt <b>len</b> bytes from <b>input</b>, storing the results in place.
@@ -229,11 +304,9 @@ aes_crypt(aes_cnt_cipher_t *cipher, const char *input, size_t len,
void
aes_crypt_inplace(aes_cnt_cipher_t *cipher, char *data, size_t len)
{
-
- /* XXXX This function is up to 5% of our runtime in some profiles;
- * we should look into unrolling some of the loops; taking advantage
- * of alignment, using a bigger buffer, and so on. Not till after 0.1.2.x,
- * though. */
+#ifdef USE_OPENSSL_CTR
+ aes_crypt(cipher, data, len, data);
+#else
int c = cipher->pos;
if (PREDICT_UNLIKELY(!len)) return;
@@ -256,6 +329,7 @@ aes_crypt_inplace(aes_cnt_cipher_t *cipher, char *data, size_t len)
UPDATE_CTR_BUF(cipher, 0);
_aes_fill_buf(cipher);
}
+#endif
}
/** Reset the 128-bit counter of <b>cipher</b> to the 16-bit big-endian value
@@ -272,6 +346,8 @@ aes_set_iv(aes_cnt_cipher_t *cipher, const char *iv)
cipher->pos = 0;
memcpy(cipher->ctr_buf.buf, iv, 16);
+#ifndef USE_OPENSSL_CTR
_aes_fill_buf(cipher);
+#endif
}
diff --git a/src/common/aes.h b/src/common/aes.h
index b2591942bc..221e846155 100644
--- a/src/common/aes.h
+++ b/src/common/aes.h
@@ -24,5 +24,7 @@ void aes_crypt(aes_cnt_cipher_t *cipher, const char *input, size_t len,
void aes_crypt_inplace(aes_cnt_cipher_t *cipher, char *data, size_t len);
void aes_set_iv(aes_cnt_cipher_t *cipher, const char *iv);
+int evaluate_evp_for_aes(int force_value);
+
#endif
diff --git a/src/common/compat.c b/src/common/compat.c
index 9a2c9d764b..ea95f9f085 100644
--- a/src/common/compat.c
+++ b/src/common/compat.c
@@ -58,6 +58,14 @@
#endif
#endif
+/* Includes for the process attaching prevention */
+#if defined(HAVE_SYS_PRCTL_H) && defined(__linux__)
+#include <sys/prctl.h>
+#elif defined(__APPLE__)
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#endif
+
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
@@ -1519,6 +1527,57 @@ switch_id(const char *user)
#endif
}
+/* We only use the linux prctl for now. There is no Win32 support; this may
+ * also work on various BSD systems and Mac OS X - send testing feedback!
+ *
+ * On recent Gnu/Linux kernels it is possible to create a system-wide policy
+ * that will prevent non-root processes from attaching to other processes
+ * unless they are the parent process; thus gdb can attach to programs that
+ * they execute but they cannot attach to other processes running as the same
+ * user. The system wide policy may be set with the sysctl
+ * kernel.yama.ptrace_scope or by inspecting
+ * /proc/sys/kernel/yama/ptrace_scope and it is 1 by default on Ubuntu 11.04.
+ *
+ * This ptrace scope will be ignored on Gnu/Linux for users with
+ * CAP_SYS_PTRACE and so it is very likely that root will still be able to
+ * attach to the Tor process.
+ */
+/** Attempt to disable debugger attachment: return 0 on success, -1 on
+ * failure. */
+int
+tor_disable_debugger_attach(void)
+{
+ int r, attempted;
+ r = -1;
+ attempted = 0;
+ log_debug(LD_CONFIG,
+ "Attemping to disable debugger attachment to Tor for "
+ "unprivileged users.");
+#if defined(__linux__) && defined(HAVE_SYS_PRCTL_H) && defined(HAVE_PRCTL)
+#ifdef PR_SET_DUMPABLE
+ attempted = 1;
+ r = prctl(PR_SET_DUMPABLE, 0);
+#endif
+#endif
+#if defined(__APPLE__) && defined(PT_DENY_ATTACH)
+ if (r < 0) {
+ attempted = 1;
+ r = ptrace(PT_DENY_ATTACH, 0, 0, 0);
+ }
+#endif
+
+ // XXX: TODO - Mac OS X has dtrace and this may be disabled.
+ // XXX: TODO - Windows probably has something similar
+ if (r == 0) {
+ log_debug(LD_CONFIG,"Debugger attachment disabled for "
+ "unprivileged users.");
+ } else if (attempted) {
+ log_warn(LD_CONFIG, "Unable to disable ptrace attach: %s",
+ strerror(errno));
+ }
+ return r;
+}
+
#ifdef HAVE_PWD_H
/** Allocate and return a string containing the home directory for the
* user <b>username</b>. Only works on posix-like systems. */
diff --git a/src/common/compat.h b/src/common/compat.h
index b005dd2974..db541623d3 100644
--- a/src/common/compat.h
+++ b/src/common/compat.h
@@ -135,7 +135,6 @@ extern INLINE double U64_TO_DBL(uint64_t x) {
/* GCC has several useful attributes. */
#if defined(__GNUC__) && __GNUC__ >= 3
#define ATTR_NORETURN __attribute__((noreturn))
-#define ATTR_PURE __attribute__((pure))
#define ATTR_CONST __attribute__((const))
#define ATTR_MALLOC __attribute__((malloc))
#define ATTR_NORETURN __attribute__((noreturn))
@@ -168,7 +167,6 @@ extern INLINE double U64_TO_DBL(uint64_t x) {
#define PREDICT_UNLIKELY(exp) __builtin_expect(!!(exp), 0)
#else
#define ATTR_NORETURN
-#define ATTR_PURE
#define ATTR_CONST
#define ATTR_MALLOC
#define ATTR_NORETURN
@@ -271,9 +269,9 @@ int tor_asprintf(char **strp, const char *fmt, ...)
int tor_vasprintf(char **strp, const char *fmt, va_list args);
const void *tor_memmem(const void *haystack, size_t hlen, const void *needle,
- size_t nlen) ATTR_PURE ATTR_NONNULL((1,3));
+ size_t nlen) ATTR_NONNULL((1,3));
static const void *tor_memstr(const void *haystack, size_t hlen,
- const char *needle) ATTR_PURE ATTR_NONNULL((1,3));
+ const char *needle) ATTR_NONNULL((1,3));
static INLINE const void *
tor_memstr(const void *haystack, size_t hlen, const char *needle)
{
@@ -546,9 +544,9 @@ long tor_weak_random(void);
/* ===== OS compatibility */
const char *get_uname(void);
-uint16_t get_uint16(const void *cp) ATTR_PURE ATTR_NONNULL((1));
-uint32_t get_uint32(const void *cp) ATTR_PURE ATTR_NONNULL((1));
-uint64_t get_uint64(const void *cp) ATTR_PURE ATTR_NONNULL((1));
+uint16_t get_uint16(const void *cp) ATTR_NONNULL((1));
+uint32_t get_uint32(const void *cp) ATTR_NONNULL((1));
+uint64_t get_uint64(const void *cp) ATTR_NONNULL((1));
void set_uint16(void *cp, uint16_t v) ATTR_NONNULL((1));
void set_uint32(void *cp, uint32_t v) ATTR_NONNULL((1));
void set_uint64(void *cp, uint64_t v) ATTR_NONNULL((1));
@@ -566,6 +564,7 @@ set_uint8(void *cp, uint8_t v)
typedef unsigned long rlim_t;
#endif
int set_max_file_descriptors(rlim_t limit, int *max);
+int tor_disable_debugger_attach(void);
int switch_id(const char *user);
#ifdef HAVE_PWD_H
char *get_user_homedir(const char *username);
diff --git a/src/common/compat_libevent.c b/src/common/compat_libevent.c
index 0cedef8d5e..67f465927c 100644
--- a/src/common/compat_libevent.c
+++ b/src/common/compat_libevent.c
@@ -558,6 +558,60 @@ tor_check_libevent_header_compatibility(void)
#endif
}
+struct tor_libevent_action_t {
+ struct event *ev;
+ void (*cb)(void *arg);
+ void *arg;
+};
+
+/** Callback for tor_run_in_libevent_loop */
+static void
+run_runnable_cb(evutil_socket_t s, short what, void *arg)
+{
+ tor_libevent_action_t *r = arg;
+ void (*cb)(void *) = r->cb;
+ void *cb_arg = r->arg;
+ (void)what;
+ (void)s;
+ tor_event_free(r->ev);
+ tor_free(r);
+
+ cb(cb_arg);
+}
+
+/** Cause cb(arg) to run later on this iteration of the libevent loop, or in
+ * the next iteration of the libevent loop. This is useful for when you're
+ * deep inside a no-reentrant code and there's some function you want to call
+ * without worrying about whether it might cause reeentrant invocation.
+ */
+tor_libevent_action_t *
+tor_run_in_libevent_loop(void (*cb)(void *arg), void *arg)
+{
+ tor_libevent_action_t *r = tor_malloc(sizeof(tor_libevent_action_t));
+ r->cb = cb;
+ r->arg = arg;
+ r->ev = tor_event_new(tor_libevent_get_base(), -1, EV_TIMEOUT,
+ run_runnable_cb, r);
+ if (!r->ev) {
+ tor_free(r);
+ return NULL;
+ }
+ /* Make the event active immediately. */
+ event_active(r->ev, EV_TIMEOUT, 1);
+
+ return r;
+}
+
+/**
+ * Cancel <b>action</b> without running it.
+ */
+void
+tor_cancel_libevent_action(tor_libevent_action_t *action)
+{
+ tor_event_free(action->ev);
+ tor_free(action);
+}
+
/*
If possible, we're going to try to use Libevent's periodic timer support,
since it does a pretty good job of making sure that periodic events get
diff --git a/src/common/compat_libevent.h b/src/common/compat_libevent.h
index 0247297177..4076cc0e08 100644
--- a/src/common/compat_libevent.h
+++ b/src/common/compat_libevent.h
@@ -44,8 +44,12 @@ void tor_event_free(struct event *ev);
#define tor_evdns_add_server_port evdns_add_server_port
#endif
-typedef struct periodic_timer_t periodic_timer_t;
+typedef struct tor_libevent_action_t tor_libevent_action_t;
+tor_libevent_action_t *tor_run_in_libevent_loop(void (*cb)(void *arg),
+ void *arg);
+void tor_cancel_libevent_action(tor_libevent_action_t *action);
+typedef struct periodic_timer_t periodic_timer_t;
periodic_timer_t *periodic_timer_new(struct event_base *base,
const struct timeval *tv,
void (*cb)(periodic_timer_t *timer, void *data),
diff --git a/src/common/container.h b/src/common/container.h
index 4a6eba789d..fe071cc1b3 100644
--- a/src/common/container.h
+++ b/src/common/container.h
@@ -35,19 +35,14 @@ void smartlist_remove(smartlist_t *sl, const void *element);
void *smartlist_pop_last(smartlist_t *sl);
void smartlist_reverse(smartlist_t *sl);
void smartlist_string_remove(smartlist_t *sl, const char *element);
-int smartlist_isin(const smartlist_t *sl, const void *element) ATTR_PURE;
-int smartlist_string_isin(const smartlist_t *sl, const char *element)
- ATTR_PURE;
-int smartlist_string_pos(const smartlist_t *, const char *elt) ATTR_PURE;
-int smartlist_string_isin_case(const smartlist_t *sl, const char *element)
- ATTR_PURE;
-int smartlist_string_num_isin(const smartlist_t *sl, int num) ATTR_PURE;
-int smartlist_strings_eq(const smartlist_t *sl1, const smartlist_t *sl2)
- ATTR_PURE;
-int smartlist_digest_isin(const smartlist_t *sl, const char *element)
- ATTR_PURE;
-int smartlist_overlap(const smartlist_t *sl1, const smartlist_t *sl2)
- ATTR_PURE;
+int smartlist_isin(const smartlist_t *sl, const void *element);
+int smartlist_string_isin(const smartlist_t *sl, const char *element);
+int smartlist_string_pos(const smartlist_t *, const char *elt);
+int smartlist_string_isin_case(const smartlist_t *sl, const char *element);
+int smartlist_string_num_isin(const smartlist_t *sl, int num);
+int smartlist_strings_eq(const smartlist_t *sl1, const smartlist_t *sl2);
+int smartlist_digest_isin(const smartlist_t *sl, const char *element);
+int smartlist_overlap(const smartlist_t *sl1, const smartlist_t *sl2);
void smartlist_intersect(smartlist_t *sl1, const smartlist_t *sl2);
void smartlist_subtract(smartlist_t *sl1, const smartlist_t *sl2);
@@ -55,14 +50,14 @@ void smartlist_subtract(smartlist_t *sl1, const smartlist_t *sl2);
#ifdef DEBUG_SMARTLIST
/** Return the number of items in sl.
*/
-static INLINE int smartlist_len(const smartlist_t *sl) ATTR_PURE;
+static INLINE int smartlist_len(const smartlist_t *sl);
static INLINE int smartlist_len(const smartlist_t *sl) {
tor_assert(sl);
return (sl)->num_used;
}
/** Return the <b>idx</b>th element of sl.
*/
-static INLINE void *smartlist_get(const smartlist_t *sl, int idx) ATTR_PURE;
+static INLINE void *smartlist_get(const smartlist_t *sl, int idx);
static INLINE void *smartlist_get(const smartlist_t *sl, int idx) {
tor_assert(sl);
tor_assert(idx>=0);
@@ -114,8 +109,7 @@ void smartlist_uniq_strings(smartlist_t *sl);
void smartlist_uniq_digests(smartlist_t *sl);
void smartlist_uniq_digests256(smartlist_t *sl);
void *smartlist_bsearch(smartlist_t *sl, const void *key,
- int (*compare)(const void *key, const void **member))
- ATTR_PURE;
+ int (*compare)(const void *key, const void **member));
int smartlist_bsearch_idx(const smartlist_t *sl, const void *key,
int (*compare)(const void *key, const void **member),
int *found_out);
diff --git a/src/common/crypto.c b/src/common/crypto.c
index a38956d3e8..ebaa0122fd 100644
--- a/src/common/crypto.c
+++ b/src/common/crypto.c
@@ -276,6 +276,9 @@ crypto_global_init(int useAccel, const char *accelName, const char *accelDir)
} else {
log_info(LD_CRYPTO, "NOT using OpenSSL engine support.");
}
+
+ evaluate_evp_for_aes(-1);
+
return crypto_seed_rng(1);
}
return 0;
diff --git a/src/common/tortls.c b/src/common/tortls.c
index 554deb7bda..a6947c87d8 100644
--- a/src/common/tortls.c
+++ b/src/common/tortls.c
@@ -52,7 +52,6 @@
#include <event2/bufferevent_ssl.h>
#include <event2/buffer.h>
#include <event2/event.h>
-#include "compat_libevent.h"
#endif
#define CRYPTO_PRIVATE /* to import prototypes from crypto.h */
@@ -64,6 +63,7 @@
#include "torlog.h"
#include "container.h"
#include <string.h>
+#include "compat_libevent.h"
/* Enable the "v2" TLS handshake.
*/
@@ -146,7 +146,7 @@ struct tor_tls_t {
/** True iff we should call negotiated_callback when we're done reading. */
unsigned int got_renegotiate:1;
/** Incremented every time we start the server side of a handshake. */
- uint8_t server_handshake_count;
+ unsigned int server_handshake_count:2;
size_t wantwrite_n; /**< 0 normally, >0 if we returned wantwrite last
* time. */
/** Last values retrieved from BIO_number_read()/write(); see
@@ -157,6 +157,11 @@ struct tor_tls_t {
/** If set, a callback to invoke whenever the client tries to renegotiate
* the handshake. */
void (*negotiated_callback)(tor_tls_t *tls, void *arg);
+
+ /** Callback to invoke whenever a client tries to renegotiate more
+ than once. */
+ void (*excess_renegotiations_callback)(void *);
+
/** Argument to pass to negotiated_callback. */
void *callback_arg;
};
@@ -580,7 +585,13 @@ tor_tls_create_certificate(crypto_pk_env_t *rsa,
const char *cname_sign,
unsigned int cert_lifetime)
{
+ /* OpenSSL generates self-signed certificates with random 64-bit serial
+ * numbers, so let's do that too. */
+#define SERIAL_NUMBER_SIZE 8
+
time_t start_time, end_time;
+ BIGNUM *serial_number = NULL;
+ unsigned char serial_tmp[SERIAL_NUMBER_SIZE];
EVP_PKEY *sign_pkey = NULL, *pkey=NULL;
X509 *x509 = NULL;
X509_NAME *name = NULL, *name_issuer=NULL;
@@ -601,8 +612,15 @@ tor_tls_create_certificate(crypto_pk_env_t *rsa,
goto error;
if (!(X509_set_version(x509, 2)))
goto error;
- if (!(ASN1_INTEGER_set(X509_get_serialNumber(x509), (long)start_time)))
- goto error;
+
+ { /* our serial number is 8 random bytes. */
+ if (crypto_rand((char *)serial_tmp, sizeof(serial_tmp)) < 0)
+ goto error;
+ if (!(serial_number = BN_bin2bn(serial_tmp, sizeof(serial_tmp), NULL)))
+ goto error;
+ if (!(BN_to_ASN1_INTEGER(serial_number, X509_get_serialNumber(x509))))
+ goto error;
+ }
if (!(name = tor_x509_name_new(cname)))
goto error;
@@ -635,11 +653,15 @@ tor_tls_create_certificate(crypto_pk_env_t *rsa,
EVP_PKEY_free(sign_pkey);
if (pkey)
EVP_PKEY_free(pkey);
+ if (serial_number)
+ BN_free(serial_number);
if (name)
X509_NAME_free(name);
if (name_issuer)
X509_NAME_free(name_issuer);
return x509;
+
+#undef SERIAL_NUMBER_SIZE
}
/** List of ciphers that servers should select from.*/
@@ -1297,55 +1319,42 @@ tor_tls_client_is_using_v2_ciphers(const SSL *ssl, const char *address)
return 1;
}
+/** We got an SSL ClientHello message. This might mean that the
+ * client wants to initiate a renegotiation and appropriate actions
+ * must be taken. */
static void
-tor_tls_debug_state_callback(const SSL *ssl, int type, int val)
-{
- log_debug(LD_HANDSHAKE, "SSL %p is now in state %s [type=%d,val=%d].",
- ssl, ssl_state_to_string(ssl->state), type, val);
-}
-
-/** Invoked when we're accepting a connection on <b>ssl</b>, and the connection
- * changes state. We use this:
- * <ul><li>To alter the state of the handshake partway through, so we
- * do not send or request extra certificates in v2 handshakes.</li>
- * <li>To detect renegotiation</li></ul>
- */
-static void
-tor_tls_server_info_callback(const SSL *ssl, int type, int val)
+tor_tls_got_client_hello(tor_tls_t *tls)
{
- tor_tls_t *tls;
- (void) val;
+ if (tls->server_handshake_count < 3)
+ ++tls->server_handshake_count;
- tor_tls_debug_state_callback(ssl, type, val);
+ if (tls->server_handshake_count == 2) {
+ if (!tls->negotiated_callback) {
+ log_warn(LD_BUG, "Got a renegotiation request but we don't"
+ " have a renegotiation callback set!");
+ }
- if (type != SSL_CB_ACCEPT_LOOP)
- return;
- if (ssl->state != SSL3_ST_SW_SRVR_HELLO_A)
- return;
+ tls->got_renegotiate = 1;
+ } else if (tls->server_handshake_count > 2 &&
+ tls->excess_renegotiations_callback) {
+ /* We got more than one renegotiation requests. The Tor protocol
+ needs just one renegotiation; more than that probably means
+ They are trying to DoS us and we have to stop them. */
- tls = tor_tls_get_by_ssl(ssl);
- if (tls) {
- /* Check whether we're watching for renegotiates. If so, this is one! */
- if (tls->negotiated_callback)
- tls->got_renegotiate = 1;
- if (tls->server_handshake_count < 127) /*avoid any overflow possibility*/
- ++tls->server_handshake_count;
- } else {
- log_warn(LD_BUG, "Couldn't look up the tls for an SSL*. How odd!");
- return;
+ tls->excess_renegotiations_callback(tls->callback_arg);
}
/* Now check the cipher list. */
- if (tor_tls_client_is_using_v2_ciphers(ssl, ADDR(tls))) {
+ if (tor_tls_client_is_using_v2_ciphers(tls->ssl, ADDR(tls))) {
/*XXXX_TLS keep this from happening more than once! */
/* Yes, we're casting away the const from ssl. This is very naughty of us.
* Let's hope openssl doesn't notice! */
/* Set SSL_MODE_NO_AUTO_CHAIN to keep from sending back any extra certs. */
- SSL_set_mode((SSL*) ssl, SSL_MODE_NO_AUTO_CHAIN);
+ SSL_set_mode((SSL*) tls->ssl, SSL_MODE_NO_AUTO_CHAIN);
/* Don't send a hello request. */
- SSL_set_verify((SSL*) ssl, SSL_VERIFY_NONE, NULL);
+ SSL_set_verify((SSL*) tls->ssl, SSL_VERIFY_NONE, NULL);
if (tls) {
tls->wasV2Handshake = 1;
@@ -1360,6 +1369,34 @@ tor_tls_server_info_callback(const SSL *ssl, int type, int val)
}
#endif
+/** This is a callback function for SSL_set_info_callback() and it
+ * will be called in every SSL state change.
+ * It logs the SSL state change, and executes any actions that must be
+ * taken. */
+static void
+tor_tls_state_changed_callback(const SSL *ssl, int type, int val)
+{
+ log_debug(LD_HANDSHAKE, "SSL %p is now in state %s [type=%d,val=%d].",
+ ssl, ssl_state_to_string(ssl->state), type, val);
+
+#ifdef V2_HANDSHAKE_SERVER
+ if (type == SSL_CB_ACCEPT_LOOP &&
+ ssl->state == SSL3_ST_SW_SRVR_HELLO_A) {
+
+ /* Call tor_tls_got_client_hello() for every SSL ClientHello we
+ receive. */
+
+ tor_tls_t *tls = tor_tls_get_by_ssl(ssl);
+ if (!tls) {
+ log_warn(LD_BUG, "Couldn't look up the tls for an SSL*. How odd!");
+ return;
+ }
+
+ tor_tls_got_client_hello(tls);
+ }
+#endif
+}
+
/** Replace *<b>ciphers</b> with a new list of SSL ciphersuites: specifically,
* a list designed to mimic a common web browser. Some of the ciphers in the
* list won't actually be implemented by OpenSSL: that's okay so long as the
@@ -1501,14 +1538,8 @@ tor_tls_new(int sock, int isServer)
log_warn(LD_NET, "Newly created BIO has read count %lu, write count %lu",
result->last_read_count, result->last_write_count);
}
-#ifdef V2_HANDSHAKE_SERVER
- if (isServer) {
- SSL_set_info_callback(result->ssl, tor_tls_server_info_callback);
- } else
-#endif
- {
- SSL_set_info_callback(result->ssl, tor_tls_debug_state_callback);
- }
+
+ SSL_set_info_callback(result->ssl, tor_tls_state_changed_callback);
/* Not expected to get called. */
tls_log_errors(NULL, LOG_WARN, LD_NET, "creating tor_tls_t object");
@@ -1526,25 +1557,23 @@ tor_tls_set_logged_address(tor_tls_t *tls, const char *address)
tls->address = tor_strdup(address);
}
-/** Set <b>cb</b> to be called with argument <b>arg</b> whenever <b>tls</b>
- * next gets a client-side renegotiate in the middle of a read. Do not
- * invoke this function until <em>after</em> initial handshaking is done!
+/** Set <b>cb</b> to be called with argument <b>arg</b> whenever
+ * <b>tls</b> next gets a client-side renegotiate in the middle of a
+ * read. Set <b>cb2</b> to be called with argument <b>arg</b> whenever
+ * <b>tls</b> gets excess renegotiation requests. Do not invoke this
+ * function until <em>after</em> initial handshaking is done!
*/
void
-tor_tls_set_renegotiate_callback(tor_tls_t *tls,
+tor_tls_set_renegotiate_callbacks(tor_tls_t *tls,
void (*cb)(tor_tls_t *, void *arg),
+ void (*cb2)(void *),
void *arg)
{
tls->negotiated_callback = cb;
+ tls->excess_renegotiations_callback = cb2;
tls->callback_arg = arg;
tls->got_renegotiate = 0;
-#ifdef V2_HANDSHAKE_SERVER
- if (cb) {
- SSL_set_info_callback(tls->ssl, tor_tls_server_info_callback);
- } else {
- SSL_set_info_callback(tls->ssl, tor_tls_debug_state_callback);
- }
-#endif
+ SSL_set_info_callback(tls->ssl, tor_tls_state_changed_callback);
}
/** If this version of openssl requires it, turn on renegotiation on
@@ -1564,16 +1593,6 @@ tor_tls_unblock_renegotiation(tor_tls_t *tls)
}
}
-/** If this version of openssl supports it, turn off renegotiation on
- * <b>tls</b>. (Our protocol never requires this for security, but it's nice
- * to use belt-and-suspenders here.)
- */
-void
-tor_tls_block_renegotiation(tor_tls_t *tls)
-{
- tls->ssl->s3->flags &= ~SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION;
-}
-
void
tor_tls_assert_renegotiation_unblocked(tor_tls_t *tls)
{
@@ -1611,6 +1630,7 @@ tor_tls_free(tor_tls_t *tls)
SSL_free(tls->ssl);
tls->ssl = NULL;
tls->negotiated_callback = NULL;
+ tls->excess_renegotiations_callback = NULL;
if (tls->context)
tor_tls_context_decref(tls->context);
tor_free(tls->address);
@@ -1632,19 +1652,30 @@ tor_tls_read(tor_tls_t *tls, char *cp, size_t len)
tor_assert(tls->state == TOR_TLS_ST_OPEN);
tor_assert(len<INT_MAX);
r = SSL_read(tls->ssl, cp, (int)len);
- if (r > 0) {
+ if (r > 0) /* return the number of characters read */
+ return r;
+
+ /* If we got here, SSL_read() did not go as expected. */
+
+ err = tor_tls_get_error(tls, r, CATCH_ZERO, "reading", LOG_DEBUG, LD_NET);
+
#ifdef V2_HANDSHAKE_SERVER
- if (tls->got_renegotiate) {
- /* Renegotiation happened! */
- log_info(LD_NET, "Got a TLS renegotiation from %s", ADDR(tls));
- if (tls->negotiated_callback)
- tls->negotiated_callback(tls, tls->callback_arg);
- tls->got_renegotiate = 0;
+ if (tls->got_renegotiate) {
+ if (tls->server_handshake_count != 2) {
+ log_warn(LD_BUG, "We did not notice renegotiation in a timely "
+ "fashion (%u)!", tls->server_handshake_count);
}
-#endif
+
+ /* Renegotiation happened! */
+ log_info(LD_NET, "Got a TLS renegotiation from %s", ADDR(tls));
+ if (tls->negotiated_callback)
+ tls->negotiated_callback(tls, tls->callback_arg);
+ tls->got_renegotiate = 0;
+
return r;
}
- err = tor_tls_get_error(tls, r, CATCH_ZERO, "reading", LOG_DEBUG, LD_NET);
+#endif
+
if (err == _TOR_TLS_ZERORETURN || err == TOR_TLS_CLOSE) {
log_debug(LD_NET,"read returned r=%d; TLS is closed",r);
tls->state = TOR_TLS_ST_CLOSED;
@@ -1681,6 +1712,7 @@ tor_tls_write(tor_tls_t *tls, const char *cp, size_t n)
}
r = SSL_write(tls->ssl, cp, (int)n);
err = tor_tls_get_error(tls, r, 0, "writing", LOG_INFO, LD_NET);
+
if (err == TOR_TLS_DONE) {
return r;
}
diff --git a/src/common/tortls.h b/src/common/tortls.h
index 673f18dfe8..9f86e37127 100644
--- a/src/common/tortls.h
+++ b/src/common/tortls.h
@@ -13,6 +13,7 @@
#include "crypto.h"
#include "compat.h"
+#include "compat_libevent.h"
/* Opaque structure to hold a TLS connection. */
typedef struct tor_tls_t tor_tls_t;
@@ -60,8 +61,9 @@ int tor_tls_context_init(int is_public_server,
unsigned int key_lifetime);
tor_tls_t *tor_tls_new(int sock, int is_server);
void tor_tls_set_logged_address(tor_tls_t *tls, const char *address);
-void tor_tls_set_renegotiate_callback(tor_tls_t *tls,
+void tor_tls_set_renegotiate_callbacks(tor_tls_t *tls,
void (*cb)(tor_tls_t *, void *arg),
+ void (*cb2)(void *),
void *arg);
int tor_tls_is_server(tor_tls_t *tls);
void tor_tls_free(tor_tls_t *tls);
@@ -77,7 +79,6 @@ int tor_tls_handshake(tor_tls_t *tls);
int tor_tls_finish_handshake(tor_tls_t *tls);
int tor_tls_renegotiate(tor_tls_t *tls);
void tor_tls_unblock_renegotiation(tor_tls_t *tls);
-void tor_tls_block_renegotiation(tor_tls_t *tls);
void tor_tls_assert_renegotiation_unblocked(tor_tls_t *tls);
int tor_tls_shutdown(tor_tls_t *tls);
int tor_tls_get_pending_bytes(tor_tls_t *tls);
diff --git a/src/common/util.c b/src/common/util.c
index c19e4d20ca..6d488d9963 100644
--- a/src/common/util.c
+++ b/src/common/util.c
@@ -3173,28 +3173,72 @@ format_helper_exit_status(unsigned char child_state, int saved_errno,
/* Maximum number of file descriptors, if we cannot get it via sysconf() */
#define DEFAULT_MAX_FD 256
-/** Terminate process running at PID <b>pid</b>.
+/** Terminate the process of <b>process_handle</b>.
* Code borrowed from Python's os.kill. */
int
-tor_terminate_process(pid_t pid)
+tor_terminate_process(process_handle_t *process_handle)
{
#ifdef MS_WINDOWS
- HANDLE handle;
- /* If the signal is outside of what GenerateConsoleCtrlEvent can use,
- attempt to open and terminate the process. */
- handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
- if (!handle)
- return -1;
+ if (tor_get_exit_code(process_handle, 0, NULL) == PROCESS_EXIT_RUNNING) {
+ HANDLE handle;
+ /* If the signal is outside of what GenerateConsoleCtrlEvent can use,
+ attempt to open and terminate the process. */
+ handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE,
+ process_handle->pid.dwProcessId);
+ if (!handle)
+ return -1;
- if (!TerminateProcess(handle, 0))
- return -1;
- else
- return 0;
+ if (!TerminateProcess(handle, 0))
+ return -1;
+ else
+ return 0;
+ }
#else /* Unix */
- return kill(pid, SIGTERM);
+ return kill(process_handle->pid, SIGTERM);
+#endif
+
+ return -1;
+}
+
+/** Return the Process ID of <b>process_handle</b>. */
+int
+tor_process_get_pid(process_handle_t *process_handle)
+{
+#ifdef MS_WINDOWS
+ return (int) process_handle->pid.dwProcessId;
+#else
+ return (int) process_handle->pid;
+#endif
+}
+
+#ifdef MS_WINDOWS
+HANDLE
+tor_process_get_stdout_pipe(process_handle_t *process_handle)
+{
+ return process_handle->stdout_pipe;
+}
+#else
+FILE *
+tor_process_get_stdout_pipe(process_handle_t *process_handle)
+{
+ return process_handle->stdout_handle;
+}
+#endif
+
+static process_handle_t *
+process_handle_new(void)
+{
+ process_handle_t *out = tor_malloc_zero(sizeof(process_handle_t));
+
+#ifndef MS_WINDOWS
+ out->stdout_pipe = -1;
+ out->stderr_pipe = -1;
#endif
+
+ return out;
}
+/*DOCDOC*/
#define CHILD_STATE_INIT 0
#define CHILD_STATE_PIPE 1
#define CHILD_STATE_MAXFD 2
@@ -3227,14 +3271,20 @@ tor_terminate_process(pid_t pid)
*/
int
tor_spawn_background(const char *const filename, const char **argv,
+#ifdef MS_WINDOWS
+ LPVOID envp,
+#else
const char **envp,
- process_handle_t *process_handle)
+#endif
+ process_handle_t **process_handle_out)
{
#ifdef MS_WINDOWS
HANDLE stdout_pipe_read = NULL;
HANDLE stdout_pipe_write = NULL;
HANDLE stderr_pipe_read = NULL;
HANDLE stderr_pipe_write = NULL;
+ process_handle_t *process_handle;
+ int status;
STARTUPINFO siStartInfo;
BOOL retval = FALSE;
@@ -3244,30 +3294,26 @@ tor_spawn_background(const char *const filename, const char **argv,
(void)envp; // Unused on Windows
- /* process_handle must not be NULL */
- tor_assert(process_handle != NULL);
-
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
/* TODO: should we set explicit security attributes? (#2046, comment 5) */
saAttr.lpSecurityDescriptor = NULL;
/* Assume failure to start process */
- memset(process_handle, 0, sizeof(process_handle_t));
- process_handle->status = PROCESS_STATUS_ERROR;
+ status = PROCESS_STATUS_ERROR;
/* Set up pipe for stdout */
if (!CreatePipe(&stdout_pipe_read, &stdout_pipe_write, &saAttr, 0)) {
log_warn(LD_GENERAL,
"Failed to create pipe for stdout communication with child process: %s",
format_win32_error(GetLastError()));
- return process_handle->status;
+ return status;
}
if (!SetHandleInformation(stdout_pipe_read, HANDLE_FLAG_INHERIT, 0)) {
log_warn(LD_GENERAL,
"Failed to configure pipe for stdout communication with child "
"process: %s", format_win32_error(GetLastError()));
- return process_handle->status;
+ return status;
}
/* Set up pipe for stderr */
@@ -3275,13 +3321,13 @@ tor_spawn_background(const char *const filename, const char **argv,
log_warn(LD_GENERAL,
"Failed to create pipe for stderr communication with child process: %s",
format_win32_error(GetLastError()));
- return process_handle->status;
+ return status;
}
if (!SetHandleInformation(stderr_pipe_read, HANDLE_FLAG_INHERIT, 0)) {
log_warn(LD_GENERAL,
"Failed to configure pipe for stderr communication with child "
"process: %s", format_win32_error(GetLastError()));
- return process_handle->status;
+ return status;
}
/* Create the child process */
@@ -3290,6 +3336,9 @@ tor_spawn_background(const char *const filename, const char **argv,
*/
joined_argv = tor_join_win_cmdline(argv);
+ process_handle = process_handle_new();
+ process_handle->status = status;
+
ZeroMemory(&(process_handle->pid), sizeof(PROCESS_INFORMATION));
ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
siStartInfo.cb = sizeof(STARTUPINFO);
@@ -3309,7 +3358,7 @@ tor_spawn_background(const char *const filename, const char **argv,
/*(TODO: set CREATE_NEW CONSOLE/PROCESS_GROUP to make GetExitCodeProcess()
* work?) */
0, // creation flags
- NULL, // use parent's environment
+ envp, // use parent's environment
NULL, // use parent's current directory
&siStartInfo, // STARTUPINFO pointer
&(process_handle->pid)); // receives PROCESS_INFORMATION
@@ -3320,22 +3369,25 @@ tor_spawn_background(const char *const filename, const char **argv,
log_warn(LD_GENERAL,
"Failed to create child process %s: %s", filename?filename:argv[0],
format_win32_error(GetLastError()));
+ tor_free(process_handle);
} else {
/* TODO: Close hProcess and hThread in process_handle->pid? */
process_handle->stdout_pipe = stdout_pipe_read;
process_handle->stderr_pipe = stderr_pipe_read;
- process_handle->status = PROCESS_STATUS_RUNNING;
+ status = process_handle->status = PROCESS_STATUS_RUNNING;
}
/* TODO: Close pipes on exit */
-
- return process_handle->status;
+ *process_handle_out = process_handle;
+ return status;
#else // MS_WINDOWS
pid_t pid;
int stdout_pipe[2];
int stderr_pipe[2];
int fd, retval;
ssize_t nbytes;
+ process_handle_t *process_handle;
+ int status;
const char *error_message = SPAWN_ERROR_MESSAGE;
size_t error_message_length;
@@ -3348,9 +3400,7 @@ tor_spawn_background(const char *const filename, const char **argv,
static int max_fd = -1;
- /* Assume failure to start */
- memset(process_handle, 0, sizeof(process_handle_t));
- process_handle->status = PROCESS_STATUS_ERROR;
+ status = PROCESS_STATUS_ERROR;
/* We do the strlen here because strlen() is not signal handler safe,
and we are not allowed to use unsafe functions between fork and exec */
@@ -3364,7 +3414,7 @@ tor_spawn_background(const char *const filename, const char **argv,
log_warn(LD_GENERAL,
"Failed to set up pipe for stdout communication with child process: %s",
strerror(errno));
- return process_handle->status;
+ return status;
}
retval = pipe(stderr_pipe);
@@ -3372,7 +3422,7 @@ tor_spawn_background(const char *const filename, const char **argv,
log_warn(LD_GENERAL,
"Failed to set up pipe for stderr communication with child process: %s",
strerror(errno));
- return process_handle->status;
+ return status;
}
child_state = CHILD_STATE_MAXFD;
@@ -3462,7 +3512,7 @@ tor_spawn_background(const char *const filename, const char **argv,
_exit(255);
/* Never reached, but avoids compiler warning */
- return process_handle->status;
+ return status;
}
/* In parent */
@@ -3473,9 +3523,11 @@ tor_spawn_background(const char *const filename, const char **argv,
close(stdout_pipe[1]);
close(stderr_pipe[0]);
close(stderr_pipe[1]);
- return process_handle->status;
+ return status;
}
+ process_handle = process_handle_new();
+ process_handle->status = status;
process_handle->pid = pid;
/* TODO: If the child process forked but failed to exec, waitpid it */
@@ -3499,7 +3551,7 @@ tor_spawn_background(const char *const filename, const char **argv,
strerror(errno));
}
- process_handle->status = PROCESS_STATUS_RUNNING;
+ status = process_handle->status = PROCESS_STATUS_RUNNING;
/* Set stdout/stderr pipes to be non-blocking */
fcntl(process_handle->stdout_pipe, F_SETFL, O_NONBLOCK);
fcntl(process_handle->stderr_pipe, F_SETFL, O_NONBLOCK);
@@ -3507,10 +3559,52 @@ tor_spawn_background(const char *const filename, const char **argv,
process_handle->stdout_handle = fdopen(process_handle->stdout_pipe, "r");
process_handle->stderr_handle = fdopen(process_handle->stderr_pipe, "r");
+ *process_handle_out = process_handle;
return process_handle->status;
#endif // MS_WINDOWS
}
+/** Destroy all resources allocated by the process handle in
+ * <b>process_handle</b>.
+ * If <b>also_terminate_process</b> is true, also terminate the
+ * process of the process handle. */
+void
+tor_process_handle_destroy(process_handle_t *process_handle,
+ int also_terminate_process)
+{
+ if (!process_handle)
+ return;
+
+ if (also_terminate_process) {
+ if (tor_terminate_process(process_handle) < 0) {
+ log_notice(LD_GENERAL, "Failed to terminate process with PID '%d'",
+ tor_process_get_pid(process_handle));
+ } else {
+ log_info(LD_GENERAL, "Terminated process with PID '%d'",
+ tor_process_get_pid(process_handle));
+ }
+ }
+
+ process_handle->status = PROCESS_STATUS_NOTRUNNING;
+
+#ifdef MS_WINDOWS
+ if (process_handle->stdout_pipe)
+ CloseHandle(process_handle->stdout_pipe);
+
+ if (process_handle->stderr_pipe)
+ CloseHandle(process_handle->stderr_pipe);
+#else
+ if (process_handle->stdout_handle)
+ fclose(process_handle->stdout_handle);
+
+ if (process_handle->stderr_handle)
+ fclose(process_handle->stderr_handle);
+#endif
+
+ memset(process_handle, 0x0f, sizeof(process_handle_t));
+ tor_free(process_handle);
+}
+
/** Get the exit code of a process specified by <b>process_handle</b> and store
* it in <b>exit_code</b>, if set to a non-NULL value. If <b>block</b> is set
* to true, the call will block until the process has exited. Otherwise if
@@ -3522,7 +3616,7 @@ tor_spawn_background(const char *const filename, const char **argv,
* probably not work in Tor, because waitpid() is called in main.c to reap any
* terminated child processes.*/
int
-tor_get_exit_code(const process_handle_t process_handle,
+tor_get_exit_code(const process_handle_t *process_handle,
int block, int *exit_code)
{
#ifdef MS_WINDOWS
@@ -3531,14 +3625,14 @@ tor_get_exit_code(const process_handle_t process_handle,
if (block) {
/* Wait for the process to exit */
- retval = WaitForSingleObject(process_handle.pid.hProcess, INFINITE);
+ retval = WaitForSingleObject(process_handle->pid.hProcess, INFINITE);
if (retval != WAIT_OBJECT_0) {
log_warn(LD_GENERAL, "WaitForSingleObject() failed (%d): %s",
(int)retval, format_win32_error(GetLastError()));
return PROCESS_EXIT_ERROR;
}
} else {
- retval = WaitForSingleObject(process_handle.pid.hProcess, 0);
+ retval = WaitForSingleObject(process_handle->pid.hProcess, 0);
if (WAIT_TIMEOUT == retval) {
/* Process has not exited */
return PROCESS_EXIT_RUNNING;
@@ -3550,7 +3644,7 @@ tor_get_exit_code(const process_handle_t process_handle,
}
if (exit_code != NULL) {
- success = GetExitCodeProcess(process_handle.pid.hProcess,
+ success = GetExitCodeProcess(process_handle->pid.hProcess,
(PDWORD)exit_code);
if (!success) {
log_warn(LD_GENERAL, "GetExitCodeProcess() failed: %s",
@@ -3562,19 +3656,19 @@ tor_get_exit_code(const process_handle_t process_handle,
int stat_loc;
int retval;
- retval = waitpid(process_handle.pid, &stat_loc, block?0:WNOHANG);
+ retval = waitpid(process_handle->pid, &stat_loc, block?0:WNOHANG);
if (!block && 0 == retval) {
/* Process has not exited */
return PROCESS_EXIT_RUNNING;
- } else if (retval != process_handle.pid) {
- log_warn(LD_GENERAL, "waitpid() failed for PID %d: %s", process_handle.pid,
- strerror(errno));
+ } else if (retval != process_handle->pid) {
+ log_warn(LD_GENERAL, "waitpid() failed for PID %d: %s",
+ process_handle->pid, strerror(errno));
return PROCESS_EXIT_ERROR;
}
if (!WIFEXITED(stat_loc)) {
log_warn(LD_GENERAL, "Process %d did not exit normally",
- process_handle.pid);
+ process_handle->pid);
return PROCESS_EXIT_ERROR;
}
@@ -3676,7 +3770,6 @@ tor_read_all_handle(FILE *h, char *buf, size_t count,
if (NULL == retval) {
if (feof(h)) {
log_debug(LD_GENERAL, "fgets() reached end of file");
- fclose(h);
if (eof)
*eof = 1;
break;
@@ -3689,7 +3782,6 @@ tor_read_all_handle(FILE *h, char *buf, size_t count,
} else {
log_warn(LD_GENERAL, "fgets() from handle failed: %s",
strerror(errno));
- fclose(h);
return -1;
}
}
@@ -3849,12 +3941,10 @@ log_from_pipe(FILE *stream, int severity, const char *executable,
r = get_string_from_pipe(stream, buf, sizeof(buf) - 1);
if (r == IO_STREAM_CLOSED) {
- fclose(stream);
return 1;
} else if (r == IO_STREAM_EAGAIN) {
return 0;
} else if (r == IO_STREAM_TERM) {
- fclose(stream);
return -1;
}
@@ -3962,7 +4052,7 @@ tor_check_port_forwarding(const char *filename, int dir_port, int or_port,
/* Static variables are initialized to zero, so child_handle.status=0
* which corresponds to it not running on startup */
- static process_handle_t child_handle;
+ static process_handle_t *child_handle=NULL;
static time_t time_to_run_helper = 0;
int stdout_status, stderr_status, retval;
@@ -3988,46 +4078,50 @@ tor_check_port_forwarding(const char *filename, int dir_port, int or_port,
argv[9] = NULL;
/* Start the child, if it is not already running */
- if (child_handle.status != PROCESS_STATUS_RUNNING &&
+ if ((!child_handle || child_handle->status != PROCESS_STATUS_RUNNING) &&
time_to_run_helper < now) {
+ int status;
+
/* Assume tor-fw-helper will succeed, start it later*/
time_to_run_helper = now + TIME_TO_EXEC_FWHELPER_SUCCESS;
+ if (child_handle) {
+ tor_process_handle_destroy(child_handle, 1);
+ child_handle = NULL;
+ }
+
#ifdef MS_WINDOWS
/* Passing NULL as lpApplicationName makes Windows search for the .exe */
- tor_spawn_background(NULL, argv, NULL, &child_handle);
+ status = tor_spawn_background(NULL, argv, NULL, &child_handle);
#else
- tor_spawn_background(filename, argv, NULL, &child_handle);
+ status = tor_spawn_background(filename, argv, NULL, &child_handle);
#endif
- if (PROCESS_STATUS_ERROR == child_handle.status) {
+
+ if (PROCESS_STATUS_ERROR == status) {
log_warn(LD_GENERAL, "Failed to start port forwarding helper %s",
filename);
time_to_run_helper = now + TIME_TO_EXEC_FWHELPER_FAIL;
return;
}
-#ifdef MS_WINDOWS
- log_info(LD_GENERAL,
- "Started port forwarding helper (%s)", filename);
-#else
+
log_info(LD_GENERAL,
- "Started port forwarding helper (%s) with pid %d", filename,
- child_handle.pid);
-#endif
+ "Started port forwarding helper (%s) with pid '%d'",
+ filename, tor_process_get_pid(child_handle));
}
/* If child is running, read from its stdout and stderr) */
- if (PROCESS_STATUS_RUNNING == child_handle.status) {
+ if (child_handle && PROCESS_STATUS_RUNNING == child_handle->status) {
/* Read from stdout/stderr and log result */
retval = 0;
#ifdef MS_WINDOWS
- stdout_status = log_from_handle(child_handle.stdout_pipe, LOG_INFO);
- stderr_status = log_from_handle(child_handle.stderr_pipe, LOG_WARN);
+ stdout_status = log_from_handle(child_handle->stdout_pipe, LOG_INFO);
+ stderr_status = log_from_handle(child_handle->stderr_pipe, LOG_WARN);
/* If we got this far (on Windows), the process started */
retval = 0;
#else
- stdout_status = log_from_pipe(child_handle.stdout_handle,
+ stdout_status = log_from_pipe(child_handle->stdout_handle,
LOG_INFO, filename, &retval);
- stderr_status = log_from_pipe(child_handle.stderr_handle,
+ stderr_status = log_from_pipe(child_handle->stderr_handle,
LOG_WARN, filename, &retval);
#endif
if (retval) {
@@ -4040,7 +4134,7 @@ tor_check_port_forwarding(const char *filename, int dir_port, int or_port,
/* There was a failure */
retval = -1;
#ifdef MS_WINDOWS
- else if (tor_get_exit_code(child_handle, 0, NULL) !=
+ else if (!child_handle || tor_get_exit_code(child_handle, 0, NULL) !=
PROCESS_EXIT_RUNNING) {
/* process has exited or there was an error */
/* TODO: Do something with the process return value */
@@ -4063,10 +4157,10 @@ tor_check_port_forwarding(const char *filename, int dir_port, int or_port,
if (0 != retval) {
if (1 == retval) {
log_info(LD_GENERAL, "Port forwarding helper terminated");
- child_handle.status = PROCESS_STATUS_NOTRUNNING;
+ child_handle->status = PROCESS_STATUS_NOTRUNNING;
} else {
log_warn(LD_GENERAL, "Failed to read from port forwarding helper");
- child_handle.status = PROCESS_STATUS_ERROR;
+ child_handle->status = PROCESS_STATUS_ERROR;
}
/* TODO: The child might not actually be finished (maybe it failed or
diff --git a/src/common/util.h b/src/common/util.h
index 79b641a014..3a68f3993d 100644
--- a/src/common/util.h
+++ b/src/common/util.h
@@ -173,19 +173,15 @@ int n_bits_set_u8(uint8_t v);
#define HEX_CHARACTERS "0123456789ABCDEFabcdef"
void tor_strlower(char *s) ATTR_NONNULL((1));
void tor_strupper(char *s) ATTR_NONNULL((1));
-int tor_strisprint(const char *s) ATTR_PURE ATTR_NONNULL((1));
-int tor_strisnonupper(const char *s) ATTR_PURE ATTR_NONNULL((1));
-int strcmp_opt(const char *s1, const char *s2) ATTR_PURE;
-int strcmpstart(const char *s1, const char *s2) ATTR_PURE ATTR_NONNULL((1,2));
-int strcmp_len(const char *s1, const char *s2, size_t len)
- ATTR_PURE ATTR_NONNULL((1,2));
-int strcasecmpstart(const char *s1, const char *s2)
- ATTR_PURE ATTR_NONNULL((1,2));
-int strcmpend(const char *s1, const char *s2) ATTR_PURE ATTR_NONNULL((1,2));
-int strcasecmpend(const char *s1, const char *s2)
- ATTR_PURE ATTR_NONNULL((1,2));
-int fast_memcmpstart(const void *mem, size_t memlen,
- const char *prefix) ATTR_PURE;
+int tor_strisprint(const char *s) ATTR_NONNULL((1));
+int tor_strisnonupper(const char *s) ATTR_NONNULL((1));
+int strcmp_opt(const char *s1, const char *s2);
+int strcmpstart(const char *s1, const char *s2) ATTR_NONNULL((1,2));
+int strcmp_len(const char *s1, const char *s2, size_t len) ATTR_NONNULL((1,2));
+int strcasecmpstart(const char *s1, const char *s2) ATTR_NONNULL((1,2));
+int strcmpend(const char *s1, const char *s2) ATTR_NONNULL((1,2));
+int strcasecmpend(const char *s1, const char *s2) ATTR_NONNULL((1,2));
+int fast_memcmpstart(const void *mem, size_t memlen, const char *prefix);
void tor_strstrip(char *s, const char *strip) ATTR_NONNULL((1,2));
long tor_parse_long(const char *s, int base, long min,
@@ -197,19 +193,19 @@ double tor_parse_double(const char *s, double min, double max, int *ok,
uint64_t tor_parse_uint64(const char *s, int base, uint64_t min,
uint64_t max, int *ok, char **next);
const char *hex_str(const char *from, size_t fromlen) ATTR_NONNULL((1));
-const char *eat_whitespace(const char *s) ATTR_PURE;
-const char *eat_whitespace_eos(const char *s, const char *eos) ATTR_PURE;
-const char *eat_whitespace_no_nl(const char *s) ATTR_PURE;
-const char *eat_whitespace_eos_no_nl(const char *s, const char *eos) ATTR_PURE;
-const char *find_whitespace(const char *s) ATTR_PURE;
-const char *find_whitespace_eos(const char *s, const char *eos) ATTR_PURE;
-const char *find_str_at_start_of_line(const char *haystack, const char *needle)
- ATTR_PURE;
+const char *eat_whitespace(const char *s);
+const char *eat_whitespace_eos(const char *s, const char *eos);
+const char *eat_whitespace_no_nl(const char *s);
+const char *eat_whitespace_eos_no_nl(const char *s, const char *eos);
+const char *find_whitespace(const char *s);
+const char *find_whitespace_eos(const char *s, const char *eos);
+const char *find_str_at_start_of_line(const char *haystack,
+ const char *needle);
int string_is_C_identifier(const char *string);
-int tor_mem_is_zero(const char *mem, size_t len) ATTR_PURE;
-int tor_digest_is_zero(const char *digest) ATTR_PURE;
-int tor_digest256_is_zero(const char *digest) ATTR_PURE;
+int tor_mem_is_zero(const char *mem, size_t len);
+int tor_digest_is_zero(const char *digest);
+int tor_digest256_is_zero(const char *digest);
char *esc_for_log(const char *string) ATTR_MALLOC;
const char *escaped(const char *string);
struct smartlist_t;
@@ -352,7 +348,7 @@ const char *parse_config_line_from_str(const char *line,
char **key_out, char **value_out);
char *expand_filename(const char *filename);
struct smartlist_t *tor_listdir(const char *dirname);
-int path_is_relative(const char *filename) ATTR_PURE;
+int path_is_relative(const char *filename);
/* Process helpers */
void start_daemon(void);
@@ -363,10 +359,14 @@ void write_pidfile(char *filename);
void tor_check_port_forwarding(const char *filename,
int dir_port, int or_port, time_t now);
-int tor_terminate_process(pid_t pid);
-typedef struct process_handle_s process_handle_t;
+typedef struct process_handle_t process_handle_t;
int tor_spawn_background(const char *const filename, const char **argv,
- const char **envp, process_handle_t *process_handle);
+#ifdef MS_WINDOWS
+ LPVOID envp,
+#else
+ const char **envp,
+#endif
+ process_handle_t **process_handle_out);
#define SPAWN_ERROR_MESSAGE "ERR: Failed to spawn background process - code "
@@ -374,16 +374,16 @@ int tor_spawn_background(const char *const filename, const char **argv,
HANDLE load_windows_system_library(const TCHAR *library_name);
#endif
-#ifdef UTIL_PRIVATE
-/* Prototypes for private functions only used by util.c (and unit tests) */
-
/* Values of process_handle_t.status. PROCESS_STATUS_NOTRUNNING must be
* 0 because tor_check_port_forwarding depends on this being the initial
* statue of the static instance of process_handle_t */
#define PROCESS_STATUS_NOTRUNNING 0
#define PROCESS_STATUS_RUNNING 1
#define PROCESS_STATUS_ERROR -1
-struct process_handle_s {
+
+#ifdef UTIL_PRIVATE
+/*DOCDOC*/
+struct process_handle_t {
int status;
#ifdef MS_WINDOWS
HANDLE stdout_pipe;
@@ -397,12 +397,13 @@ struct process_handle_s {
pid_t pid;
#endif // MS_WINDOWS
};
+#endif
/* Return values of tor_get_exit_code() */
#define PROCESS_EXIT_RUNNING 1
#define PROCESS_EXIT_EXITED 0
#define PROCESS_EXIT_ERROR -1
-int tor_get_exit_code(const process_handle_t process_handle,
+int tor_get_exit_code(const process_handle_t *process_handle,
int block, int *exit_code);
int tor_split_lines(struct smartlist_t *sl, char *buf, int len);
#ifdef MS_WINDOWS
@@ -419,6 +420,20 @@ ssize_t tor_read_all_from_process_stderr(
const process_handle_t *process_handle, char *buf, size_t count);
char *tor_join_win_cmdline(const char *argv[]);
+int tor_process_get_pid(process_handle_t *process_handle);
+#ifdef MS_WINDOWS
+HANDLE tor_process_get_stdout_pipe(process_handle_t *process_handle);
+#else
+FILE *tor_process_get_stdout_pipe(process_handle_t *process_handle);
+#endif
+
+int tor_terminate_process(process_handle_t *process_handle);
+void tor_process_handle_destroy(process_handle_t *process_handle,
+ int also_terminate_process);
+
+#ifdef UTIL_PRIVATE
+/* Prototypes for private functions only used by util.c (and unit tests) */
+
void format_helper_exit_status(unsigned char child_state,
int saved_errno, char *hex_errno);
diff --git a/src/or/Makefile.am b/src/or/Makefile.am
index 67adf504df..a5682081ae 100644
--- a/src/or/Makefile.am
+++ b/src/or/Makefile.am
@@ -126,8 +126,9 @@ tor_main.o: micro-revision.i
micro-revision.i: FORCE
@rm -f micro-revision.tmp; \
- if test -d ../../.git && test -x "`which git 2>&1;true`"; then \
- HASH="`git rev-parse --short=16 HEAD`"; \
+ if test -d "$(top_srcdir)/.git" && \
+ test -x "`which git 2>&1;true`"; then \
+ HASH="`cd "$(top_srcdir)" && git rev-parse --short=16 HEAD`"; \
echo \"$$HASH\" > micro-revision.tmp; \
fi; \
if test ! -f micro-revision.tmp ; then \
@@ -141,10 +142,10 @@ micro-revision.i: FORCE
or_sha1.i: $(tor_SOURCES) $(libtor_a_SOURCES)
if test "@SHA1SUM@" != none; then \
- @SHA1SUM@ $(tor_SOURCES) $(libtor_a_SOURCES) | \
+ (cd "$(srcdir)" && @SHA1SUM@ $(tor_SOURCES) $(libtor_a_SOURCES)) | \
@SED@ -n 's/^\(.*\)$$/"\1\\n"/p' > or_sha1.i; \
elif test "@OPENSSL@" != none; then \
- @OPENSSL@ sha1 $(tor_SOURCES) $(libtor_a_SOURCES) | \
+ (cd "$(srcdir)" && @OPENSSL@ sha1 $(tor_SOURCES) $(libtor_a_SOURCES)) | \
@SED@ -n 's/SHA1(\(.*\))= \(.*\)/"\2 \1\\n"/p' > or_sha1.i; \
else \
rm or_sha1.i; \
diff --git a/src/or/config.c b/src/or/config.c
index 06914b62af..ab991a4f6e 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -231,6 +231,7 @@ static config_var_t _option_vars[] = {
V(CountPrivateBandwidth, BOOL, "0"),
V(DataDirectory, FILENAME, NULL),
OBSOLETE("DebugLogFile"),
+ V(DisableNetwork, BOOL, "0"),
V(DirAllowPrivateAddresses, BOOL, NULL),
V(TestingAuthDirTimeToLearnReachability, INTERVAL, "30 minutes"),
V(DirListenAddress, LINELIST, NULL),
@@ -246,6 +247,7 @@ static config_var_t _option_vars[] = {
V(DirReqStatistics, BOOL, "1"),
VAR("DirServer", LINELIST, DirServers, NULL),
V(DisableAllSwap, BOOL, "0"),
+ V(DisableDebuggerAttachment, BOOL, "1"),
V(DisableIOCP, BOOL, "1"),
V(DynamicDHGroups, BOOL, "1"),
V(DNSPort, LINELIST, NULL),
@@ -406,6 +408,7 @@ static config_var_t _option_vars[] = {
V(UseEntryGuards, BOOL, "1"),
V(UseMicrodescriptors, AUTOBOOL, "auto"),
V(User, STRING, NULL),
+ V(UserspaceIOCPBuffers, BOOL, "0"),
VAR("V1AuthoritativeDirectory",BOOL, V1AuthoritativeDir, "0"),
VAR("V2AuthoritativeDirectory",BOOL, V2AuthoritativeDir, "0"),
VAR("V3AuthoritativeDirectory",BOOL, V3AuthoritativeDir, "0"),
@@ -660,8 +663,12 @@ static const config_format_t state_format = {
/** Command-line and config-file options. */
static or_options_t *global_options = NULL;
+/** DOCDOC */
+static or_options_t *global_default_options = NULL;
/** Name of most recently read torrc file. */
static char *torrc_fname = NULL;
+/** DOCDOC */
+static char *torrc_defaults_fname;
/** Persistent serialized state. */
static or_state_t *global_state = NULL;
/** Configuration Options set by command line. */
@@ -805,6 +812,8 @@ config_free_all(void)
{
or_options_free(global_options);
global_options = NULL;
+ or_options_free(global_default_options);
+ global_default_options = NULL;
config_free(&state_format, global_state);
global_state = NULL;
@@ -820,6 +829,7 @@ config_free_all(void)
}
tor_free(torrc_fname);
+ tor_free(torrc_defaults_fname);
tor_free(_version);
tor_free(global_dirfrontpagecontents);
}
@@ -1092,13 +1102,22 @@ options_act_reversible(const or_options_t *old_options, char **msg)
consider_hibernation(time(NULL));
/* Launch the listeners. (We do this before we setuid, so we can bind to
- * ports under 1024.) We don't want to rebind if we're hibernating. */
+ * ports under 1024.) We don't want to rebind if we're hibernating. If
+ * networking is disabled, this will close all but the control listeners,
+ * but disable those. */
if (!we_are_hibernating()) {
if (retry_all_listeners(replaced_listeners, new_listeners) < 0) {
*msg = tor_strdup("Failed to bind one of the listener ports.");
goto rollback;
}
}
+ if (options->DisableNetwork) {
+ /* Aggressively close non-controller stuff, NOW */
+ log_notice(LD_NET, "DisableNetwork is set. Tor will not make or accept "
+ "non-control network connections. Shutting down all existing "
+ "connections.");
+ connection_mark_all_noncontrol_connections();
+ }
}
#if defined(HAVE_NET_IF_H) && defined(HAVE_NET_PFVAR_H)
@@ -1304,6 +1323,14 @@ options_act(const or_options_t *old_options)
const int transition_affects_workers =
old_options && options_transition_affects_workers(old_options, options);
+ /* disable ptrace and later, other basic debugging techniques */
+ if (options->DisableDebuggerAttachment) {
+ tor_disable_debugger_attach();
+ } else {
+ log_notice(LD_CONFIG,"Debugger attachment enabled "
+ "for unprivileged users.");
+ }
+
if (running_tor && !have_lockfile()) {
if (try_locking(options, 1) < 0)
return -1;
@@ -1767,7 +1794,11 @@ config_get_commandlines(int argc, char **argv, config_line_t **result)
int i = 1;
while (i < argc) {
+ unsigned command = CONFIG_LINE_NORMAL;
+ int want_arg = 1;
+
if (!strcmp(argv[i],"-f") ||
+ !strcmp(argv[i],"--defaults-torrc") ||
!strcmp(argv[i],"--hash-password")) {
i += 2; /* command-line option with argument. ignore them. */
continue;
@@ -1784,13 +1815,6 @@ config_get_commandlines(int argc, char **argv, config_line_t **result)
continue;
}
- if (i == argc-1) {
- log_warn(LD_CONFIG,"Command-line option '%s' with no value. Failing.",
- argv[i]);
- config_free_lines(front);
- return -1;
- }
-
*new = tor_malloc_zero(sizeof(config_line_t));
s = argv[i];
@@ -1799,15 +1823,33 @@ config_get_commandlines(int argc, char **argv, config_line_t **result)
s++;
if (*s == '-')
s++;
+ /* Figure out the command, if any. */
+ if (*s == '+') {
+ s++;
+ command = CONFIG_LINE_APPEND;
+ } else if (*s == '/') {
+ s++;
+ command = CONFIG_LINE_CLEAR;
+ /* A 'clear' command has no argument. */
+ want_arg = 0;
+ }
+
+ if (want_arg && i == argc-1) {
+ log_warn(LD_CONFIG,"Command-line option '%s' with no value. Failing.",
+ argv[i]);
+ config_free_lines(front);
+ return -1;
+ }
(*new)->key = tor_strdup(expand_abbrev(&options_format, s, 1, 1));
- (*new)->value = tor_strdup(argv[i+1]);
+ (*new)->value = want_arg ? tor_strdup(argv[i+1]) : tor_strdup("");
+ (*new)->command = command;
(*new)->next = NULL;
log(LOG_DEBUG, LD_CONFIG, "command line: parsed keyword '%s', value '%s'",
(*new)->key, (*new)->value);
new = &((*new)->next);
- i += 2;
+ i += want_arg ? 2 : 1;
}
*result = front;
return 0;
@@ -1822,7 +1864,7 @@ config_line_append(config_line_t **lst,
{
config_line_t *newline;
- newline = tor_malloc(sizeof(config_line_t));
+ newline = tor_malloc_zero(sizeof(config_line_t));
newline->key = tor_strdup(key);
newline->value = tor_strdup(val);
newline->next = NULL;
@@ -1835,9 +1877,12 @@ config_line_append(config_line_t **lst,
/** Helper: parse the config string and strdup into key/value
* strings. Set *result to the list, or NULL if parsing the string
* failed. Return 0 on success, -1 on failure. Warn and ignore any
- * misformatted lines. */
+ * misformatted lines.
+ *
+ * If <b>extended</b> is set, then treat keys beginning with / and with + as
+ * indicating "clear" and "append" respectively. */
int
-config_get_lines(const char *string, config_line_t **result)
+config_get_lines(const char *string, config_line_t **result, int extended)
{
config_line_t *list = NULL, **next;
char *k, *v;
@@ -1853,13 +1898,30 @@ config_get_lines(const char *string, config_line_t **result)
return -1;
}
if (k && v) {
+ unsigned command = CONFIG_LINE_NORMAL;
+ if (extended) {
+ if (k[0] == '+') {
+ char *k_new = tor_strdup(k+1);
+ tor_free(k);
+ k = k_new;
+ command = CONFIG_LINE_APPEND;
+ } else if (k[0] == '/') {
+ char *k_new = tor_strdup(k+1);
+ tor_free(k);
+ k = k_new;
+ tor_free(v);
+ v = tor_strdup("");
+ command = CONFIG_LINE_CLEAR;
+ }
+ }
/* This list can get long, so we keep a pointer to the end of it
* rather than using config_line_append over and over and getting
* n^2 performance. */
- *next = tor_malloc(sizeof(config_line_t));
+ *next = tor_malloc_zero(sizeof(config_line_t));
(*next)->key = k;
(*next)->value = v;
(*next)->next = NULL;
+ (*next)->command = command;
next = &((*next)->next);
} else {
tor_free(k);
@@ -2087,7 +2149,19 @@ config_assign_value(const config_format_t *fmt, or_options_t *options,
case CONFIG_TYPE_LINELIST:
case CONFIG_TYPE_LINELIST_S:
- config_line_append((config_line_t**)lvalue, c->key, c->value);
+ {
+ config_line_t *lastval = *(config_line_t**)lvalue;
+ if (lastval && lastval->fragile) {
+ if (c->command != CONFIG_LINE_APPEND) {
+ config_free_lines(lastval);
+ *(config_line_t**)lvalue = NULL;
+ } else {
+ lastval->fragile = 0;
+ }
+ }
+
+ config_line_append((config_line_t**)lvalue, c->key, c->value);
+ }
break;
case CONFIG_TYPE_OBSOLETE:
log_warn(LD_CONFIG, "Skipping obsolete configuration option '%s'", c->key);
@@ -2103,6 +2177,28 @@ config_assign_value(const config_format_t *fmt, or_options_t *options,
return 0;
}
+/** Mark every linelist in <b>options<b> "fragile", so that fresh assignments
+ * to it will replace old ones. */
+static void
+config_mark_lists_fragile(const config_format_t *fmt, or_options_t *options)
+{
+ int i;
+ tor_assert(fmt);
+ tor_assert(options);
+
+ for (i = 0; fmt->vars[i].name; ++i) {
+ const config_var_t *var = &fmt->vars[i];
+ config_line_t *list;
+ if (var->type != CONFIG_TYPE_LINELIST &&
+ var->type != CONFIG_TYPE_LINELIST_V)
+ continue;
+
+ list = *(config_line_t **)STRUCT_VAR_P(options, var->var_offset);
+ if (list)
+ list->fragile = 1;
+ }
+}
+
/** If <b>c</b> is a syntactically valid configuration line, update
* <b>options</b> with its value and return 0. Otherwise return -1 for bad
* key, -2 for bad value.
@@ -2145,8 +2241,9 @@ config_assign_line(const config_format_t *fmt, or_options_t *options,
if (!strlen(c->value)) {
/* reset or clear it, then return */
if (!clear_first) {
- if (var->type == CONFIG_TYPE_LINELIST ||
- var->type == CONFIG_TYPE_LINELIST_S) {
+ if ((var->type == CONFIG_TYPE_LINELIST ||
+ var->type == CONFIG_TYPE_LINELIST_S) &&
+ c->command != CONFIG_LINE_CLEAR) {
/* We got an empty linelist from the torrc or command line.
As a special case, call this an error. Warn and ignore. */
log_warn(LD_CONFIG,
@@ -2156,6 +2253,8 @@ config_assign_line(const config_format_t *fmt, or_options_t *options,
}
}
return 0;
+ } else if (c->command == CONFIG_LINE_CLEAR && !clear_first) {
+ option_reset(fmt, options, var, use_defaults);
}
if (options_seen && (var->type != CONFIG_TYPE_LINELIST &&
@@ -2250,7 +2349,7 @@ config_lines_dup(const config_line_t *inp)
config_line_t *result = NULL;
config_line_t **next_out = &result;
while (inp) {
- *next_out = tor_malloc(sizeof(config_line_t));
+ *next_out = tor_malloc_zero(sizeof(config_line_t));
(*next_out)->key = tor_strdup(inp->key);
(*next_out)->value = tor_strdup(inp->value);
inp = inp->next;
@@ -2487,6 +2586,12 @@ config_assign(const config_format_t *fmt, void *options, config_line_t *list,
list = list->next;
}
bitarray_free(options_seen);
+
+ /** Now we're done assigning a group of options to the configuration.
+ * Subsequent group assignments should _replace_ linelists, not extend
+ * them. */
+ config_mark_lists_fragile(fmt, options);
+
return 0;
}
@@ -2982,24 +3087,30 @@ config_init(const config_format_t *fmt, void *options)
* Else, if comment_defaults, write default values as comments.
*/
static char *
-config_dump(const config_format_t *fmt, const void *options, int minimal,
+config_dump(const config_format_t *fmt, const void *default_options,
+ const void *options, int minimal,
int comment_defaults)
{
smartlist_t *elements;
- or_options_t *defaults;
+ const or_options_t *defaults = default_options;
+ void *defaults_tmp = NULL;
config_line_t *line, *assigned;
char *result;
int i;
char *msg = NULL;
- defaults = config_alloc(fmt);
- config_init(fmt, defaults);
+ if (defaults == NULL) {
+ defaults = defaults_tmp = config_alloc(fmt);
+ config_init(fmt, defaults_tmp);
+ }
/* XXX use a 1 here so we don't add a new log line while dumping */
- if (fmt->validate_fn(NULL,defaults, 1, &msg) < 0) {
- log_err(LD_BUG, "Failed to validate default config.");
- tor_free(msg);
- tor_assert(0);
+ if (default_options == NULL) {
+ if (fmt->validate_fn(NULL, defaults_tmp, 1, &msg) < 0) {
+ log_err(LD_BUG, "Failed to validate default config.");
+ tor_free(msg);
+ tor_assert(0);
+ }
}
elements = smartlist_create();
@@ -3041,7 +3152,8 @@ config_dump(const config_format_t *fmt, const void *options, int minimal,
result = smartlist_join_strings(elements, "", 0, NULL);
SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp));
smartlist_free(elements);
- config_free(fmt, defaults);
+ if (defaults_tmp)
+ config_free(fmt, defaults_tmp);
return result;
}
@@ -3052,7 +3164,8 @@ config_dump(const config_format_t *fmt, const void *options, int minimal,
char *
options_dump(const or_options_t *options, int minimal)
{
- return config_dump(&options_format, options, minimal, 0);
+ return config_dump(&options_format, global_default_options,
+ options, minimal, 0);
}
/** Return 0 if every element of sl is a string holding a decimal
@@ -4133,6 +4246,7 @@ options_transition_affects_descriptor(const or_options_t *old_options,
old_options->ORPort != new_options->ORPort ||
old_options->DirPort != new_options->DirPort ||
old_options->ClientOnly != new_options->ClientOnly ||
+ old_options->DisableNetwork != new_options->DisableNetwork ||
old_options->_PublishServerDescriptor !=
new_options->_PublishServerDescriptor ||
get_effective_bwrate(old_options) != get_effective_bwrate(new_options) ||
@@ -4206,17 +4320,25 @@ get_windows_conf_root(void)
}
#endif
-/** Return the default location for our torrc file. */
+/** Return the default location for our torrc file.
+ * DOCDOC defaults_file */
static const char *
-get_default_conf_file(void)
+get_default_conf_file(int defaults_file)
{
#ifdef MS_WINDOWS
- static char path[MAX_PATH+1];
- strlcpy(path, get_windows_conf_root(), MAX_PATH);
- strlcat(path,"\\torrc",MAX_PATH);
- return path;
+ if (defaults_file) {
+ static char defaults_path[MAX_PATH+1];
+ tor_snprintf(defaults_path, MAX_PATH, "%s\\torrc-defaults",
+ get_windows_conf_root());
+ return defaults_path;
+ } else {
+ static char path[MAX_PATH+1];
+ tor_snprintf(path, MAX_PATH, "%s\\torrc",
+ get_windows_conf_root());
+ return path;
+ }
#else
- return (CONFDIR "/torrc");
+ return defaults_file ? CONFDIR "/torrc-defaults" : CONFDIR "/torrc";
#endif
}
@@ -4249,37 +4371,46 @@ check_nickname_list(const char *lst, const char *name, char **msg)
return r;
}
-/** Learn config file name from command line arguments, or use the default */
+/** Learn config file name from command line arguments, or use the default,
+ * DOCDOC defaults_file */
static char *
find_torrc_filename(int argc, char **argv,
+ int defaults_file,
int *using_default_torrc, int *ignore_missing_torrc)
{
char *fname=NULL;
int i;
+ const char *fname_opt = defaults_file ? "--defaults-torrc" : "-f";
+ const char *ignore_opt = defaults_file ? NULL : "--ignore-missing-torrc";
+
+ if (defaults_file)
+ *ignore_missing_torrc = 1;
for (i = 1; i < argc; ++i) {
- if (i < argc-1 && !strcmp(argv[i],"-f")) {
+ if (i < argc-1 && !strcmp(argv[i],fname_opt)) {
if (fname) {
- log(LOG_WARN, LD_CONFIG, "Duplicate -f options on command line.");
+ log(LOG_WARN, LD_CONFIG, "Duplicate %s options on command line.",
+ fname_opt);
tor_free(fname);
}
fname = expand_filename(argv[i+1]);
*using_default_torrc = 0;
++i;
- } else if (!strcmp(argv[i],"--ignore-missing-torrc")) {
+ } else if (ignore_opt && !strcmp(argv[i],ignore_opt)) {
*ignore_missing_torrc = 1;
}
}
if (*using_default_torrc) {
/* didn't find one, try CONFDIR */
- const char *dflt = get_default_conf_file();
+ const char *dflt = get_default_conf_file(defaults_file);
if (dflt && file_status(dflt) == FN_FILE) {
fname = tor_strdup(dflt);
} else {
#ifndef MS_WINDOWS
- char *fn;
- fn = expand_filename("~/.torrc");
+ char *fn = NULL;
+ if (!defaults_file)
+ fn = expand_filename("~/.torrc");
if (fn && file_status(fn) == FN_FILE) {
fname = fn;
} else {
@@ -4294,31 +4425,34 @@ find_torrc_filename(int argc, char **argv,
return fname;
}
-/** Load torrc from disk, setting torrc_fname if successful */
+/** Load torrc from disk, setting torrc_fname if successful.
+ * DOCDOC defaults_file */
static char *
-load_torrc_from_disk(int argc, char **argv)
+load_torrc_from_disk(int argc, char **argv, int defaults_file)
{
char *fname=NULL;
char *cf = NULL;
int using_default_torrc = 1;
int ignore_missing_torrc = 0;
+ char **fname_var = defaults_file ? &torrc_fname : &torrc_defaults_fname;
- fname = find_torrc_filename(argc, argv,
+ fname = find_torrc_filename(argc, argv, defaults_file,
&using_default_torrc, &ignore_missing_torrc);
tor_assert(fname);
log(LOG_DEBUG, LD_CONFIG, "Opening config file \"%s\"", fname);
- tor_free(torrc_fname);
- torrc_fname = fname;
+ tor_free(*fname_var);
+ *fname_var = fname;
/* Open config file */
if (file_status(fname) != FN_FILE ||
!(cf = read_file_to_str(fname,0,NULL))) {
- if (using_default_torrc == 1 || ignore_missing_torrc ) {
- log(LOG_NOTICE, LD_CONFIG, "Configuration file \"%s\" not present, "
- "using reasonable defaults.", fname);
+ if (using_default_torrc == 1 || ignore_missing_torrc) {
+ if (!defaults_file)
+ log(LOG_NOTICE, LD_CONFIG, "Configuration file \"%s\" not present, "
+ "using reasonable defaults.", fname);
tor_free(fname); /* sets fname to NULL */
- torrc_fname = NULL;
+ *fname_var = NULL;
cf = tor_strdup("");
} else {
log(LOG_WARN, LD_CONFIG,
@@ -4332,7 +4466,7 @@ load_torrc_from_disk(int argc, char **argv)
return cf;
err:
tor_free(fname);
- torrc_fname = NULL;
+ *fname_var = NULL;
return NULL;
}
@@ -4343,7 +4477,7 @@ load_torrc_from_disk(int argc, char **argv)
int
options_init_from_torrc(int argc, char **argv)
{
- char *cf=NULL;
+ char *cf=NULL, *cf_defaults=NULL;
int i, retval, command;
static char **backup_argv;
static int backup_argc;
@@ -4403,13 +4537,15 @@ options_init_from_torrc(int argc, char **argv)
if (command == CMD_HASH_PASSWORD) {
cf = tor_strdup("");
} else {
- cf = load_torrc_from_disk(argc, argv);
+ cf_defaults = load_torrc_from_disk(argc, argv, 1);
+ cf = load_torrc_from_disk(argc, argv, 0);
if (!cf)
goto err;
}
- retval = options_init_from_string(cf, command, command_arg, &errmsg);
+ retval = options_init_from_string(cf_defaults, cf, command, command_arg, &errmsg);
tor_free(cf);
+ tor_free(cf_defaults);
if (retval < 0)
goto err;
@@ -4433,13 +4569,13 @@ options_init_from_torrc(int argc, char **argv)
* * -4 for error while setting the new options
*/
setopt_err_t
-options_init_from_string(const char *cf,
+options_init_from_string(const char *cf_defaults, const char *cf,
int command, const char *command_arg,
char **msg)
{
- or_options_t *oldoptions, *newoptions;
+ or_options_t *oldoptions, *newoptions, *newdefaultoptions=NULL;
config_line_t *cl;
- int retval;
+ int retval, i;
setopt_err_t err = SETOPT_ERR_MISC;
tor_assert(msg);
@@ -4452,17 +4588,24 @@ options_init_from_string(const char *cf,
newoptions->command = command;
newoptions->command_arg = command_arg;
- /* get config lines, assign them */
- retval = config_get_lines(cf, &cl);
- if (retval < 0) {
- err = SETOPT_ERR_PARSE;
- goto err;
- }
- retval = config_assign(&options_format, newoptions, cl, 0, 0, msg);
- config_free_lines(cl);
- if (retval < 0) {
- err = SETOPT_ERR_PARSE;
- goto err;
+ for (i = 0; i < 2; ++i) {
+ const char *body = i==0 ? cf_defaults : cf;
+ if (!body)
+ continue;
+ /* get config lines, assign them */
+ retval = config_get_lines(body, &cl, 1);
+ if (retval < 0) {
+ err = SETOPT_ERR_PARSE;
+ goto err;
+ }
+ retval = config_assign(&options_format, newoptions, cl, 0, 0, msg);
+ config_free_lines(cl);
+ if (retval < 0) {
+ err = SETOPT_ERR_PARSE;
+ goto err;
+ }
+ if (i==0)
+ newdefaultoptions = options_dup(&options_format, newoptions);
}
/* Go through command-line variables too */
@@ -4497,6 +4640,8 @@ options_init_from_string(const char *cf,
/* Clear newoptions and re-initialize them with new defaults. */
config_free(&options_format, newoptions);
+ config_free(&options_format, newdefaultoptions);
+ newdefaultoptions = NULL;
newoptions = tor_malloc_zero(sizeof(or_options_t));
newoptions->_magic = OR_OPTIONS_MAGIC;
options_init(newoptions);
@@ -4504,22 +4649,24 @@ options_init_from_string(const char *cf,
newoptions->command_arg = command_arg;
/* Assign all options a second time. */
- retval = config_get_lines(cf, &cl);
- if (retval < 0) {
- err = SETOPT_ERR_PARSE;
- goto err;
- }
- retval = config_assign(&options_format, newoptions, cl, 0, 0, msg);
- config_free_lines(cl);
- if (retval < 0) {
- err = SETOPT_ERR_PARSE;
- goto err;
- }
- retval = config_assign(&options_format, newoptions,
- global_cmdline_options, 0, 0, msg);
- if (retval < 0) {
- err = SETOPT_ERR_PARSE;
- goto err;
+ for (i = 0; i < 2; ++i) {
+ const char *body = i==0 ? cf_defaults : cf;
+ if (!body)
+ continue;
+ /* get config lines, assign them */
+ retval = config_get_lines(body, &cl, 1);
+ if (retval < 0) {
+ err = SETOPT_ERR_PARSE;
+ goto err;
+ }
+ retval = config_assign(&options_format, newoptions, cl, 0, 0, msg);
+ config_free_lines(cl);
+ if (retval < 0) {
+ err = SETOPT_ERR_PARSE;
+ goto err;
+ }
+ if (i==0)
+ newdefaultoptions = options_dup(&options_format, newoptions);
}
}
@@ -4538,11 +4685,14 @@ options_init_from_string(const char *cf,
err = SETOPT_ERR_SETTING;
goto err; /* frees and replaces old options */
}
+ config_free(&options_format, global_default_options);
+ global_default_options = newdefaultoptions;
return SETOPT_OK;
err:
config_free(&options_format, newoptions);
+ config_free(&options_format, newdefaultoptions);
if (*msg) {
char *old_msg = *msg;
tor_asprintf(msg, "Failed to parse/validate config: %s", old_msg);
@@ -4554,12 +4704,14 @@ options_init_from_string(const char *cf,
/** Return the location for our configuration file.
*/
const char *
-get_torrc_fname(void)
+get_torrc_fname(int defaults_fname)
{
- if (torrc_fname)
- return torrc_fname;
+ const char *fname = defaults_fname ? torrc_defaults_fname : torrc_fname;
+
+ if (fname)
+ return fname;
else
- return get_default_conf_file();
+ return get_default_conf_file(defaults_fname);
}
/** Adjust the address map based on the MapAddress elements in the
@@ -5164,7 +5316,7 @@ parse_dir_server_line(const char *line, dirinfo_type_t required_type,
* 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());
+ get_torrc_fname(0));
goto err;
}
if (base16_decode(digest, DIGEST_LEN, fingerprint, HEX_DIGEST_LEN)<0) {
@@ -5723,7 +5875,7 @@ options_save_current(void)
* If we try falling back to datadirectory or something, we have a better
* chance of saving the configuration, but a better chance of doing
* something the user never expected. */
- return write_configuration_file(get_torrc_fname(), get_options());
+ return write_configuration_file(get_torrc_fname(0), get_options());
}
/** Mapping from a unit name to a multiplier for converting that unit into a
@@ -6189,7 +6341,7 @@ or_state_load(void)
if (contents) {
config_line_t *lines=NULL;
int assign_retval;
- if (config_get_lines(contents, &lines)<0)
+ if (config_get_lines(contents, &lines, 0)<0)
goto done;
assign_retval = config_assign(&state_format, new_state,
lines, 0, 0, &errmsg);
@@ -6293,7 +6445,7 @@ or_state_save(time_t now)
tor_free(global_state->TorVersion);
tor_asprintf(&global_state->TorVersion, "Tor %s", get_version());
- state = config_dump(&state_format, global_state, 1, 0);
+ state = config_dump(&state_format, NULL, global_state, 1, 0);
format_local_iso_time(tbuf, now);
tor_asprintf(&contents,
"# Tor state file last generated on %s local time\n"
diff --git a/src/or/config.h b/src/or/config.h
index 76f6841d70..e1fc5cfe9a 100644
--- a/src/or/config.h
+++ b/src/or/config.h
@@ -23,24 +23,24 @@ const char *escaped_safe_str_client(const char *address);
const char *escaped_safe_str(const char *address);
const char *get_version(void);
-int config_get_lines(const char *string, config_line_t **result);
+int config_get_lines(const char *string, config_line_t **result, int extended);
void config_free_lines(config_line_t *front);
setopt_err_t options_trial_assign(config_line_t *list, int use_defaults,
int clear_first, char **msg);
int resolve_my_address(int warn_severity, const or_options_t *options,
uint32_t *addr, char **hostname_out);
-int is_local_addr(const tor_addr_t *addr) ATTR_PURE;
+int is_local_addr(const tor_addr_t *addr);
void options_init(or_options_t *options);
char *options_dump(const or_options_t *options, int minimal);
int options_init_from_torrc(int argc, char **argv);
-setopt_err_t options_init_from_string(const char *cf,
+setopt_err_t options_init_from_string(const char *cf_defaults, const char *cf,
int command, const char *command_arg, char **msg);
int option_is_recognized(const char *key);
const char *option_get_canonical_name(const char *key);
config_line_t *option_get_assignment(const or_options_t *options,
const char *key);
int options_save_current(void);
-const char *get_torrc_fname(void);
+const char *get_torrc_fname(int defaults_fname);
char *options_get_datadir_fname2_suffix(const or_options_t *options,
const char *sub1, const char *sub2,
const char *suffix);
diff --git a/src/or/connection.c b/src/or/connection.c
index a52bf48078..b87f922175 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -1318,6 +1318,24 @@ connection_connect(connection_t *conn, const char *address,
else
protocol_family = PF_INET;
+ if (get_options()->DisableNetwork) {
+ /* We should never even try to connect anyplace if DisableNetwork is set.
+ * Warn if we do, and refuse to make the connection. */
+ static ratelim_t disablenet_violated = RATELIM_INIT(30*60);
+ char *m;
+#ifdef MS_WINDOWS
+ *socket_error = WSAENETUNREACH;
+#else
+ *socket_error = ENETUNREACH;
+#endif
+ if ((m = rate_limit_log(&disablenet_violated, approx_time()))) {
+ log_warn(LD_BUG, "Tried to open a socket with DisableNetwork set.%s", m);
+ tor_free(m);
+ }
+ tor_fragile_assert();
+ return -1;
+ }
+
s = tor_open_socket(protocol_family,SOCK_STREAM,IPPROTO_TCP);
if (s < 0) {
*socket_error = tor_socket_errno(-1);
@@ -1968,7 +1986,7 @@ retry_all_listeners(smartlist_t *replaced_conns,
smartlist_add(listeners, conn);
} SMARTLIST_FOREACH_END(conn);
- if (! options->ClientOnly) {
+ if (! options->ClientOnly && ! options->DisableNetwork) {
if (retry_listeners(listeners,
CONN_TYPE_OR_LISTENER, options->ORListenAddress,
options->ORPort, "0.0.0.0",
@@ -1981,10 +1999,13 @@ retry_all_listeners(smartlist_t *replaced_conns,
retval = -1;
}
- if (retry_listener_ports(listeners,
- get_configured_client_ports(),
- new_conns) < 0)
- retval = -1;
+ if (!options->DisableNetwork) {
+ if (retry_listener_ports(listeners,
+ get_configured_client_ports(),
+ new_conns) < 0)
+ retval = -1;
+ }
+
if (retry_listeners(listeners,
CONN_TYPE_CONTROL_LISTENER,
options->ControlListenAddress,
@@ -2025,6 +2046,43 @@ retry_all_listeners(smartlist_t *replaced_conns,
return retval;
}
+/** Mark every listener of type other than CONTROL_LISTENER to be closed. */
+void
+connection_mark_all_noncontrol_listeners(void)
+{
+ SMARTLIST_FOREACH_BEGIN(get_connection_array(), connection_t *, conn) {
+ if (conn->marked_for_close)
+ continue;
+ if (conn->type == CONN_TYPE_CONTROL_LISTENER)
+ continue;
+ if (connection_is_listener(conn))
+ connection_mark_for_close(conn);
+ } SMARTLIST_FOREACH_END(conn);
+}
+
+/** Mark every external conection not used for controllers for close. */
+void
+connection_mark_all_noncontrol_connections(void)
+{
+ SMARTLIST_FOREACH_BEGIN(get_connection_array(), connection_t *, conn) {
+ if (conn->marked_for_close)
+ continue;
+ switch (conn->type) {
+ case CONN_TYPE_CPUWORKER:
+ case CONN_TYPE_CONTROL_LISTENER:
+ case CONN_TYPE_CONTROL:
+ break;
+ case CONN_TYPE_AP:
+ connection_mark_unattached_ap(TO_ENTRY_CONN(conn),
+ END_STREAM_REASON_HIBERNATING);
+ break;
+ default:
+ connection_mark_for_close(conn);
+ break;
+ }
+ } SMARTLIST_FOREACH_END(conn);
+}
+
/** Return 1 if we should apply rate limiting to <b>conn</b>, and 0
* otherwise.
* Right now this just checks if it's an internal IP address or an
diff --git a/src/or/connection.h b/src/or/connection.h
index 9f11489727..c4b8bf8abe 100644
--- a/src/or/connection.h
+++ b/src/or/connection.h
@@ -66,6 +66,9 @@ int get_proxy_addrport(tor_addr_t *addr, uint16_t *port, int *proxy_type,
int retry_all_listeners(smartlist_t *replaced_conns,
smartlist_t *new_conns);
+void connection_mark_all_noncontrol_listeners(void);
+void connection_mark_all_noncontrol_connections(void);
+
ssize_t connection_bucket_write_limit(connection_t *conn, time_t now);
int global_write_bucket_low(connection_t *conn, size_t attempt, int priority);
void connection_bucket_init(void);
diff --git a/src/or/connection_or.c b/src/or/connection_or.c
index cce99e4d65..246b08ad77 100644
--- a/src/or/connection_or.c
+++ b/src/or/connection_or.c
@@ -492,6 +492,9 @@ connection_or_about_to_close(or_connection_t *or_conn)
time_t now = time(NULL);
connection_t *conn = TO_CONN(or_conn);
+ if (or_conn->pending_action)
+ tor_cancel_libevent_action(or_conn->pending_action);
+
/* Remember why we're closing this connection. */
if (conn->state != OR_CONN_STATE_OPEN) {
/* Inform any pending (not attached) circs that they should
@@ -1146,10 +1149,6 @@ connection_or_tls_renegotiated_cb(tor_tls_t *tls, void *_conn)
or_connection_t *conn = _conn;
(void)tls;
- /* Don't invoke this again. */
- tor_tls_set_renegotiate_callback(tls, NULL, NULL);
- tor_tls_block_renegotiation(tls);
-
if (connection_tls_finish_handshake(conn) < 0) {
/* XXXX_TLS double-check that it's ok to do this from inside read. */
/* XXXX_TLS double-check that this verifies certificates. */
@@ -1157,6 +1156,34 @@ connection_or_tls_renegotiated_cb(tor_tls_t *tls, void *_conn)
}
}
+/*DOCDOC*/
+static void
+close_connection_libevent_cb(void *_conn)
+{
+ or_connection_t *or_conn = _conn;
+ connection_t *conn = TO_CONN(or_conn);
+
+ or_conn->pending_action = NULL;
+
+ connection_stop_reading(conn);
+ if (!conn->marked_for_close)
+ connection_mark_for_close(conn);
+}
+
+/* DOCDOC */
+static void
+connection_or_close_connection_cb(void *_conn)
+{
+ /* We can't close their connection from in here since it's an OpenSSL
+ callback, so we set a libevent event that triggers in the next event
+ loop and closes the connection. */
+ or_connection_t *or_conn = _conn;
+ if (or_conn->_base.marked_for_close || or_conn->pending_action)
+ return;
+ or_conn->pending_action =
+ tor_run_in_libevent_loop(close_connection_libevent_cb, or_conn);
+}
+
/** Move forward with the tls handshake. If it finishes, hand
* <b>conn</b> to connection_tls_finish_handshake().
*
@@ -1203,8 +1230,9 @@ connection_tls_continue_handshake(or_connection_t *conn)
/* v2/v3 handshake, but not a client. */
log_debug(LD_OR, "Done with initial SSL handshake (server-side). "
"Expecting renegotiation or VERSIONS cell");
- tor_tls_set_renegotiate_callback(conn->tls,
+ tor_tls_set_renegotiate_callbacks(conn->tls,
connection_or_tls_renegotiated_cb,
+ connection_or_close_connection_cb,
conn);
conn->_base.state = OR_CONN_STATE_TLS_SERVER_RENEGOTIATING;
connection_stop_writing(TO_CONN(conn));
@@ -1266,8 +1294,9 @@ connection_or_handle_event_cb(struct bufferevent *bufev, short event,
} else if (tor_tls_get_num_server_handshakes(conn->tls) == 1) {
/* v2 or v3 handshake, as a server. Only got one handshake, so
* wait for the next one. */
- tor_tls_set_renegotiate_callback(conn->tls,
+ tor_tls_set_renegotiate_callbacks(conn->tls,
connection_or_tls_renegotiated_cb,
+ connection_or_close_connection_cb,
conn);
conn->_base.state = OR_CONN_STATE_TLS_SERVER_RENEGOTIATING;
/* return 0; */
@@ -1536,7 +1565,6 @@ connection_tls_finish_handshake(or_connection_t *conn)
connection_or_init_conn_from_address(conn, &conn->_base.addr,
conn->_base.port, digest_rcvd, 0);
}
- tor_tls_block_renegotiation(conn->tls);
return connection_or_set_state_open(conn);
} else {
conn->_base.state = OR_CONN_STATE_OR_HANDSHAKING_V2;
diff --git a/src/or/control.c b/src/or/control.c
index 109eb8857b..8d924b44f1 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -737,7 +737,7 @@ control_setconf_helper(control_connection_t *conn, uint32_t len, char *body,
SMARTLIST_FOREACH(entries, char *, cp, tor_free(cp));
smartlist_free(entries);
- if (config_get_lines(config, &lines) < 0) {
+ if (config_get_lines(config, &lines, 0) < 0) {
log_warn(LD_CONTROL,"Controller gave us config lines we can't parse.");
connection_write_str_to_buf("551 Couldn't parse configuration\r\n",
conn);
@@ -883,7 +883,7 @@ handle_control_loadconf(control_connection_t *conn, uint32_t len,
const char *msg = NULL;
(void) len;
- retval = options_init_from_string(body, CMD_RUN_TOR, NULL, &errstring);
+ retval = options_init_from_string(NULL, body, CMD_RUN_TOR, NULL, &errstring);
if (retval != SETOPT_OK)
log_warn(LD_CONTROL,
@@ -1378,7 +1378,9 @@ getinfo_helper_misc(control_connection_t *conn, const char *question,
if (!strcmp(question, "version")) {
*answer = tor_strdup(get_version());
} else if (!strcmp(question, "config-file")) {
- *answer = tor_strdup(get_torrc_fname());
+ *answer = tor_strdup(get_torrc_fname(0));
+ } else if (!strcmp(question, "config-defaults-file")) {
+ *answer = tor_strdup(get_torrc_fname(1));
} else if (!strcmp(question, "config-text")) {
*answer = options_dump(get_options(), 1);
} else if (!strcmp(question, "info/names")) {
diff --git a/src/or/dirserv.c b/src/or/dirserv.c
index be62459b16..8fe1b18a35 100644
--- a/src/or/dirserv.c
+++ b/src/or/dirserv.c
@@ -232,7 +232,7 @@ dirserv_load_fingerprint_file(void)
}
tor_free(fname);
- result = config_get_lines(cf, &front);
+ result = config_get_lines(cf, &front, 0);
tor_free(cf);
if (result < 0) {
log_warn(LD_CONFIG, "Error reading from fingerprint file");
diff --git a/src/or/dirvote.c b/src/or/dirvote.c
index bf34c62af3..01e2358c44 100644
--- a/src/or/dirvote.c
+++ b/src/or/dirvote.c
@@ -50,7 +50,7 @@ static int dirvote_publish_consensus(void);
static char *make_consensus_method_list(int low, int high, const char *sep);
/** The highest consensus method that we currently support. */
-#define MAX_SUPPORTED_CONSENSUS_METHOD 11
+#define MAX_SUPPORTED_CONSENSUS_METHOD 12
/** Lowest consensus method that contains a 'directory-footer' marker */
#define MIN_METHOD_FOR_FOOTER 9
@@ -64,6 +64,10 @@ static char *make_consensus_method_list(int low, int high, const char *sep);
/** Lowest consensus method that generates microdescriptors */
#define MIN_METHOD_FOR_MICRODESC 8
+/** Lowest consensus method that ensures a majority of authorities voted
+ * for a param. */
+#define MIN_METHOD_FOR_MAJORITY_PARAMS 12
+
/* =====
* Voting
* =====*/
@@ -608,11 +612,16 @@ compute_consensus_versions_list(smartlist_t *lst, int n_versioning)
return result;
}
+/** Minimum number of directory authorities voting for a parameter to
+ * include it in the consensus, if consensus method 12 or later is to be
+ * used. See proposal 178 for details. */
+#define MIN_VOTES_FOR_PARAM 3
+
/** Helper: given a list of valid networkstatus_t, return a new string
* containing the contents of the consensus network parameter set.
*/
/* private */ char *
-dirvote_compute_params(smartlist_t *votes)
+dirvote_compute_params(smartlist_t *votes, int method, int total_authorities)
{
int i;
int32_t *vals;
@@ -669,11 +678,17 @@ dirvote_compute_params(smartlist_t *votes)
next_param = smartlist_get(param_list, param_sl_idx+1);
if (!next_param || strncmp(next_param, param, cur_param_len)) {
/* We've reached the end of a series. */
- int32_t median = median_int32(vals, i);
- char *out_string = tor_malloc(64+cur_param_len);
- memcpy(out_string, param, cur_param_len);
- tor_snprintf(out_string+cur_param_len,64, "%ld", (long)median);
- smartlist_add(output, out_string);
+ /* Make sure enough authorities voted on this param, unless the
+ * the consensus method we use is too old for that. */
+ if (method < MIN_METHOD_FOR_MAJORITY_PARAMS ||
+ i > total_authorities/2 ||
+ i >= MIN_VOTES_FOR_PARAM) {
+ int32_t median = median_int32(vals, i);
+ char *out_string = tor_malloc(64+cur_param_len);
+ memcpy(out_string, param, cur_param_len);
+ tor_snprintf(out_string+cur_param_len,64, "%ld", (long)median);
+ smartlist_add(output, out_string);
+ }
i = 0;
if (next_param) {
@@ -1496,7 +1511,8 @@ networkstatus_compute_consensus(smartlist_t *votes,
}
if (consensus_method >= MIN_METHOD_FOR_PARAMS) {
- params = dirvote_compute_params(votes);
+ params = dirvote_compute_params(votes, consensus_method,
+ total_authorities);
if (params) {
smartlist_add(chunks, tor_strdup("params "));
smartlist_add(chunks, params);
diff --git a/src/or/dirvote.h b/src/or/dirvote.h
index d19635173f..1f4dc362b5 100644
--- a/src/or/dirvote.h
+++ b/src/or/dirvote.h
@@ -84,7 +84,8 @@ document_signature_t *voter_get_sig_by_algorithm(
#ifdef DIRVOTE_PRIVATE
char *format_networkstatus_vote(crypto_pk_env_t *private_key,
networkstatus_t *v3_ns);
-char *dirvote_compute_params(smartlist_t *votes);
+char *dirvote_compute_params(smartlist_t *votes, int method,
+ int total_authorities);
#endif
#endif
diff --git a/src/or/dns.c b/src/or/dns.c
index 8ed9536903..beb110acb2 100644
--- a/src/or/dns.c
+++ b/src/or/dns.c
@@ -1395,6 +1395,10 @@ launch_resolve(edge_connection_t *exitconn)
int r;
int options = get_options()->ServerDNSSearchDomains ? 0
: DNS_QUERY_NO_SEARCH;
+
+ if (get_options()->DisableNetwork)
+ return -1;
+
/* What? Nameservers not configured? Sounds like a bug. */
if (!nameservers_configured) {
log_warn(LD_EXIT, "(Harmless.) Nameservers not configured, but resolve "
@@ -1601,6 +1605,9 @@ launch_test_addresses(int fd, short event, void *args)
(void)event;
(void)args;
+ if (options->DisableNetwork)
+ return;
+
log_info(LD_EXIT, "Launching checks to see whether our nameservers like to "
"hijack *everything*.");
/* This situation is worse than the failure-hijacking situation. When this
diff --git a/src/or/hibernate.c b/src/or/hibernate.c
index 6fd2b4f197..ce64581d1c 100644
--- a/src/or/hibernate.c
+++ b/src/or/hibernate.c
@@ -735,7 +735,6 @@ hibernate_soft_limit_reached(void)
static void
hibernate_begin(hibernate_state_t new_state, time_t now)
{
- connection_t *conn;
const or_options_t *options = get_options();
if (new_state == HIBERNATE_STATE_EXITING &&
@@ -756,15 +755,7 @@ hibernate_begin(hibernate_state_t new_state, time_t now)
}
/* close listeners. leave control listener(s). */
- while ((conn = connection_get_by_type(CONN_TYPE_OR_LISTENER)) ||
- (conn = connection_get_by_type(CONN_TYPE_AP_LISTENER)) ||
- (conn = connection_get_by_type(CONN_TYPE_AP_TRANS_LISTENER)) ||
- (conn = connection_get_by_type(CONN_TYPE_AP_DNS_LISTENER)) ||
- (conn = connection_get_by_type(CONN_TYPE_AP_NATD_LISTENER)) ||
- (conn = connection_get_by_type(CONN_TYPE_DIR_LISTENER))) {
- log_info(LD_NET,"Closing listener type %d", conn->type);
- connection_mark_for_close(conn);
- }
+ connection_mark_all_noncontrol_listeners();
/* XXX kill intro point circs */
/* XXX upload rendezvous service descriptors with no intro points */
diff --git a/src/or/main.c b/src/or/main.c
index 95f9958aa8..da45f5a681 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -196,6 +196,26 @@ free_old_inbuf(connection_t *conn)
}
#endif
+#ifdef MS_WINDOWS
+/** Remove the kernel-space send and receive buffers for <b>s</b>. For use
+ * with IOCP only. */
+static int
+set_buffer_lengths_to_zero(tor_socket_t s)
+{
+ int zero = 0;
+ int r = 0;
+ if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, (void*)&zero, sizeof(zero))) {
+ log_warn(LD_NET, "Unable to clear SO_SNDBUF");
+ r = -1;
+ }
+ if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, (void*)&zero, sizeof(zero))) {
+ log_warn(LD_NET, "Unable to clear SO_RCVBUF");
+ r = -1;
+ }
+ return r;
+}
+#endif
+
/** Add <b>conn</b> to the array of connections that we can poll on. The
* connection's socket must be set; the connection starts out
* non-reading and non-writing.
@@ -216,6 +236,14 @@ connection_add_impl(connection_t *conn, int is_connecting)
#ifdef USE_BUFFEREVENTS
if (connection_type_uses_bufferevent(conn)) {
if (SOCKET_OK(conn->s) && !conn->linked) {
+
+#ifdef MS_WINDOWS
+ if (tor_libevent_using_iocp_bufferevents() &&
+ get_options()->UserspaceIOCPBuffers) {
+ set_buffer_lengths_to_zero(conn->s);
+ }
+#endif
+
conn->bufev = bufferevent_socket_new(
tor_libevent_get_base(),
conn->s,
@@ -906,7 +934,7 @@ directory_info_has_arrived(time_t now, int from_cache)
update_extrainfo_downloads(now);
}
- if (server_mode(options) && !we_are_hibernating() && !from_cache &&
+ if (server_mode(options) && !net_is_disabled() && !from_cache &&
(can_complete_circuit || !any_predicted_circuits(now)))
consider_testing_reachability(1, 1);
}
@@ -1133,11 +1161,11 @@ run_scheduled_events(time_t now)
if (router_rebuild_descriptor(1)<0) {
log_info(LD_CONFIG, "Couldn't rebuild router descriptor");
}
- if (advertised_server_mode())
+ if (advertised_server_mode() & !options->DisableNetwork)
router_upload_dir_desc_to_dirservers(0);
}
- if (time_to_try_getting_descriptors < now) {
+ if (!options->DisableNetwork && time_to_try_getting_descriptors < now) {
update_all_descriptor_downloads(now);
update_extrainfo_downloads(now);
if (router_have_minimum_dir_info())
@@ -1188,7 +1216,7 @@ run_scheduled_events(time_t now)
if (time_to_launch_reachability_tests < now &&
(authdir_mode_tests_reachability(options)) &&
- !we_are_hibernating()) {
+ !net_is_disabled()) {
time_to_launch_reachability_tests = now + REACHABILITY_TEST_INTERVAL;
/* try to determine reachability of the other Tor relays */
dirserv_test_reachability(now);
@@ -1324,7 +1352,7 @@ run_scheduled_events(time_t now)
/* 2b. Once per minute, regenerate and upload the descriptor if the old
* one is inaccurate. */
- if (time_to_check_descriptor < now) {
+ if (time_to_check_descriptor < now && !options->DisableNetwork) {
static int dirport_reachability_count = 0;
time_to_check_descriptor = now + CHECK_DESCRIPTOR_INTERVAL;
check_descriptor_bandwidth_changed(now);
@@ -1399,7 +1427,7 @@ run_scheduled_events(time_t now)
connection_expire_held_open();
/** 3d. And every 60 seconds, we relaunch listeners if any died. */
- if (!we_are_hibernating() && time_to_check_listeners < now) {
+ if (!net_is_disabled() && time_to_check_listeners < now) {
retry_all_listeners(NULL, NULL);
time_to_check_listeners = now+60;
}
@@ -1410,7 +1438,7 @@ run_scheduled_events(time_t now)
* and we make a new circ if there are no clean circuits.
*/
have_dir_info = router_have_minimum_dir_info();
- if (have_dir_info && !we_are_hibernating())
+ if (have_dir_info && !net_is_disabled())
circuit_build_needed_circs(now);
/* every 10 seconds, but not at the same second as other such events */
@@ -1441,7 +1469,7 @@ run_scheduled_events(time_t now)
circuit_close_all_marked();
/** 7. And upload service descriptors if necessary. */
- if (can_complete_circuit && !we_are_hibernating()) {
+ if (can_complete_circuit && !net_is_disabled()) {
rend_consider_services_upload(now);
rend_consider_descriptor_republication();
}
@@ -1458,7 +1486,8 @@ run_scheduled_events(time_t now)
/** 9. and if we're a server, check whether our DNS is telling stories to
* us. */
- if (public_server_mode(options) && time_to_check_for_correct_dns < now) {
+ if (!net_is_disabled() &&
+ public_server_mode(options) && time_to_check_for_correct_dns < now) {
if (!time_to_check_for_correct_dns) {
time_to_check_for_correct_dns = now + 60 + crypto_rand_int(120);
} else {
@@ -1477,7 +1506,8 @@ run_scheduled_events(time_t now)
}
/** 11. check the port forwarding app */
- if (time_to_check_port_forwarding < now &&
+ if (!net_is_disabled() &&
+ time_to_check_port_forwarding < now &&
options->PortForwarding &&
is_server) {
#define PORT_FORWARDING_CHECK_INTERVAL 5
@@ -1489,7 +1519,7 @@ run_scheduled_events(time_t now)
}
/** 11b. check pending unconfigured managed proxies */
- if (pt_proxies_configuration_pending())
+ if (!net_is_disabled() && pt_proxies_configuration_pending())
pt_configure_remaining_proxies();
/** 11c. validate pluggable transports configuration if we need to */
@@ -1561,7 +1591,7 @@ second_elapsed_callback(periodic_timer_t *timer, void *arg)
control_event_stream_bandwidth_used();
if (server_mode(options) &&
- !we_are_hibernating() &&
+ !net_is_disabled() &&
seconds_elapsed > 0 &&
can_complete_circuit &&
stats_n_seconds_working / TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT !=
@@ -1762,7 +1792,8 @@ do_hup(void)
/* retry appropriate downloads */
router_reset_status_download_failures();
router_reset_descriptor_download_failures();
- update_networkstatus_downloads(time(NULL));
+ if (!options->DisableNetwork)
+ update_networkstatus_downloads(time(NULL));
/* We'll retry routerstatus downloads in about 10 seconds; no need to
* force a retry there. */
diff --git a/src/or/or.h b/src/or/or.h
index ec49014d94..be7fb413e2 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -1272,6 +1272,8 @@ typedef struct or_connection_t {
unsigned active_circuit_pqueue_last_recalibrated;
struct or_connection_t *next_with_same_id; /**< Next connection with same
* identity digest as this one. */
+
+ tor_libevent_action_t *pending_action;
} or_connection_t;
/** Subtype of connection_t for an "edge connection" -- that is, an entry (ap)
@@ -2836,11 +2838,25 @@ typedef struct port_cfg_t {
char unix_addr[FLEXIBLE_ARRAY_MEMBER];
} port_cfg_t;
+/** Ordinary configuration line. */
+#define CONFIG_LINE_NORMAL 0
+/** Appends to previous configuration for the same option, even if we
+ * would ordinary replace it. */
+#define CONFIG_LINE_APPEND 1
+/* Removes all previous configuration for an option. */
+#define CONFIG_LINE_CLEAR 2
+
/** A linked list of lines in a config file. */
typedef struct config_line_t {
char *key;
char *value;
struct config_line_t *next;
+ /** What special treatment (if any) does this line require? */
+ unsigned int command:2;
+ /** If true, subsequent assignments to this linelist should replace
+ * it, not extend it. Set only on the first item in a linelist in an
+ * or_options_t. */
+ unsigned int fragile:1;
} config_line_t;
typedef struct routerset_t routerset_t;
@@ -3250,6 +3266,8 @@ typedef struct {
disclaimer. This allows a server administrator to show
that they're running Tor and anyone visiting their server
will know this without any specialized knowledge. */
+ int DisableDebuggerAttachment; /**< Currently Linux only specific attempt to
+ disable ptrace; needs BSD testing. */
/** Boolean: if set, we start even if our resolv.conf file is missing
* or broken. */
int ServerDNSAllowBrokenConfig;
@@ -3434,6 +3452,15 @@ typedef struct {
* never use it. If -1, we do what the consensus says. */
int OptimisticData;
+ /** If 1, and we are using IOCP, we set the kernel socket SNDBUF and RCVBUF
+ * to 0 to try to save kernel memory and avoid the dread "Out of buffers"
+ * issue. */
+ int UserspaceIOCPBuffers;
+
+ /** If 1, we accept and launch no external network connections, except on
+ * control ports. */
+ int DisableNetwork;
+
} or_options_t;
/** Persistent state for an onion router, as saved to disk. */
diff --git a/src/or/router.c b/src/or/router.c
index 5d36939a8b..8fe45dd6f8 100644
--- a/src/or/router.c
+++ b/src/or/router.c
@@ -785,7 +785,7 @@ check_whether_dirport_reachable(void)
const or_options_t *options = get_options();
return !options->DirPort ||
options->AssumeReachable ||
- we_are_hibernating() ||
+ net_is_disabled() ||
can_reach_dir_port;
}
@@ -811,7 +811,7 @@ decide_to_advertise_dirport(const or_options_t *options, uint16_t dir_port)
return 0;
if (authdir_mode(options)) /* always publish */
return dir_port;
- if (we_are_hibernating())
+ if (net_is_disabled())
return 0;
if (!check_whether_dirport_reachable())
return 0;
@@ -979,6 +979,14 @@ router_perform_bandwidth_test(int num_circs, time_t now)
}
}
+/** Return true iff our network is in some sense disabled: either we're
+ * hibernating, entering hibernation, or */
+int
+net_is_disabled(void)
+{
+ return get_options()->DisableNetwork || we_are_hibernating();
+}
+
/** Return true iff we believe ourselves to be an authoritative
* directory server.
*/
diff --git a/src/or/router.h b/src/or/router.h
index 68eadbf4c2..6a9851cdbd 100644
--- a/src/or/router.h
+++ b/src/or/router.h
@@ -40,6 +40,8 @@ void router_orport_found_reachable(void);
void router_dirport_found_reachable(void);
void router_perform_bandwidth_test(int num_circs, time_t now);
+int net_is_disabled(void);
+
int authdir_mode(const or_options_t *options);
int authdir_mode_v1(const or_options_t *options);
int authdir_mode_v2(const or_options_t *options);
diff --git a/src/or/routerlist.c b/src/or/routerlist.c
index d97b978f43..689df99c57 100644
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@ -3244,7 +3244,7 @@ router_set_status(const char *digest, int up)
log_debug(LD_DIR,"Marking router %s as %s.",
node_describe(node), up ? "up" : "down");
#endif
- if (!up && node_is_me(node) && !we_are_hibernating())
+ if (!up && node_is_me(node) && !net_is_disabled())
log_warn(LD_NET, "We just marked ourself as down. Are your external "
"addresses reachable?");
node->is_running = up;
@@ -4009,6 +4009,8 @@ signed_desc_digest_is_recognized(signed_descriptor_t *desc)
void
update_all_descriptor_downloads(time_t now)
{
+ if (get_options()->DisableNetwork)
+ return;
update_router_descriptor_downloads(now);
update_microdesc_downloads(now);
launch_dummy_descriptor_download_as_needed(now, get_options());
@@ -4021,6 +4023,8 @@ routerlist_retry_directory_downloads(time_t now)
{
router_reset_status_download_failures();
router_reset_descriptor_download_failures();
+ if (get_options()->DisableNetwork)
+ return;
update_networkstatus_downloads(now);
update_all_descriptor_downloads(now);
}
diff --git a/src/or/transports.c b/src/or/transports.c
index 6e8200f407..10155c4475 100644
--- a/src/or/transports.c
+++ b/src/or/transports.c
@@ -13,11 +13,18 @@
#include "transports.h"
#include "util.h"
-static void set_managed_proxy_environment(char ***envp,
+#ifdef MS_WINDOWS
+static void set_managed_proxy_environment(LPVOID *envp,
const managed_proxy_t *mp);
+#else
+static int set_managed_proxy_environment(char ***envp,
+ const managed_proxy_t *mp);
+#endif
+
static INLINE int proxy_configuration_finished(const managed_proxy_t *mp);
-static void managed_proxy_destroy(managed_proxy_t *mp);
+static void managed_proxy_destroy(managed_proxy_t *mp,
+ int also_terminate_process);
static void handle_finished_proxy(managed_proxy_t *mp);
static void configure_proxy(managed_proxy_t *mp);
@@ -229,12 +236,10 @@ proxy_prepare_for_restart(managed_proxy_t *mp)
transport_t *t_tmp = NULL;
tor_assert(mp->conf_state == PT_PROTO_COMPLETED);
- tor_assert(mp->pid);
- /* kill the old obfsproxy process */
- tor_terminate_process(mp->pid);
- mp->pid = 0;
- fclose(mp->_stdout);
+ /* destroy the process handle and terminate the process. */
+ tor_process_handle_destroy(mp->process_handle, 1);
+ mp->process_handle = NULL;
/* destroy all its old transports. we no longer use them. */
SMARTLIST_FOREACH_BEGIN(mp->transports, const char *, t_name) {
@@ -256,52 +261,52 @@ proxy_prepare_for_restart(managed_proxy_t *mp)
static int
launch_managed_proxy(managed_proxy_t *mp)
{
- (void) mp;
- (void) set_managed_proxy_environment;
- return -1;
-#if 0
- /* XXXX023 we must reenable this code for managed proxies to work.
- * "All it needs" is revision to work with the new tor_spawn_background
- * API. */
- char **envp=NULL;
- int pid;
- process_handle_t proc;
- FILE *stdout_read = NULL;
- int stdout_pipe=-1, stderr_pipe=-1;
+ int retval;
+
+#ifdef MS_WINDOWS
+
+ LPVOID envp=NULL;
- /* prepare the environment variables for the managed proxy */
set_managed_proxy_environment(&envp, mp);
+ tor_assert(envp);
- pid = tor_spawn_background(mp->argv[0], (const char **)mp->argv,
- (const char **)envp, &proc);
- if (pid < 0) {
- log_warn(LD_GENERAL, "Managed proxy at '%s' failed at launch.",
- mp->argv[0]);
+ /* Passing NULL as lpApplicationName makes Windows search for the .exe */
+ retval = tor_spawn_background(NULL, (const char **)mp->argv, envp,
+ &mp->process_handle);
+
+ tor_free(envp);
+
+#else
+
+ char **envp=NULL;
+
+ /* prepare the environment variables for the managed proxy */
+ if (set_managed_proxy_environment(&envp, mp) < 0) {
+ log_warn(LD_GENERAL, "Could not setup the environment of "
+ "the managed proxy at '%s'.", mp->argv[0]);
+ free_execve_args(envp);
return -1;
}
+ retval = tor_spawn_background(mp->argv[0], (const char **)mp->argv,
+ (const char **)envp, &mp->process_handle);
+
/* free the memory allocated by set_managed_proxy_environment(). */
free_execve_args(envp);
- /* Set stdout/stderr pipes to be non-blocking */
-#ifdef _WIN32
- {
- u_long nonblocking = 1;
- ioctlsocket(stdout_pipe, FIONBIO, &nonblocking);
- }
-#else
- fcntl(stdout_pipe, F_SETFL, O_NONBLOCK);
#endif
- /* Open the buffered IO streams */
- stdout_read = fdopen(stdout_pipe, "r");
+ if (retval == PROCESS_STATUS_ERROR) {
+ log_warn(LD_GENERAL, "Managed proxy at '%s' failed at launch.",
+ mp->argv[0]);
+ return -1;
+ }
- log_info(LD_CONFIG, "Managed proxy has spawned at PID %d.", pid);
+ log_info(LD_CONFIG, "Managed proxy at '%s' has spawned with PID '%d'.",
+ mp->argv[0], tor_process_get_pid(mp->process_handle));
mp->conf_state = PT_PROTO_LAUNCHED;
- mp->_stdout = stdout_read;
- mp->pid = pid;
-#endif
+
return 0;
}
@@ -314,7 +319,8 @@ pt_configure_remaining_proxies(void)
log_debug(LD_CONFIG, "Configuring remaining managed proxies (%d)!",
unconfigured_proxies_n);
SMARTLIST_FOREACH_BEGIN(managed_proxy_list, managed_proxy_t *, mp) {
- tor_assert(mp->conf_state != PT_PROTO_BROKEN);
+ tor_assert(mp->conf_state != PT_PROTO_BROKEN ||
+ mp->conf_state != PT_PROTO_FAILED_LAUNCH);
if (mp->got_hup) {
mp->got_hup = 0;
@@ -343,6 +349,65 @@ pt_configure_remaining_proxies(void)
} SMARTLIST_FOREACH_END(mp);
}
+#ifdef MS_WINDOWS
+
+/** Attempt to continue configuring managed proxy <b>mp</b>. */
+static void
+configure_proxy(managed_proxy_t *mp)
+{
+ int pos;
+ char stdout_buf[200];
+ smartlist_t *lines = NULL;
+
+ /* if we haven't launched the proxy yet, do it now */
+ if (mp->conf_state == PT_PROTO_INFANT) {
+ if (launch_managed_proxy(mp) < 0) { /* launch fail */
+ mp->conf_state = PT_PROTO_FAILED_LAUNCH;
+ handle_finished_proxy(mp);
+ }
+ return;
+ }
+
+ tor_assert(mp->conf_state != PT_PROTO_INFANT);
+ tor_assert(mp->process_handle);
+
+ pos = tor_read_all_handle(tor_process_get_stdout_pipe(mp->process_handle),
+ stdout_buf, sizeof(stdout_buf) - 1, NULL);
+ if (pos < 0) {
+ log_notice(LD_GENERAL, "Failed to read data from managed proxy");
+ mp->conf_state = PT_PROTO_BROKEN;
+ goto done;
+ }
+
+ if (pos == 0) /* proxy has nothing interesting to say. */
+ return;
+
+ /* End with a null even if there isn't a \r\n at the end */
+ /* TODO: What if this is a partial line? */
+ stdout_buf[pos] = '\0';
+
+ /* Split up the buffer */
+ lines = smartlist_create();
+ tor_split_lines(lines, stdout_buf, pos);
+
+ /* Handle lines. */
+ SMARTLIST_FOREACH_BEGIN(lines, const char *, line) {
+ handle_proxy_line(line, mp);
+ if (proxy_configuration_finished(mp))
+ goto done;
+ } SMARTLIST_FOREACH_END(line);
+
+ done:
+ /* if the proxy finished configuring, exit the loop. */
+ if (proxy_configuration_finished(mp))
+ handle_finished_proxy(mp);
+
+ if (lines)
+ smartlist_free(lines);
+}
+
+#else /* MS_WINDOWS */
+
/** Attempt to continue configuring managed proxy <b>mp</b>. */
static void
configure_proxy(managed_proxy_t *mp)
@@ -352,15 +417,19 @@ configure_proxy(managed_proxy_t *mp)
/* if we haven't launched the proxy yet, do it now */
if (mp->conf_state == PT_PROTO_INFANT) {
- launch_managed_proxy(mp);
+ if (launch_managed_proxy(mp) < 0) { /* launch fail */
+ mp->conf_state = PT_PROTO_FAILED_LAUNCH;
+ handle_finished_proxy(mp);
+ }
return;
}
tor_assert(mp->conf_state != PT_PROTO_INFANT);
+ tor_assert(mp->process_handle);
while (1) {
- r = get_string_from_pipe(mp->_stdout, stdout_buf,
- sizeof(stdout_buf) - 1);
+ r = get_string_from_pipe(tor_process_get_stdout_pipe(mp->process_handle),
+ stdout_buf, sizeof(stdout_buf) - 1);
if (r == IO_STREAM_OKAY) { /* got a line; handle it! */
handle_proxy_line((const char *)stdout_buf, mp);
@@ -382,6 +451,8 @@ configure_proxy(managed_proxy_t *mp)
}
}
+#endif /* MS_WINDOWS */
+
/** Register server managed proxy <b>mp</b> transports to state */
static void
register_server_proxy(managed_proxy_t *mp)
@@ -394,6 +465,10 @@ register_server_proxy(managed_proxy_t *mp)
tor_assert(mp->conf_state != PT_PROTO_COMPLETED);
SMARTLIST_FOREACH_BEGIN(mp->transports, transport_t *, t) {
save_transport_to_state(t->name, &t->addr, t->port);
+ /* LOG_WARN so that the bridge operator can easily find the
+ transport's port in the log file and send it to the users. */
+ log_warn(LD_GENERAL, "Registered server transport '%s' at '%s:%d'",
+ t->name, fmt_addr(&t->addr), (int)t->port);
smartlist_add(sm_tmp, tor_strdup(t->name));
} SMARTLIST_FOREACH_END(t);
@@ -453,7 +528,8 @@ register_proxy(managed_proxy_t *mp)
/** Free memory allocated by managed proxy <b>mp</b>. */
static void
-managed_proxy_destroy(managed_proxy_t *mp)
+managed_proxy_destroy(managed_proxy_t *mp,
+ int also_terminate_process)
{
if (mp->conf_state != PT_PROTO_COMPLETED)
SMARTLIST_FOREACH(mp->transports, transport_t *, t, transport_free(t));
@@ -470,15 +546,11 @@ managed_proxy_destroy(managed_proxy_t *mp)
/* remove it from the list of managed proxies */
smartlist_remove(managed_proxy_list, mp);
- /* close its stdout stream */
- if (mp->_stdout)
- fclose(mp->_stdout);
-
/* free the argv */
free_execve_args(mp->argv);
- if (mp->pid)
- tor_terminate_process(mp->pid);
+ tor_process_handle_destroy(mp->process_handle, also_terminate_process);
+ mp->process_handle = NULL;
tor_free(mp);
}
@@ -489,7 +561,10 @@ handle_finished_proxy(managed_proxy_t *mp)
{
switch (mp->conf_state) {
case PT_PROTO_BROKEN: /* if broken: */
- managed_proxy_destroy(mp); /* annihilate it. */
+ managed_proxy_destroy(mp, 1); /* annihilate it. */
+ break;
+ case PT_PROTO_FAILED_LAUNCH: /* if it failed before launching: */
+ managed_proxy_destroy(mp, 0); /* destroy it but don't terminate */
break;
case PT_PROTO_CONFIGURED: /* if configured correctly: */
register_proxy(mp); /* register its transports */
@@ -515,7 +590,8 @@ static INLINE int
proxy_configuration_finished(const managed_proxy_t *mp)
{
return (mp->conf_state == PT_PROTO_CONFIGURED ||
- mp->conf_state == PT_PROTO_BROKEN);
+ mp->conf_state == PT_PROTO_BROKEN ||
+ mp->conf_state == PT_PROTO_FAILED_LAUNCH);
}
/** This function is called when a proxy sends an {S,C}METHODS DONE message. */
@@ -537,7 +613,7 @@ handle_methods_done(const managed_proxy_t *mp)
void
handle_proxy_line(const char *line, managed_proxy_t *mp)
{
- log_debug(LD_GENERAL, "Got a line from managed proxy: %s\n", line);
+ log_debug(LD_GENERAL, "Got a line from managed proxy: %s", line);
if (strlen(line) < SMALLEST_MANAGED_LINE_SIZE) {
log_warn(LD_GENERAL, "Managed proxy configuration line is too small. "
@@ -614,14 +690,16 @@ handle_proxy_line(const char *line, managed_proxy_t *mp)
return;
} else if (!strcmpstart(line, SPAWN_ERROR_MESSAGE)) {
log_warn(LD_GENERAL, "Could not launch managed proxy executable!");
- goto err;
+ mp->conf_state = PT_PROTO_FAILED_LAUNCH;
+ return;
}
log_warn(LD_CONFIG, "Unknown line received by managed proxy. (%s)", line);
err:
mp->conf_state = PT_PROTO_BROKEN;
- return;
+ log_warn(LD_CONFIG, "Managed proxy at '%s' failed the configuration protocol"
+ " and will be destroyed.", mp->argv ? mp->argv[0] : "");
}
/** Parses an ENV-ERROR <b>line</b> and warns the user accordingly. */
@@ -858,8 +936,115 @@ get_bindaddr_for_proxy(const managed_proxy_t *mp)
return bindaddr;
}
-/** Prepare the <b>envp</b> of managed proxy <b>mp</b> */
+#ifdef MS_WINDOWS
+
+/** Prepare the environment <b>envp</b> of managed proxy <b>mp</b>.
+ * <b>envp</b> is allocated on the heap and should be freed by the
+ * caller after its use. */
static void
+set_managed_proxy_environment(LPVOID *envp, const managed_proxy_t *mp)
+{
+ const or_options_t *options = get_options();
+ extern char **environ;
+
+ LPVOID tmp=NULL;
+
+ char *state_tmp=NULL;
+ char *state_env=NULL;
+ char *transports_to_launch=NULL;
+ char *transports_env=NULL;
+ char *bindaddr_tmp=NULL;
+ char *bindaddr_env=NULL;
+ char *orport_env=NULL;
+
+ char version_env[31]; /* XXX temp */
+ char extended_env[43]; /* XXX temp */
+
+ int env_size = 0;
+
+ /* A smartlist carrying all the env. variables that the managed
+ proxy should inherit. */
+ smartlist_t *envs = smartlist_create();
+
+ /* Copy the whole environment of the Tor process.
+ It should also copy PATH and HOME of the Tor process.*/
+ char **environ_tmp = environ;
+ while (*environ_tmp)
+ smartlist_add(envs, *environ_tmp++);
+
+ /* Create the TOR_PT_* environment variables. */
+ state_tmp = get_datadir_fname("pt_state/"); /* XXX temp */
+ tor_asprintf(&state_env, "TOR_PT_STATE_LOCATION=%s", state_tmp);
+
+ strcpy(version_env, "TOR_PT_MANAGED_TRANSPORT_VER=1");
+
+ transports_to_launch =
+ smartlist_join_strings(mp->transports_to_launch, ",", 0, NULL);
+
+ tor_asprintf(&transports_env,
+ mp->is_server ?
+ "TOR_PT_SERVER_TRANSPORTS=%s" : "TOR_PT_CLIENT_TRANSPORTS=%s",
+ transports_to_launch);
+
+ smartlist_add(envs, state_env);
+ smartlist_add(envs, version_env);
+ smartlist_add(envs, transports_env);
+
+ if (mp->is_server) {
+ tor_asprintf(&orport_env, "TOR_PT_ORPORT=127.0.0.1:%d", options->ORPort);
+
+ bindaddr_tmp = get_bindaddr_for_proxy(mp);
+ tor_asprintf(&bindaddr_env, "TOR_PT_SERVER_BINDADDR=%s", bindaddr_tmp);
+
+ strcpy(extended_env, "TOR_PT_EXTENDED_SERVER_PORT=127.0.0.1:4200");
+
+ smartlist_add(envs, orport_env);
+ smartlist_add(envs, extended_env);
+ smartlist_add(envs, bindaddr_env);
+ }
+
+ /* It seems like some versions of Windows need a sorted lpEnvironment
+ block. */
+ smartlist_sort_strings(envs);
+
+ /* An environment block consists of a null-terminated block of
+ null-terminated strings: */
+
+ /* Calculate the block's size. */
+ SMARTLIST_FOREACH(envs, const char *, s,
+ env_size += strlen(s) + 1);
+ env_size += 1; /* space for last NUL */
+
+ *envp = tor_malloc(env_size);
+ tmp = *envp;
+
+ /* Create the block. */
+ SMARTLIST_FOREACH_BEGIN(envs, const char *, s) {
+ memcpy(tmp, s, strlen(s)); /* copy the env. variable string */
+ tmp += strlen(s);
+ memset(tmp, '\0', 1); /* append NUL at the end of the string */
+ tmp += 1;
+ } SMARTLIST_FOREACH_END(s);
+ memset(tmp, '\0', 1); /* last NUL */
+
+ /* Finally, free the whole mess. */
+ tor_free(state_tmp);
+ tor_free(state_env);
+ tor_free(transports_to_launch);
+ tor_free(transports_env);
+ tor_free(bindaddr_tmp);
+ tor_free(bindaddr_env);
+ tor_free(orport_env);
+
+ smartlist_free(envs);
+}
+
+#else /* MS_WINDOWS */
+
+/** Prepare the environment <b>envp</b> of managed proxy <b>mp</b>.
+ * <b>envp</b> is allocated on the heap and should be freed by the
+ * caller after its use. */
+static int
set_managed_proxy_environment(char ***envp, const managed_proxy_t *mp)
{
const or_options_t *options = get_options();
@@ -867,7 +1052,10 @@ set_managed_proxy_environment(char ***envp, const managed_proxy_t *mp)
char *state_loc=NULL;
char *transports_to_launch=NULL;
char *bindaddr=NULL;
+ char *home_env=NULL;
+ char *path_env=NULL;
+ int r = -1;
int n_envs = mp->is_server ? ENVIRON_SIZE_SERVER : ENVIRON_SIZE_CLIENT;
/* allocate enough space for our env. vars and a NULL pointer */
@@ -878,8 +1066,13 @@ set_managed_proxy_environment(char ***envp, const managed_proxy_t *mp)
transports_to_launch =
smartlist_join_strings(mp->transports_to_launch, ",", 0, NULL);
- tor_asprintf(tmp++, "HOME=%s", getenv("HOME"));
- tor_asprintf(tmp++, "PATH=%s", getenv("PATH"));
+ home_env = getenv("HOME");
+ path_env = getenv("PATH");
+ if (!home_env || !path_env)
+ goto done;
+
+ tor_asprintf(tmp++, "HOME=%s", home_env);
+ tor_asprintf(tmp++, "PATH=%s", path_env);
tor_asprintf(tmp++, "TOR_PT_STATE_LOCATION=%s", state_loc);
tor_asprintf(tmp++, "TOR_PT_MANAGED_TRANSPORT_VER=1"); /* temp */
if (mp->is_server) {
@@ -896,11 +1089,18 @@ set_managed_proxy_environment(char ***envp, const managed_proxy_t *mp)
}
*tmp = NULL;
+ r = 0;
+
+ done:
tor_free(state_loc);
tor_free(transports_to_launch);
tor_free(bindaddr);
+
+ return r;
}
+#endif /* MS_WINDOWS */
+
/** Create and return a new managed proxy for <b>transport</b> using
* <b>proxy_argv</b>. If <b>is_server</b> is true, it's a server
* managed proxy. */
@@ -995,9 +1195,9 @@ pt_prepare_proxy_list_for_config_read(void)
SMARTLIST_FOREACH_BEGIN(managed_proxy_list, managed_proxy_t *, mp) {
/* Destroy unconfigured proxies. */
if (mp->conf_state != PT_PROTO_COMPLETED) {
- managed_proxy_destroy(mp);
- unconfigured_proxies_n--;
- continue;
+ managed_proxy_destroy(mp, 1);
+ unconfigured_proxies_n--;
+ continue;
}
tor_assert(mp->conf_state == PT_PROTO_COMPLETED);
@@ -1024,7 +1224,7 @@ sweep_proxy_list(void)
SMARTLIST_FOREACH_BEGIN(managed_proxy_list, managed_proxy_t *, mp) {
if (mp->marked_for_removal) {
SMARTLIST_DEL_CURRENT(managed_proxy_list, mp);
- managed_proxy_destroy(mp);
+ managed_proxy_destroy(mp, 1);
}
} SMARTLIST_FOREACH_END(mp);
}
@@ -1039,7 +1239,7 @@ pt_free_all(void)
free them. Otherwise, it hasn't registered its transports yet
and we should free them here. */
SMARTLIST_FOREACH(managed_proxy_list, managed_proxy_t *, mp,
- managed_proxy_destroy(mp));
+ managed_proxy_destroy(mp, 1));
smartlist_free(managed_proxy_list);
managed_proxy_list=NULL;
diff --git a/src/or/transports.h b/src/or/transports.h
index 4a93387596..314af2b3a0 100644
--- a/src/or/transports.h
+++ b/src/or/transports.h
@@ -36,7 +36,8 @@ enum pt_proto_state {
PT_PROTO_ACCEPTING_METHODS, /* accepting methods */
PT_PROTO_CONFIGURED, /* configured successfully */
PT_PROTO_COMPLETED, /* configure and registered its transports */
- PT_PROTO_BROKEN
+ PT_PROTO_BROKEN, /* broke during the protocol */
+ PT_PROTO_FAILED_LAUNCH /* failed while launching */
};
/** Structure containing information of a managed proxy. */
@@ -47,8 +48,8 @@ typedef struct {
int is_server; /* is it a server proxy? */
- FILE *_stdout; /* a stream to its stdout
- (closed in managed_proxy_destroy()) */
+ /* A pointer to the process handle of this managed proxy. */
+ process_handle_t *process_handle;
int pid; /* The Process ID this managed proxy is using. */
diff --git a/src/test/test_crypto.c b/src/test/test_crypto.c
index 1b338a29ab..cad8c2f556 100644
--- a/src/test/test_crypto.c
+++ b/src/test/test_crypto.c
@@ -7,6 +7,7 @@
#define CRYPTO_PRIVATE
#include "or.h"
#include "test.h"
+#include "aes.h"
/** Run unit tests for Diffie-Hellman functionality. */
static void
@@ -95,13 +96,16 @@ test_crypto_rng(void)
/** Run unit tests for our AES functionality */
static void
-test_crypto_aes(void)
+test_crypto_aes(void *arg)
{
char *data1 = NULL, *data2 = NULL, *data3 = NULL;
crypto_cipher_env_t *env1 = NULL, *env2 = NULL;
int i, j;
char *mem_op_hex_tmp=NULL;
+ int use_evp = !strcmp(arg,"evp");
+ evaluate_evp_for_aes(use_evp);
+
data1 = tor_malloc(1024);
data2 = tor_malloc(1024);
data3 = tor_malloc(1024);
@@ -670,7 +674,7 @@ test_crypto_s2k(void)
/** Test AES-CTR encryption and decryption with IV. */
static void
-test_crypto_aes_iv(void)
+test_crypto_aes_iv(void *arg)
{
crypto_cipher_env_t *cipher;
char *plain, *encrypted1, *encrypted2, *decrypted1, *decrypted2;
@@ -678,6 +682,9 @@ test_crypto_aes_iv(void)
char key1[16], key2[16];
ssize_t encrypted_size, decrypted_size;
+ int use_evp = !strcmp(arg,"evp");
+ evaluate_evp_for_aes(use_evp);
+
plain = tor_malloc(4095);
encrypted1 = tor_malloc(4095 + 1 + 16);
encrypted2 = tor_malloc(4095 + 1 + 16);
@@ -851,18 +858,36 @@ test_crypto_base32_decode(void)
;
}
+static void *
+pass_data_setup_fn(const struct testcase_t *testcase)
+{
+ return testcase->setup_data;
+}
+static int
+pass_data_cleanup_fn(const struct testcase_t *testcase, void *ptr)
+{
+ (void)ptr;
+ (void)testcase;
+ return 1;
+}
+static const struct testcase_setup_t pass_data = {
+ pass_data_setup_fn, pass_data_cleanup_fn
+};
+
#define CRYPTO_LEGACY(name) \
{ #name, legacy_test_helper, 0, &legacy_setup, test_crypto_ ## name }
struct testcase_t crypto_tests[] = {
CRYPTO_LEGACY(formats),
CRYPTO_LEGACY(rng),
- CRYPTO_LEGACY(aes),
+ { "aes_AES", test_crypto_aes, TT_FORK, &pass_data, (void*)"aes" },
+ { "aes_EVP", test_crypto_aes, TT_FORK, &pass_data, (void*)"evp" },
CRYPTO_LEGACY(sha),
CRYPTO_LEGACY(pk),
CRYPTO_LEGACY(dh),
CRYPTO_LEGACY(s2k),
- CRYPTO_LEGACY(aes_iv),
+ { "aes_iv_AES", test_crypto_aes_iv, TT_FORK, &pass_data, (void*)"aes" },
+ { "aes_iv_EVP", test_crypto_aes_iv, TT_FORK, &pass_data, (void*)"evp" },
CRYPTO_LEGACY(base32_decode),
END_OF_TESTCASES
};
diff --git a/src/test/test_dir.c b/src/test/test_dir.c
index 205d7b577c..5b7ce5cabe 100644
--- a/src/test/test_dir.c
+++ b/src/test/test_dir.c
@@ -620,13 +620,81 @@ test_dir_param_voting(void)
test_eq(0, networkstatus_get_param(&vote4, "foobar", 0, -100, 8));
smartlist_add(votes, &vote1);
+
+ /* Do the first tests without adding all the other votes, for
+ * networks without many dirauths. */
+
+ res = dirvote_compute_params(votes, 11, 6);
+ test_streq(res, "ab=90 abcd=20 cw=50 x-yz=-99");
+ tor_free(res);
+
+ res = dirvote_compute_params(votes, 12, 2);
+ test_streq(res, "");
+ tor_free(res);
+
+ res = dirvote_compute_params(votes, 12, 1);
+ test_streq(res, "ab=90 abcd=20 cw=50 x-yz=-99");
+ tor_free(res);
+
smartlist_add(votes, &vote2);
+
+ res = dirvote_compute_params(votes, 11, 2);
+ test_streq(res, "ab=27 abcd=20 cw=5 x-yz=-99");
+ tor_free(res);
+
+ res = dirvote_compute_params(votes, 12, 2);
+ test_streq(res, "ab=27 cw=5 x-yz=-99");
+ tor_free(res);
+
+ res = dirvote_compute_params(votes, 12, 3);
+ test_streq(res, "ab=27 cw=5 x-yz=-99");
+ tor_free(res);
+
+ res = dirvote_compute_params(votes, 12, 6);
+ test_streq(res, "");
+ tor_free(res);
+
smartlist_add(votes, &vote3);
+
+ res = dirvote_compute_params(votes, 11, 3);
+ test_streq(res, "ab=27 abcd=20 c=60 cw=50 x-yz=-9 zzzzz=101");
+ tor_free(res);
+
+ res = dirvote_compute_params(votes, 12, 3);
+ test_streq(res, "ab=27 abcd=20 cw=50 x-yz=-9");
+ tor_free(res);
+
+ res = dirvote_compute_params(votes, 12, 5);
+ test_streq(res, "cw=50 x-yz=-9");
+ tor_free(res);
+
+ res = dirvote_compute_params(votes, 12, 9);
+ test_streq(res, "cw=50 x-yz=-9");
+ tor_free(res);
+
smartlist_add(votes, &vote4);
- res = dirvote_compute_params(votes);
- test_streq(res,
- "ab=90 abcd=20 c=1 cw=50 x-yz=-9 zzzzz=101");
+ res = dirvote_compute_params(votes, 11, 4);
+ test_streq(res, "ab=90 abcd=20 c=1 cw=50 x-yz=-9 zzzzz=101");
+ tor_free(res);
+
+ res = dirvote_compute_params(votes, 12, 4);
+ test_streq(res, "ab=90 abcd=20 cw=50 x-yz=-9");
+ tor_free(res);
+
+ res = dirvote_compute_params(votes, 12, 5);
+ test_streq(res, "ab=90 abcd=20 cw=50 x-yz=-9");
+ tor_free(res);
+
+ /* Test that the special-cased "at least three dirauths voted for
+ * this param" logic works as expected. */
+ res = dirvote_compute_params(votes, 12, 6);
+ test_streq(res, "ab=90 abcd=20 cw=50 x-yz=-9");
+ tor_free(res);
+
+ res = dirvote_compute_params(votes, 12, 10);
+ test_streq(res, "ab=90 abcd=20 cw=50 x-yz=-9");
+ tor_free(res);
done:
tor_free(res);
@@ -1049,7 +1117,7 @@ test_dir_v3_networkstatus(void)
"Running:Stable:V2Dir:Valid");
tor_free(cp);
cp = smartlist_join_strings(con->net_params, ":", 0, NULL);
- test_streq(cp, "bar=2000000000:circuitwindow=80:foo=660");
+ test_streq(cp, "circuitwindow=80:foo=660");
tor_free(cp);
test_eq(4, smartlist_len(con->voters)); /*3 voters, 1 legacy key.*/
diff --git a/src/test/test_pt.c b/src/test/test_pt.c
index f97b21fa0d..45f441106e 100644
--- a/src/test/test_pt.c
+++ b/src/test/test_pt.c
@@ -91,7 +91,7 @@ test_pt_protocol(void)
{
char line[200];
- managed_proxy_t *mp = tor_malloc(sizeof(managed_proxy_t));
+ managed_proxy_t *mp = tor_malloc_zero(sizeof(managed_proxy_t));
mp->conf_state = PT_PROTO_LAUNCHED;
mp->transports = smartlist_create();
diff --git a/src/test/test_util.c b/src/test/test_util.c
index 64bf52e7b1..93f11cd208 100644
--- a/src/test/test_util.c
+++ b/src/test/test_util.c
@@ -1388,27 +1388,29 @@ run_util_spawn_background(const char *argv[], const char *expected_out,
{
int retval, exit_code;
ssize_t pos;
- process_handle_t process_handle;
+ process_handle_t *process_handle=NULL;
char stdout_buf[100], stderr_buf[100];
+ int status;
/* Start the program */
#ifdef MS_WINDOWS
- tor_spawn_background(NULL, argv, NULL, &process_handle);
+ status = tor_spawn_background(NULL, argv, NULL, &process_handle);
#else
- tor_spawn_background(argv[0], argv, NULL, &process_handle);
+ status = tor_spawn_background(argv[0], argv, NULL, &process_handle);
#endif
- tt_int_op(process_handle.status, ==, expected_status);
-
- /* If the process failed to start, don't bother continuing */
- if (process_handle.status == PROCESS_STATUS_ERROR)
+ tt_int_op(status, ==, expected_status);
+ if (status == PROCESS_STATUS_ERROR)
return;
- tt_int_op(process_handle.stdout_pipe, >, 0);
- tt_int_op(process_handle.stderr_pipe, >, 0);
+ tt_assert(process_handle != NULL);
+ tt_int_op(process_handle->status, ==, expected_status);
+
+ tt_int_op(process_handle->stdout_pipe, >, 0);
+ tt_int_op(process_handle->stderr_pipe, >, 0);
/* Check stdout */
- pos = tor_read_all_from_process_stdout(&process_handle, stdout_buf,
+ pos = tor_read_all_from_process_stdout(process_handle, stdout_buf,
sizeof(stdout_buf) - 1);
tt_assert(pos >= 0);
stdout_buf[pos] = '\0';
@@ -1422,7 +1424,7 @@ run_util_spawn_background(const char *argv[], const char *expected_out,
// TODO: Make test-child exit with something other than 0
/* Check stderr */
- pos = tor_read_all_from_process_stderr(&process_handle, stderr_buf,
+ pos = tor_read_all_from_process_stderr(process_handle, stderr_buf,
sizeof(stderr_buf) - 1);
tt_assert(pos >= 0);
stderr_buf[pos] = '\0';
@@ -1430,7 +1432,8 @@ run_util_spawn_background(const char *argv[], const char *expected_out,
tt_int_op(pos, ==, strlen(expected_err));
done:
- ;
+ if (process_handle)
+ tor_process_handle_destroy(process_handle, 1);
}
/** Check that we can launch a process and read the output */
@@ -1489,7 +1492,8 @@ test_util_spawn_background_partial_read(void *ptr)
int retval, exit_code;
ssize_t pos = -1;
- process_handle_t process_handle;
+ process_handle_t *process_handle=NULL;
+ int status;
char stdout_buf[100], stderr_buf[100];
#ifdef MS_WINDOWS
const char *argv[] = {"test-child.exe", "--test", NULL};
@@ -1510,21 +1514,23 @@ test_util_spawn_background_partial_read(void *ptr)
/* Start the program */
#ifdef MS_WINDOWS
- tor_spawn_background(NULL, argv, NULL, &process_handle);
+ status = tor_spawn_background(NULL, argv, NULL, &process_handle);
#else
- tor_spawn_background(argv[0], argv, NULL, &process_handle);
+ status = tor_spawn_background(argv[0], argv, NULL, &process_handle);
#endif
- tt_int_op(process_handle.status, ==, expected_status);
+ tt_int_op(status, ==, expected_status);
+ tt_assert(process_handle);
+ tt_int_op(process_handle->status, ==, expected_status);
/* Check stdout */
- for (expected_out_ctr =0; expected_out[expected_out_ctr] != NULL;) {
+ for (expected_out_ctr = 0; expected_out[expected_out_ctr] != NULL;) {
#ifdef MS_WINDOWS
- pos = tor_read_all_handle(process_handle.stdout_pipe, stdout_buf,
+ pos = tor_read_all_handle(process_handle->stdout_pipe, stdout_buf,
sizeof(stdout_buf) - 1, NULL);
#else
/* Check that we didn't read the end of file last time */
tt_assert(!eof);
- pos = tor_read_all_handle(process_handle.stdout_handle, stdout_buf,
+ pos = tor_read_all_handle(process_handle->stdout_handle, stdout_buf,
sizeof(stdout_buf) - 1, NULL, &eof);
#endif
log_info(LD_GENERAL, "tor_read_all_handle() returned %d", (int)pos);
@@ -1542,16 +1548,16 @@ test_util_spawn_background_partial_read(void *ptr)
/* The process should have exited without writing more */
#ifdef MS_WINDOWS
- pos = tor_read_all_handle(process_handle.stdout_pipe, stdout_buf,
+ pos = tor_read_all_handle(process_handle->stdout_pipe, stdout_buf,
sizeof(stdout_buf) - 1,
- &process_handle);
+ process_handle);
tt_int_op(pos, ==, 0);
#else
if (!eof) {
/* We should have got all the data, but maybe not the EOF flag */
- pos = tor_read_all_handle(process_handle.stdout_handle, stdout_buf,
+ pos = tor_read_all_handle(process_handle->stdout_handle, stdout_buf,
sizeof(stdout_buf) - 1,
- &process_handle, &eof);
+ process_handle, &eof);
tt_int_op(pos, ==, 0);
tt_assert(eof);
}
@@ -1566,7 +1572,7 @@ test_util_spawn_background_partial_read(void *ptr)
// TODO: Make test-child exit with something other than 0
/* Check stderr */
- pos = tor_read_all_from_process_stderr(&process_handle, stderr_buf,
+ pos = tor_read_all_from_process_stderr(process_handle, stderr_buf,
sizeof(stderr_buf) - 1);
tt_assert(pos >= 0);
stderr_buf[pos] = '\0';
@@ -1574,7 +1580,7 @@ test_util_spawn_background_partial_read(void *ptr)
tt_int_op(pos, ==, strlen(expected_err));
done:
- ;
+ tor_process_handle_destroy(process_handle, 1);
}
/**
diff --git a/src/tools/tor-gencert.c b/src/tools/tor-gencert.c
index 974a58becf..57f82b1bc7 100644
--- a/src/tools/tor-gencert.c
+++ b/src/tools/tor-gencert.c
@@ -153,7 +153,7 @@ parse_commandline(int argc, char **argv)
}
months_lifetime = atoi(argv[++i]);
if (months_lifetime > 24 || months_lifetime < 0) {
- fprintf(stderr, "Lifetime (in months) was out of range.");
+ fprintf(stderr, "Lifetime (in months) was out of range.\n");
return 1;
}
} else if (!strcmp(argv[i], "-r") || !strcmp(argv[i], "--reuse")) {