aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/compat.c9
-rw-r--r--src/common/compat.h8
-rw-r--r--src/common/container.c19
-rw-r--r--src/common/container.h1
-rw-r--r--src/common/crypto.c90
-rw-r--r--src/common/crypto.h14
-rw-r--r--src/common/crypto_curve25519.c2
-rw-r--r--src/common/crypto_curve25519.h5
-rw-r--r--src/common/crypto_format.c1
-rw-r--r--src/common/include.am43
-rw-r--r--src/common/log.c20
-rw-r--r--src/common/sandbox.c331
-rw-r--r--src/common/sandbox.h55
-rw-r--r--src/common/testsupport.h80
-rw-r--r--src/common/torlog.h7
-rw-r--r--src/common/tortls.c44
-rw-r--r--src/common/util.c105
-rw-r--r--src/common/util.h26
-rwxr-xr-xsrc/config/deanonymind.py27
-rw-r--r--src/config/geoip-manual91
-rw-r--r--src/or/addressmap.c2
-rw-r--r--src/or/addressmap.h6
-rw-r--r--src/or/buffers.c2
-rw-r--r--src/or/buffers.h4
-rw-r--r--src/or/channel.c71
-rw-r--r--src/or/channel.h4
-rw-r--r--src/or/circuitlist.c155
-rw-r--r--src/or/circuitlist.h11
-rw-r--r--src/or/circuitmux.c170
-rw-r--r--src/or/circuitmux.h19
-rw-r--r--src/or/circuitstats.c21
-rw-r--r--src/or/circuitstats.h21
-rw-r--r--src/or/config.c383
-rw-r--r--src/or/config.h21
-rw-r--r--src/or/confparse.c54
-rw-r--r--src/or/confparse.h3
-rw-r--r--src/or/connection.c198
-rw-r--r--src/or/connection.h8
-rw-r--r--src/or/connection_edge.c4
-rw-r--r--src/or/connection_edge.h6
-rw-r--r--src/or/control.c7
-rw-r--r--src/or/control.h4
-rw-r--r--src/or/directory.c88
-rw-r--r--src/or/dirserv.c23
-rw-r--r--src/or/dirserv.h23
-rw-r--r--src/or/dirvote.c25
-rw-r--r--src/or/dirvote.h14
-rw-r--r--src/or/entrynodes.c71
-rw-r--r--src/or/entrynodes.h11
-rw-r--r--src/or/geoip.c73
-rw-r--r--src/or/geoip.h8
-rw-r--r--src/or/hibernate.c2
-rw-r--r--src/or/hibernate.h2
-rw-r--r--src/or/include.am30
-rw-r--r--src/or/main.c41
-rw-r--r--src/or/main.h4
-rw-r--r--src/or/microdesc.c6
-rw-r--r--src/or/networkstatus.c4
-rw-r--r--src/or/ntmain.c1
-rw-r--r--src/or/or.h89
-rw-r--r--src/or/relay.c132
-rw-r--r--src/or/relay.h7
-rw-r--r--src/or/rephist.c48
-rw-r--r--src/or/replaycache.c19
-rw-r--r--src/or/replaycache.h4
-rw-r--r--src/or/router.c2
-rw-r--r--src/or/router.h4
-rw-r--r--src/or/routerlist.c64
-rw-r--r--src/or/routerlist.h9
-rw-r--r--src/or/transports.c62
-rw-r--r--src/or/transports.h14
-rw-r--r--src/test/bench.c2
-rw-r--r--src/test/include.am17
-rwxr-xr-xsrc/test/test-network.sh25
-rw-r--r--src/test/test.c133
-rw-r--r--src/test/test_addr.c102
-rw-r--r--src/test/test_circuitlist.c168
-rw-r--r--src/test/test_config.c272
-rw-r--r--src/test/test_crypto.c90
-rw-r--r--src/test/test_data.c5
-rw-r--r--src/test/test_dir.c4
-rw-r--r--src/test/test_pt.c55
-rw-r--r--src/test/test_replay.c170
-rw-r--r--src/test/test_util.c138
-rw-r--r--src/tools/tor-checkkey.c2
-rw-r--r--src/tools/tor-fw-helper/tor-fw-helper.c2
-rw-r--r--src/tools/tor-gencert.c2
-rw-r--r--src/win32/orconfig.h2
88 files changed, 3374 insertions, 847 deletions
diff --git a/src/common/compat.c b/src/common/compat.c
index 69eb0643d..0e943f38f 100644
--- a/src/common/compat.c
+++ b/src/common/compat.c
@@ -1746,6 +1746,15 @@ get_user_homedir(const char *username)
* actually examine the filesystem; does a purely syntactic modification.
*
* The parent of the root director is considered to be iteself.
+ *
+ * Path separators are the forward slash (/) everywhere and additionally
+ * the backslash (\) on Win32.
+ *
+ * Cuts off any number of trailing path separators but otherwise ignores
+ * them for purposes of finding the parent directory.
+ *
+ * Returns 0 if a parent directory was successfully found, -1 otherwise (fname
+ * did not have any path separators or only had them at the end).
* */
int
get_parent_directory(char *fname)
diff --git a/src/common/compat.h b/src/common/compat.h
index 8ab719052..258fc9902 100644
--- a/src/common/compat.h
+++ b/src/common/compat.h
@@ -84,13 +84,19 @@
/* ===== Compiler compatibility */
-/* GCC can check printf types on arbitrary functions. */
+/* GCC can check printf and scanf types on arbitrary functions. */
#ifdef __GNUC__
#define CHECK_PRINTF(formatIdx, firstArg) \
__attribute__ ((format(printf, formatIdx, firstArg)))
#else
#define CHECK_PRINTF(formatIdx, firstArg)
#endif
+#ifdef __GNUC__
+#define CHECK_SCANF(formatIdx, firstArg) \
+ __attribute__ ((format(scanf, formatIdx, firstArg)))
+#else
+#define CHECK_SCANF(formatIdx, firstArg)
+#endif
/* inline is __inline on windows. */
#ifdef _WIN32
diff --git a/src/common/container.c b/src/common/container.c
index eec497a3e..476dc8291 100644
--- a/src/common/container.c
+++ b/src/common/container.c
@@ -243,6 +243,25 @@ smartlist_strings_eq(const smartlist_t *sl1, const smartlist_t *sl2)
return 1;
}
+/** Return true iff the two lists contain the same int pointer values in
+ * the same order, or if they are both NULL. */
+int
+smartlist_ints_eq(const smartlist_t *sl1, const smartlist_t *sl2)
+{
+ if (sl1 == NULL)
+ return sl2 == NULL;
+ if (sl2 == NULL)
+ return 0;
+ if (smartlist_len(sl1) != smartlist_len(sl2))
+ return 0;
+ SMARTLIST_FOREACH(sl1, int *, cp1, {
+ int *cp2 = smartlist_get(sl2, cp1_sl_idx);
+ if (*cp1 != *cp2)
+ return 0;
+ });
+ return 1;
+}
+
/** Return true iff <b>sl</b> has some element E such that
* tor_memeq(E,<b>element</b>,DIGEST_LEN)
*/
diff --git a/src/common/container.h b/src/common/container.h
index 1a68b8f67..1bcc54066 100644
--- a/src/common/container.h
+++ b/src/common/container.h
@@ -42,6 +42,7 @@ int smartlist_contains_string_case(const smartlist_t *sl, const char *element);
int smartlist_contains_int_as_string(const smartlist_t *sl, int num);
int smartlist_strings_eq(const smartlist_t *sl1, const smartlist_t *sl2);
int smartlist_contains_digest(const smartlist_t *sl, const char *element);
+int smartlist_ints_eq(const smartlist_t *sl1, const smartlist_t *sl2);
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);
diff --git a/src/common/crypto.c b/src/common/crypto.c
index 0ababeaea..730ce0828 100644
--- a/src/common/crypto.c
+++ b/src/common/crypto.c
@@ -114,7 +114,6 @@ crypto_get_rsa_padding_overhead(int padding)
switch (padding)
{
case RSA_PKCS1_OAEP_PADDING: return PKCS1_OAEP_PADDING_OVERHEAD;
- case RSA_PKCS1_PADDING: return PKCS1_PADDING_OVERHEAD;
default: tor_assert(0); return -1;
}
}
@@ -126,7 +125,6 @@ crypto_get_rsa_padding(int padding)
{
switch (padding)
{
- case PK_PKCS1_PADDING: return RSA_PKCS1_PADDING;
case PK_PKCS1_OAEP_PADDING: return RSA_PKCS1_OAEP_PADDING;
default: tor_assert(0); return -1;
}
@@ -1154,22 +1152,21 @@ int
crypto_pk_asn1_encode(crypto_pk_t *pk, char *dest, size_t dest_len)
{
int len;
- unsigned char *buf, *cp;
- len = i2d_RSAPublicKey(pk->key, NULL);
- if (len < 0 || (size_t)len > dest_len || dest_len > SIZE_T_CEILING)
+ unsigned char *buf = NULL;
+
+ len = i2d_RSAPublicKey(pk->key, &buf);
+ if (len < 0 || buf == NULL)
return -1;
- cp = buf = tor_malloc(len+1);
- len = i2d_RSAPublicKey(pk->key, &cp);
- if (len < 0) {
- crypto_log_errors(LOG_WARN,"encoding public key");
- tor_free(buf);
+
+ if ((size_t)len > dest_len || dest_len > SIZE_T_CEILING) {
+ OPENSSL_free(buf);
return -1;
}
/* We don't encode directly into 'dest', because that would be illegal
* type-punning. (C99 is smarter than me, C99 is smarter than me...)
*/
memcpy(dest,buf,len);
- tor_free(buf);
+ OPENSSL_free(buf);
return len;
}
@@ -1200,24 +1197,17 @@ crypto_pk_asn1_decode(const char *str, size_t len)
int
crypto_pk_get_digest(crypto_pk_t *pk, char *digest_out)
{
- unsigned char *buf, *bufp;
+ unsigned char *buf = NULL;
int len;
- len = i2d_RSAPublicKey(pk->key, NULL);
- if (len < 0)
+ len = i2d_RSAPublicKey(pk->key, &buf);
+ if (len < 0 || buf == NULL)
return -1;
- buf = bufp = tor_malloc(len+1);
- len = i2d_RSAPublicKey(pk->key, &bufp);
- if (len < 0) {
- crypto_log_errors(LOG_WARN,"encoding public key");
- tor_free(buf);
- return -1;
- }
if (crypto_digest(digest_out, (char*)buf, len) < 0) {
- tor_free(buf);
+ OPENSSL_free(buf);
return -1;
}
- tor_free(buf);
+ OPENSSL_free(buf);
return 0;
}
@@ -1226,31 +1216,24 @@ crypto_pk_get_digest(crypto_pk_t *pk, char *digest_out)
int
crypto_pk_get_all_digests(crypto_pk_t *pk, digests_t *digests_out)
{
- unsigned char *buf, *bufp;
+ unsigned char *buf = NULL;
int len;
- len = i2d_RSAPublicKey(pk->key, NULL);
- if (len < 0)
- return -1;
- buf = bufp = tor_malloc(len+1);
- len = i2d_RSAPublicKey(pk->key, &bufp);
- if (len < 0) {
- crypto_log_errors(LOG_WARN,"encoding public key");
- tor_free(buf);
+ len = i2d_RSAPublicKey(pk->key, &buf);
+ if (len < 0 || buf == NULL)
return -1;
- }
if (crypto_digest_all(digests_out, (char*)buf, len) < 0) {
- tor_free(buf);
+ OPENSSL_free(buf);
return -1;
}
- tor_free(buf);
+ OPENSSL_free(buf);
return 0;
}
/** Copy <b>in</b> to the <b>outlen</b>-byte buffer <b>out</b>, adding spaces
* every four spaces. */
-/* static */ void
-add_spaces_to_fp(char *out, size_t outlen, const char *in)
+void
+crypto_add_spaces_to_fp(char *out, size_t outlen, const char *in)
{
int n = 0;
char *end = out+outlen;
@@ -1287,7 +1270,7 @@ crypto_pk_get_fingerprint(crypto_pk_t *pk, char *fp_out, int add_space)
}
base16_encode(hexdigest,sizeof(hexdigest),digest,DIGEST_LEN);
if (add_space) {
- add_spaces_to_fp(fp_out, FINGERPRINT_LEN+1, hexdigest);
+ crypto_add_spaces_to_fp(fp_out, FINGERPRINT_LEN+1, hexdigest);
} else {
strncpy(fp_out, hexdigest, HEX_DIGEST_LEN+1);
}
@@ -1637,21 +1620,6 @@ crypto_digest_smartlist(char *digest_out, size_t len_out,
crypto_digest_free(d);
}
-/** Compute the HMAC-SHA-1 of the <b>msg_len</b> bytes in <b>msg</b>, using
- * the <b>key</b> of length <b>key_len</b>. Store the DIGEST_LEN-byte result
- * in <b>hmac_out</b>.
- */
-void
-crypto_hmac_sha1(char *hmac_out,
- const char *key, size_t key_len,
- const char *msg, size_t msg_len)
-{
- tor_assert(key_len < INT_MAX);
- tor_assert(msg_len < INT_MAX);
- HMAC(EVP_sha1(), key, (int)key_len, (unsigned char*)msg, (int)msg_len,
- (unsigned char*)hmac_out, NULL);
-}
-
/** Compute the HMAC-SHA-256 of the <b>msg_len</b> bytes in <b>msg</b>, using
* the <b>key</b> of length <b>key_len</b>. Store the DIGEST256_LEN-byte
* result in <b>hmac_out</b>.
@@ -1720,7 +1688,7 @@ crypto_store_dynamic_dh_modulus(const char *fname)
{
int len, new_len;
DH *dh = NULL;
- unsigned char *dh_string_repr = NULL, *cp = NULL;
+ unsigned char *dh_string_repr = NULL;
char *base64_encoded_dh = NULL;
char *file_string = NULL;
int retval = -1;
@@ -1744,15 +1712,8 @@ crypto_store_dynamic_dh_modulus(const char *fname)
if (!BN_set_word(dh->g, DH_GENERATOR))
goto done;
- len = i2d_DHparams(dh, NULL);
- if (len < 0) {
- log_warn(LD_CRYPTO, "Error occured while DER encoding DH modulus (1).");
- goto done;
- }
-
- cp = dh_string_repr = tor_malloc_zero(len+1);
- len = i2d_DHparams(dh, &cp);
- if ((len < 0) || ((cp - dh_string_repr) != len)) {
+ len = i2d_DHparams(dh, &dh_string_repr);
+ if ((len < 0) || (dh_string_repr == NULL)) {
log_warn(LD_CRYPTO, "Error occured while DER encoding DH modulus (2).");
goto done;
}
@@ -1779,7 +1740,8 @@ crypto_store_dynamic_dh_modulus(const char *fname)
done:
if (dh)
DH_free(dh);
- tor_free(dh_string_repr);
+ if (dh_string_repr)
+ OPENSSL_free(dh_string_repr);
tor_free(base64_encoded_dh);
tor_free(file_string);
diff --git a/src/common/crypto.h b/src/common/crypto.h
index 2fbca4c26..651d553a4 100644
--- a/src/common/crypto.h
+++ b/src/common/crypto.h
@@ -15,6 +15,7 @@
#include <stdio.h>
#include "torint.h"
+#include "testsupport.h"
/*
Macro to create an arbitrary OpenSSL version number as used by
@@ -69,13 +70,9 @@
* signs removed. */
#define BASE64_DIGEST256_LEN 43
-/** Constant used to indicate PKCS1 padding for public-key encryption */
-#define PK_PKCS1_PADDING 60001
/** Constant used to indicate OAEP padding for public-key encryption */
#define PK_PKCS1_OAEP_PADDING 60002
-/** Number of bytes added for PKCS1 padding. */
-#define PKCS1_PADDING_OVERHEAD 11
/** Number of bytes added for PKCS1-OAEP padding. */
#define PKCS1_OAEP_PADDING_OVERHEAD 42
@@ -221,9 +218,6 @@ void crypto_digest_get_digest(crypto_digest_t *digest,
crypto_digest_t *crypto_digest_dup(const crypto_digest_t *digest);
void crypto_digest_assign(crypto_digest_t *into,
const crypto_digest_t *from);
-void crypto_hmac_sha1(char *hmac_out,
- const char *key, size_t key_len,
- const char *msg, size_t msg_len);
void crypto_hmac_sha256(char *hmac_out,
const char *key, size_t key_len,
const char *msg, size_t msg_len);
@@ -290,7 +284,6 @@ void secret_to_key(char *key_out, size_t key_out_len, const char *secret,
/** OpenSSL-based utility functions. */
void memwipe(void *mem, uint8_t byte, size_t sz);
-#ifdef CRYPTO_PRIVATE
/* Prototypes for private functions only used by tortls.c, crypto.c, and the
* unit tests. */
struct rsa_st;
@@ -301,9 +294,8 @@ crypto_pk_t *crypto_new_pk_from_rsa_(struct rsa_st *rsa);
struct evp_pkey_st *crypto_pk_get_evp_pkey_(crypto_pk_t *env,
int private);
struct dh_st *crypto_dh_get_dh_(crypto_dh_t *dh);
-/* Prototypes for private functions only used by crypto.c and test.c*/
-void add_spaces_to_fp(char *out, size_t outlen, const char *in);
-#endif
+
+void crypto_add_spaces_to_fp(char *out, size_t outlen, const char *in);
#endif
diff --git a/src/common/crypto_curve25519.c b/src/common/crypto_curve25519.c
index 88c723f37..9e83440e1 100644
--- a/src/common/crypto_curve25519.c
+++ b/src/common/crypto_curve25519.c
@@ -29,7 +29,7 @@ int curve25519_donna(uint8_t *mypublic,
#endif
#endif
-int
+STATIC int
curve25519_impl(uint8_t *output, const uint8_t *secret,
const uint8_t *basepoint)
{
diff --git a/src/common/crypto_curve25519.h b/src/common/crypto_curve25519.h
index 652f1883c..f9d533ba2 100644
--- a/src/common/crypto_curve25519.h
+++ b/src/common/crypto_curve25519.h
@@ -4,6 +4,7 @@
#ifndef TOR_CRYPTO_CURVE25519_H
#define TOR_CRYPTO_CURVE25519_H
+#include "testsupport.h"
#include "torint.h"
/** Length of a curve25519 public key when encoded. */
@@ -52,8 +53,8 @@ int curve25519_keypair_read_from_file(curve25519_keypair_t *keypair_out,
const char *fname);
#ifdef CRYPTO_CURVE25519_PRIVATE
-int curve25519_impl(uint8_t *output, const uint8_t *secret,
- const uint8_t *basepoint);
+STATIC int curve25519_impl(uint8_t *output, const uint8_t *secret,
+ const uint8_t *basepoint);
#endif
#endif
diff --git a/src/common/crypto_format.c b/src/common/crypto_format.c
index 93932f839..be669c8d2 100644
--- a/src/common/crypto_format.c
+++ b/src/common/crypto_format.c
@@ -3,7 +3,6 @@
/* Formatting and parsing code for crypto-related data structures. */
-#define CRYPTO_CURVE25519_PRIVATE
#include "orconfig.h"
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
diff --git a/src/common/include.am b/src/common/include.am
index b796ebfae..032befd20 100644
--- a/src/common/include.am
+++ b/src/common/include.am
@@ -1,5 +1,15 @@
-noinst_LIBRARIES+= src/common/libor.a src/common/libor-crypto.a src/common/libor-event.a
+noinst_LIBRARIES += \
+ src/common/libor.a \
+ src/common/libor-crypto.a \
+ src/common/libor-event.a
+
+if UNITTESTS_ENABLED
+noinst_LIBRARIES += \
+ src/common/libor-testing.a \
+ src/common/libor-crypto-testing.a \
+ src/common/libor-event-testing.a
+endif
EXTRA_DIST+= \
src/common/common_sha1.i \
@@ -14,9 +24,13 @@ else
libor_extra_source=
endif
+src_common_libcurve25519_donna_a_CFLAGS=
+
if BUILD_CURVE25519_DONNA
src_common_libcurve25519_donna_a_SOURCES=\
src/ext/curve25519_donna/curve25519-donna.c
+src_common_libcurve25519_donna_a_CFLAGS+=\
+ @F_OMIT_FRAME_POINTER@
noinst_LIBRARIES+=src/common/libcurve25519_donna.a
LIBDONNA=src/common/libcurve25519_donna.a
else
@@ -30,13 +44,11 @@ LIBDONNA=
endif
endif
-src_common_libcurve25519_donna_a_CFLAGS =
-
if CURVE25519_ENABLED
libcrypto_extra_source=src/common/crypto_curve25519.c
endif
-src_common_libor_a_SOURCES = \
+LIBOR_A_SOURCES = \
src/common/address.c \
src/common/compat.c \
src/common/container.c \
@@ -47,9 +59,10 @@ src_common_libor_a_SOURCES = \
src/common/procmon.c \
src/common/util.c \
src/common/util_codedigest.c \
+ src/common/sandbox.c \
$(libor_extra_source)
-src_common_libor_crypto_a_SOURCES = \
+LIBOR_CRYPTO_A_SOURCES = \
src/common/aes.c \
src/common/crypto.c \
src/common/crypto_format.c \
@@ -57,7 +70,23 @@ src_common_libor_crypto_a_SOURCES = \
src/common/tortls.c \
$(libcrypto_extra_source)
-src_common_libor_event_a_SOURCES = src/common/compat_libevent.c
+LIBOR_EVENT_A_SOURCES = src/common/compat_libevent.c
+
+src_common_libor_a_SOURCES = $(LIBOR_A_SOURCES)
+src_common_libor_crypto_a_SOURCES = $(LIBOR_CRYPTO_A_SOURCES)
+src_common_libor_event_a_SOURCES = $(LIBOR_EVENT_A_SOURCES)
+
+src_common_libor_testing_a_SOURCES = $(LIBOR_A_SOURCES)
+src_common_libor_crypto_testing_a_SOURCES = $(LIBOR_CRYPTO_A_SOURCES)
+src_common_libor_event_testing_a_SOURCES = $(LIBOR_EVENT_A_SOURCES)
+
+src_common_libor_testing_a_CPPFLAGS = -DTOR_UNIT_TESTS $(AM_CPPFLAGS)
+src_common_libor_crypto_testing_a_CPPFLAGS = -DTOR_UNIT_TESTS $(AM_CPPFLAGS)
+src_common_libor_event_testing_a_CPPFLAGS = -DTOR_UNIT_TESTS $(AM_CPPFLAGS)
+src_common_libor_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+src_common_libor_crypto_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+src_common_libor_event_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+
COMMONHEADERS = \
src/common/address.h \
@@ -72,6 +101,8 @@ COMMONHEADERS = \
src/common/memarea.h \
src/common/mempool.h \
src/common/procmon.h \
+ src/common/sandbox.h \
+ src/common/testsupport.h \
src/common/torgzip.h \
src/common/torint.h \
src/common/torlog.h \
diff --git a/src/common/log.c b/src/common/log.c
index e196a1128..303fba93a 100644
--- a/src/common/log.c
+++ b/src/common/log.c
@@ -36,6 +36,10 @@
#include "torlog.h"
#include "container.h"
+/** Given a severity, yields an index into log_severity_list_t.masks to use
+ * for that severity. */
+#define SEVERITY_MASK_IDX(sev) ((sev) - LOG_ERR)
+
/** @{ */
/** The string we stick at the end of a log message when it is too long,
* and its length. */
@@ -1138,6 +1142,22 @@ get_min_log_level(void)
return min;
}
+/** Return the fd of a file log that is receiving ERR messages, or -1 if
+ * no such log exists. */
+int
+get_err_logging_fd(void)
+{
+ const logfile_t *lf;
+ for (lf = logfiles; lf; lf = lf->next) {
+ if (lf->is_temporary || lf->is_syslog || !lf->filename ||
+ lf->callback || lf->seems_dead || lf->fd < 0)
+ continue;
+ if (lf->severities->masks[LOG_ERR] & LD_GENERAL)
+ return lf->fd;
+ }
+ return -1;
+}
+
/** Switch all logs to output at most verbose level. */
void
switch_logs_debug(void)
diff --git a/src/common/sandbox.c b/src/common/sandbox.c
new file mode 100644
index 000000000..dbb1657cd
--- /dev/null
+++ b/src/common/sandbox.c
@@ -0,0 +1,331 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file sandbox.c
+ * \brief Code to enable sandboxing.
+ **/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "orconfig.h"
+#include "sandbox.h"
+#include "torlog.h"
+#include "util.h"
+
+#if defined(HAVE_SECCOMP_H) && defined(__linux__)
+#define USE_LIBSECCOMP
+#endif
+
+#define DEBUGGING_CLOSE
+
+#if defined(USE_LIBSECCOMP)
+
+#include <sys/syscall.h>
+#include <seccomp.h>
+#include <signal.h>
+#include <unistd.h>
+
+/** Variable used for storing all syscall numbers that will be allowed with the
+ * stage 1 general Tor sandbox.
+ */
+static int general_filter[] = {
+ SCMP_SYS(access),
+ SCMP_SYS(brk),
+ SCMP_SYS(clock_gettime),
+ SCMP_SYS(close),
+ SCMP_SYS(clone),
+ SCMP_SYS(epoll_create),
+ SCMP_SYS(epoll_ctl),
+ SCMP_SYS(epoll_wait),
+ SCMP_SYS(execve),
+ SCMP_SYS(fcntl),
+#ifdef __NR_fcntl64
+ /* Older libseccomp versions don't define PNR entries for all of these,
+ * so we need to ifdef them here.*/
+ SCMP_SYS(fcntl64),
+#endif
+ SCMP_SYS(flock),
+ SCMP_SYS(fstat),
+#ifdef __NR_fstat64
+ SCMP_SYS(fstat64),
+#endif
+ SCMP_SYS(futex),
+ SCMP_SYS(getdents64),
+ SCMP_SYS(getegid),
+#ifdef __NR_getegid32
+ SCMP_SYS(getegid32),
+#endif
+ SCMP_SYS(geteuid),
+#ifdef __NR_geteuid32
+ SCMP_SYS(geteuid32),
+#endif
+ SCMP_SYS(getgid),
+#ifdef __NR_getgid32
+ SCMP_SYS(getgid32),
+#endif
+ SCMP_SYS(getrlimit),
+ SCMP_SYS(gettimeofday),
+ SCMP_SYS(getuid),
+#ifdef __NR_getuid32
+ SCMP_SYS(getuid32),
+#endif
+ SCMP_SYS(lseek),
+#ifdef __NR__llseek
+ SCMP_SYS(_llseek),
+#endif
+ SCMP_SYS(mkdir),
+ SCMP_SYS(mlockall),
+ SCMP_SYS(mmap),
+#ifdef __NR_mmap2
+ SCMP_SYS(mmap2),
+#endif
+ SCMP_SYS(mprotect),
+ SCMP_SYS(mremap),
+ SCMP_SYS(munmap),
+ SCMP_SYS(open),
+ SCMP_SYS(openat),
+ SCMP_SYS(poll),
+ SCMP_SYS(prctl),
+ SCMP_SYS(read),
+ SCMP_SYS(rename),
+ SCMP_SYS(rt_sigaction),
+ SCMP_SYS(rt_sigprocmask),
+ SCMP_SYS(rt_sigreturn),
+#ifdef __NR_sigreturn
+ SCMP_SYS(sigreturn),
+#endif
+ SCMP_SYS(set_robust_list),
+ SCMP_SYS(set_thread_area),
+ SCMP_SYS(set_tid_address),
+ SCMP_SYS(stat),
+#ifdef __NR_stat64
+ SCMP_SYS(stat64),
+#endif
+ SCMP_SYS(time),
+ SCMP_SYS(uname),
+ SCMP_SYS(write),
+ SCMP_SYS(exit_group),
+ SCMP_SYS(exit),
+
+ // socket syscalls
+ SCMP_SYS(accept4),
+ SCMP_SYS(bind),
+ SCMP_SYS(connect),
+ SCMP_SYS(getsockname),
+ SCMP_SYS(getsockopt),
+ SCMP_SYS(listen),
+#if __NR_recv >= 0
+ /* This is a kludge; It's necessary on 64-bit with libseccomp 1.0.0; I
+ * don't know if other 64-bit or other versions require it. */
+ SCMP_SYS(recv),
+#endif
+ SCMP_SYS(recvmsg),
+#if __NR_send >= 0
+ SCMP_SYS(send),
+#endif
+ SCMP_SYS(sendto),
+ SCMP_SYS(setsockopt),
+ SCMP_SYS(socket),
+ SCMP_SYS(socketpair),
+
+ // TODO: remove when accept4 is fixed
+#ifdef __NR_socketcall
+ SCMP_SYS(socketcall),
+#endif
+
+ SCMP_SYS(recvfrom),
+ SCMP_SYS(unlink)
+};
+
+/**
+ * Function responsible for setting up and enabling a global syscall filter.
+ * The function is a prototype developed for stage 1 of sandboxing Tor.
+ * Returns 0 on success.
+ */
+static int
+install_glob_syscall_filter(void)
+{
+ int rc = 0, i, filter_size;
+ scmp_filter_ctx ctx;
+
+ ctx = seccomp_init(SCMP_ACT_TRAP);
+ if (ctx == NULL) {
+ log_err(LD_BUG,"(Sandbox) failed to initialise libseccomp context");
+ rc = -1;
+ goto end;
+ }
+
+ if (general_filter != NULL) {
+ filter_size = sizeof(general_filter) / sizeof(general_filter[0]);
+ } else {
+ filter_size = 0;
+ }
+
+ // add general filters
+ for (i = 0; i < filter_size; i++) {
+ rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, general_filter[i], 0);
+ if (rc != 0) {
+ log_err(LD_BUG,"(Sandbox) failed to add syscall index %d, "
+ "received libseccomp error %d", i, rc);
+ goto end;
+ }
+ }
+
+ rc = seccomp_load(ctx);
+
+ end:
+ seccomp_release(ctx);
+ return (rc < 0 ? -rc : rc);
+}
+
+/** Additional file descriptor to use when logging seccomp2 failures */
+static int sigsys_debugging_fd = -1;
+
+/** Use the file descriptor <b>fd</b> to log seccomp2 failures. */
+static void
+sigsys_set_debugging_fd(int fd)
+{
+ sigsys_debugging_fd = fd;
+}
+
+/**
+ * Function called when a SIGSYS is caught by the application. It notifies the
+ * user that an error has occurred and either terminates or allows the
+ * application to continue execution, based on the DEBUGGING_CLOSE symbol.
+ */
+static void
+sigsys_debugging(int nr, siginfo_t *info, void *void_context)
+{
+ ucontext_t *ctx = (ucontext_t *) (void_context);
+ char message[256];
+ int rv = 0, syscall, length, err;
+ (void) nr;
+
+ if (info->si_code != SYS_SECCOMP)
+ return;
+
+ if (!ctx)
+ return;
+
+ syscall = ctx->uc_mcontext.gregs[REG_SYSCALL];
+
+ strlcpy(message, "\n\n(Sandbox) Caught a bad syscall attempt (syscall 0x",
+ sizeof(message));
+ (void) format_hex_number_sigsafe(syscall, message+strlen(message),
+ sizeof(message)-strlen(message));
+ strlcat(message, ")\n", sizeof(message));
+ length = strlen(message);
+
+ err = 0;
+ if (sigsys_debugging_fd >= 0) {
+ rv = write(sigsys_debugging_fd, message, length);
+ err += rv != length;
+ }
+
+ rv = write(STDOUT_FILENO, message, length);
+ err += rv != length;
+
+ if (err)
+ _exit(2);
+
+#if defined(DEBUGGING_CLOSE)
+ _exit(1);
+#endif // DEBUGGING_CLOSE
+}
+
+/**
+ * Function that adds a handler for SIGSYS, which is the signal thrown
+ * when the application is issuing a syscall which is not allowed. The
+ * main purpose of this function is to help with debugging by identifying
+ * filtered syscalls.
+ */
+static int
+install_sigsys_debugging(void)
+{
+ struct sigaction act;
+ sigset_t mask;
+
+ memset(&act, 0, sizeof(act));
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGSYS);
+
+ act.sa_sigaction = &sigsys_debugging;
+ act.sa_flags = SA_SIGINFO;
+ if (sigaction(SIGSYS, &act, NULL) < 0) {
+ log_err(LD_BUG,"(Sandbox) Failed to register SIGSYS signal handler");
+ return -1;
+ }
+
+ if (sigprocmask(SIG_UNBLOCK, &mask, NULL)) {
+ log_err(LD_BUG,"(Sandbox) Failed call to sigprocmask()");
+ return -2;
+ }
+
+ return 0;
+}
+#endif // USE_LIBSECCOMP
+
+#ifdef USE_LIBSECCOMP
+/**
+ * Initialises the syscall sandbox filter for any linux architecture, taking
+ * into account various available features for different linux flavours.
+ */
+static int
+initialise_libseccomp_sandbox(void)
+{
+ if (install_sigsys_debugging())
+ return -1;
+
+ if (install_glob_syscall_filter())
+ return -2;
+
+ return 0;
+}
+
+#endif // USE_LIBSECCOMP
+
+/**
+ * Enables the stage 1 general sandbox. It applies a syscall filter which does
+ * not restrict any Tor features. The filter is representative for the whole
+ * application.
+ */
+int
+tor_global_sandbox(void)
+{
+
+#if defined(USE_LIBSECCOMP)
+ return initialise_libseccomp_sandbox();
+
+#elif defined(_WIN32)
+ log_warn(LD_BUG,"Windows sandboxing is not implemented. The feature is "
+ "currently disabled.");
+ return 0;
+
+#elif defined(TARGET_OS_MAC)
+ log_warn(LD_BUG,"Mac OSX sandboxing is not implemented. The feature is "
+ "currently disabled");
+ return 0;
+#else
+ log_warn(LD_BUG,"Sandboxing is not implemented for your platform. The "
+ "feature is currently disabled");
+ return 0;
+#endif
+}
+
+/** Use <b>fd</b> to log non-survivable sandbox violations. */
+void
+sandbox_set_debugging_fd(int fd)
+{
+#ifdef USE_LIBSECCOMP
+ sigsys_set_debugging_fd(fd);
+#else
+ (void)fd;
+#endif
+}
+
diff --git a/src/common/sandbox.h b/src/common/sandbox.h
new file mode 100644
index 000000000..bd6f0cfb4
--- /dev/null
+++ b/src/common/sandbox.h
@@ -0,0 +1,55 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file sandbox.h
+ * \brief Header file for sandbox.c.
+ **/
+
+#ifndef SANDBOX_H_
+#define SANDBOX_H_
+
+#ifndef SYS_SECCOMP
+
+/**
+ * Used by SIGSYS signal handler to check if the signal was issued due to a
+ * seccomp2 filter violation.
+ */
+#define SYS_SECCOMP 1
+
+#endif
+
+/**
+ * Linux definitions
+ */
+#ifdef __linux__
+
+#define __USE_GNU
+#include <sys/ucontext.h>
+
+/**
+ * Linux 32 bit definitions
+ */
+#if defined(__i386__)
+
+#define REG_SYSCALL REG_EAX
+
+/**
+ * Linux 64 bit definitions
+ */
+#elif defined(__x86_64__)
+
+#define REG_SYSCALL REG_RAX
+
+#endif
+
+#endif // __linux__
+
+void sandbox_set_debugging_fd(int fd);
+int tor_global_sandbox(void);
+
+#endif /* SANDBOX_H_ */
+
diff --git a/src/common/testsupport.h b/src/common/testsupport.h
new file mode 100644
index 000000000..4a4f50b69
--- /dev/null
+++ b/src/common/testsupport.h
@@ -0,0 +1,80 @@
+/* Copyright (c) 2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_TESTSUPPORT_H
+#define TOR_TESTSUPPORT_H
+
+#ifdef TOR_UNIT_TESTS
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+/** Quick and dirty macros to implement test mocking.
+ *
+ * To use them, suppose that you have a function you'd like to mock
+ * with the signature "void writebuf(size_t n, char *buf)". You can then
+ * declare the function as:
+ *
+ * MOCK_DECL(void, writebuf, (size_t n, char *buf));
+ *
+ * and implement it as:
+ *
+ * MOCK_IMPL(void
+ * writebuf,(size_t n, char *buf)
+ * {
+ * ...
+ * }
+ *
+ * For the non-testing build, this will expand simply into:
+ *
+ * void writebuf(size_t n, char *buf);
+ * void
+ * writebuf(size_t n, char *buf)
+ * {
+ * ...
+ * }
+ *
+ * But for the testing case, it will expand into:
+ *
+ * void writebuf__real(size_t n, char *buf);
+ * extern void (*writebuf)(size_t n, char *buf);
+ *
+ * void (*writebuf)(size_t n, char *buf) = writebuf__real;
+ * void
+ * writebuf__real(size_t n, char *buf)
+ * {
+ * ...
+ * }
+ *
+ * This is not a great mocking system! It is deliberately "the simplest
+ * thing that could work", and pays for its simplicity in its lack of
+ * features, and in its uglification of the Tor code. Replacing it with
+ * something clever would be a fine thing.
+ *
+ * @{ */
+#ifdef TOR_UNIT_TESTS
+#define MOCK_DECL(rv, funcname, arglist) \
+ rv funcname ##__real arglist; \
+ extern rv(*funcname) arglist
+#define MOCK_IMPL(rv, funcname, arglist) \
+ rv(*funcname) arglist = funcname ##__real; \
+ rv funcname ##__real arglist
+#define MOCK(func, replacement) \
+ do { \
+ (func) = (replacement); \
+ } while (0)
+#define UNMOCK(func) \
+ do { \
+ func = func ##__real; \
+ } while (0)
+#else
+#define MOCK_DECL(rv, funcname, arglist) \
+ rv funcname arglist
+#define MOCK_IMPL(rv, funcname, arglist) \
+ rv funcname arglist
+#endif
+/** @} */
+
+#endif
+
diff --git a/src/common/torlog.h b/src/common/torlog.h
index 8675d7b6e..ecd7e121e 100644
--- a/src/common/torlog.h
+++ b/src/common/torlog.h
@@ -114,12 +114,6 @@ typedef struct log_severity_list_t {
log_domain_mask_t masks[LOG_DEBUG-LOG_ERR+1];
} log_severity_list_t;
-#ifdef LOG_PRIVATE
-/** Given a severity, yields an index into log_severity_list_t.masks to use
- * for that severity. */
-#define SEVERITY_MASK_IDX(sev) ((sev) - LOG_ERR)
-#endif
-
/** Callback type used for add_callback_log. */
typedef void (*log_callback)(int severity, uint32_t domain, const char *msg);
@@ -142,6 +136,7 @@ int get_min_log_level(void);
void switch_logs_debug(void);
void logs_free_all(void);
void add_temp_log(int min_severity);
+int get_err_logging_fd(void);
void close_temp_logs(void);
void rollback_log_changes(void);
void mark_logs_temp(void);
diff --git a/src/common/tortls.c b/src/common/tortls.c
index b7e5bc1a5..df706b001 100644
--- a/src/common/tortls.c
+++ b/src/common/tortls.c
@@ -48,9 +48,6 @@
#include "compat_libevent.h"
#endif
-#define CRYPTO_PRIVATE /* to import prototypes from crypto.h */
-#define TORTLS_PRIVATE
-
#include "crypto.h"
#include "tortls.h"
#include "util.h"
@@ -806,24 +803,24 @@ tor_cert_new(X509 *x509_cert)
tor_cert_t *cert;
EVP_PKEY *pkey;
RSA *rsa;
- int length, length2;
- unsigned char *cp;
+ int length;
+ unsigned char *buf = NULL;
if (!x509_cert)
return NULL;
- length = i2d_X509(x509_cert, NULL);
+ length = i2d_X509(x509_cert, &buf);
cert = tor_malloc_zero(sizeof(tor_cert_t));
- if (length <= 0) {
+ if (length <= 0 || buf == NULL) {
tor_free(cert);
log_err(LD_CRYPTO, "Couldn't get length of encoded x509 certificate");
X509_free(x509_cert);
return NULL;
}
cert->encoded_len = (size_t) length;
- cp = cert->encoded = tor_malloc(length);
- length2 = i2d_X509(x509_cert, &cp);
- tor_assert(length2 == length);
+ cert->encoded = tor_malloc(length);
+ memcpy(cert->encoded, buf, length);
+ OPENSSL_free(buf);
cert->cert = x509_cert;
@@ -979,31 +976,6 @@ tor_tls_cert_get_key(tor_cert_t *cert)
return result;
}
-/** Return true iff <b>a</b> and <b>b</b> represent the same public key. */
-static int
-pkey_eq(EVP_PKEY *a, EVP_PKEY *b)
-{
- /* We'd like to do this, but openssl 0.9.7 doesn't have it:
- return EVP_PKEY_cmp(a,b) == 1;
- */
- unsigned char *a_enc=NULL, *b_enc=NULL, *a_ptr, *b_ptr;
- int a_len1, b_len1, a_len2, b_len2, result;
- a_len1 = i2d_PublicKey(a, NULL);
- b_len1 = i2d_PublicKey(b, NULL);
- if (a_len1 != b_len1)
- return 0;
- a_ptr = a_enc = tor_malloc(a_len1);
- b_ptr = b_enc = tor_malloc(b_len1);
- a_len2 = i2d_PublicKey(a, &a_ptr);
- b_len2 = i2d_PublicKey(b, &b_ptr);
- tor_assert(a_len2 == a_len1);
- tor_assert(b_len2 == b_len1);
- result = tor_memeq(a_enc, b_enc, a_len1);
- tor_free(a_enc);
- tor_free(b_enc);
- return result;
-}
-
/** Return true iff the other side of <b>tls</b> has authenticated to us, and
* the key certified in <b>cert</b> is the same as the key they used to do it.
*/
@@ -1019,7 +991,7 @@ tor_tls_cert_matches_key(const tor_tls_t *tls, const tor_cert_t *cert)
link_key = X509_get_pubkey(peercert);
cert_key = X509_get_pubkey(cert->cert);
- result = link_key && cert_key && pkey_eq(cert_key, link_key);
+ result = link_key && cert_key && EVP_PKEY_cmp(cert_key, link_key) == 1;
X509_free(peercert);
if (link_key)
diff --git a/src/common/util.c b/src/common/util.c
index db160fdf0..d9913dda4 100644
--- a/src/common/util.c
+++ b/src/common/util.c
@@ -879,6 +879,39 @@ tor_digest_is_zero(const char *digest)
return tor_memeq(digest, ZERO_DIGEST, DIGEST_LEN);
}
+/** Return true if <b>string</b> is a valid '<key>=[<value>]' string.
+ * <value> is optional, to indicate the empty string. Log at logging
+ * <b>severity</b> if something ugly happens. */
+int
+string_is_key_value(int severity, const char *string)
+{
+ /* position of equal sign in string */
+ const char *equal_sign_pos = NULL;
+
+ tor_assert(string);
+
+ if (strlen(string) < 2) { /* "x=" is shortest args string */
+ tor_log(severity, LD_GENERAL, "'%s' is too short to be a k=v value.",
+ escaped(string));
+ return 0;
+ }
+
+ equal_sign_pos = strchr(string, '=');
+ if (!equal_sign_pos) {
+ tor_log(severity, LD_GENERAL, "'%s' is not a k=v value.", escaped(string));
+ return 0;
+ }
+
+ /* validate that the '=' is not in the beginning of the string. */
+ if (equal_sign_pos == string) {
+ tor_log(severity, LD_GENERAL, "'%s' is not a valid k=v value.",
+ escaped(string));
+ return 0;
+ }
+
+ return 1;
+}
+
/** Return true iff the DIGEST256_LEN bytes in digest are all zero. */
int
tor_digest256_is_zero(const char *digest)
@@ -1190,6 +1223,46 @@ escaped(const char *s)
return escaped_val_;
}
+/** Escape every ";" or "\" character of <b>string</b>. Use
+ * <b>escape_char</b> as the character to use for escaping.
+ * The returned string is allocated on the heap and it's the
+ * responsibility of the caller to free it. */
+char *
+tor_escape_str_for_socks_arg(const char *string)
+{
+ char *new_string = NULL;
+ char *new_cp = NULL;
+ size_t length, new_length;
+ static const char *chars_to_escape = ";\\";
+
+ tor_assert(string);
+
+ length = strlen(string);
+
+ if (!length) /* If we were given the empty string, return the same. */
+ return tor_strdup("");
+ /* (new_length > SIZE_MAX) => ((length * 2) + 1 > SIZE_MAX) =>
+ (length*2 > SIZE_MAX - 1) => (length > (SIZE_MAX - 1)/2) */
+ if (length > (SIZE_MAX - 1)/2) /* check for overflow */
+ return NULL;
+
+ /* this should be enough even if all characters must be escaped */
+ new_length = (length * 2) + 1;
+
+ new_string = new_cp = tor_malloc(new_length);
+
+ while (*string) {
+ if (strchr(chars_to_escape, *string))
+ *new_cp++ = '\\';
+
+ *new_cp++ = *string++;
+ }
+
+ *new_cp = '\0'; /* NUL-terminate the new string */
+
+ return new_string;
+}
+
/* =====
* Time
* ===== */
@@ -3309,13 +3382,13 @@ tor_join_win_cmdline(const char *argv[])
}
/**
- * Helper function to output hex numbers, called by
- * format_helper_exit_status(). This writes the hexadecimal digits of x into
- * buf, up to max_len digits, and returns the actual number of digits written.
- * If there is insufficient space, it will write nothing and return 0.
+ * Helper function to output hex numbers from within a signal handler.
*
- * This function DOES NOT add a terminating NUL character to its output: be
- * careful!
+ * Writes the nul-terminated hexadecimal digits of <b>x</b> into a buffer
+ * <b>buf</b> of size <b>buf_len</b>, and return the actual number of digits
+ * written, not counting the terminal NUL.
+ *
+ * If there is insufficient space, write nothing and return 0.
*
* This accepts an unsigned int because format_helper_exit_status() needs to
* call it with a signed int and an unsigned char, and since the C standard
@@ -3330,15 +3403,14 @@ tor_join_win_cmdline(const char *argv[])
* arbitrary C functions.
*/
int
-format_hex_number_for_helper_exit_status(unsigned int x, char *buf,
- int max_len)
+format_hex_number_sigsafe(unsigned int x, char *buf, int buf_len)
{
int len;
unsigned int tmp;
char *cur;
/* Sanity check */
- if (!buf || max_len <= 0)
+ if (!buf || buf_len <= 1)
return 0;
/* How many chars do we need for x? */
@@ -3354,7 +3426,7 @@ format_hex_number_for_helper_exit_status(unsigned int x, char *buf,
}
/* Bail if we would go past the end of the buffer */
- if (len > max_len)
+ if (len+1 > buf_len)
return 0;
/* Point to last one */
@@ -3366,10 +3438,13 @@ format_hex_number_for_helper_exit_status(unsigned int x, char *buf,
x >>= 4;
} while (x != 0 && cur >= buf);
+ buf[len] = '\0';
+
/* Return len */
return len;
}
+#ifndef _WIN32
/** Format <b>child_state</b> and <b>saved_errno</b> as a hex string placed in
* <b>hex_errno</b>. Called between fork and _exit, so must be signal-handler
* safe.
@@ -3385,7 +3460,7 @@ format_hex_number_for_helper_exit_status(unsigned int x, char *buf,
* On success return the number of characters added to hex_errno, not counting
* the terminating NUL; return -1 on error.
*/
-int
+STATIC int
format_helper_exit_status(unsigned char child_state, int saved_errno,
char *hex_errno)
{
@@ -3416,8 +3491,8 @@ format_helper_exit_status(unsigned char child_state, int saved_errno,
cur = hex_errno;
/* Emit child_state */
- written = format_hex_number_for_helper_exit_status(child_state,
- cur, left);
+ written = format_hex_number_sigsafe(child_state, cur, left);
+
if (written <= 0)
goto err;
@@ -3446,8 +3521,7 @@ format_helper_exit_status(unsigned char child_state, int saved_errno,
}
/* Emit unsigned_errno */
- written = format_hex_number_for_helper_exit_status(unsigned_errno,
- cur, left);
+ written = format_hex_number_sigsafe(unsigned_errno, cur, left);
if (written <= 0)
goto err;
@@ -3478,6 +3552,7 @@ format_helper_exit_status(unsigned char child_state, int saved_errno,
done:
return res;
}
+#endif
/* Maximum number of file descriptors, if we cannot get it via sysconf() */
#define DEFAULT_MAX_FD 256
diff --git a/src/common/util.h b/src/common/util.h
index 96a02dd77..ad7526658 100644
--- a/src/common/util.h
+++ b/src/common/util.h
@@ -15,6 +15,7 @@
#include "torint.h"
#include "compat.h"
#include "di_ops.h"
+#include "testsupport.h"
#include <stdio.h>
#include <stdlib.h>
#ifdef _WIN32
@@ -222,23 +223,21 @@ 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 string_is_key_value(int severity, const char *string);
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);
+
+char *tor_escape_str_for_socks_arg(const char *string);
+
struct smartlist_t;
-int tor_vsscanf(const char *buf, const char *pattern, va_list ap)
-#ifdef __GNUC__
- __attribute__((format(scanf, 2, 0)))
-#endif
- ;
+int tor_vsscanf(const char *buf, const char *pattern, va_list ap) \
+ CHECK_SCANF(2, 0);
int tor_sscanf(const char *buf, const char *pattern, ...)
-#ifdef __GNUC__
- __attribute__((format(scanf, 2, 3)))
-#endif
- ;
+ CHECK_SCANF(2, 3);
void smartlist_add_asprintf(struct smartlist_t *sl, const char *pattern, ...)
CHECK_PRINTF(2, 3);
@@ -519,12 +518,13 @@ int32_t tor_weak_random_range(tor_weak_rng_t *rng, int32_t top);
* <b>n</b> */
#define tor_weak_random_one_in_n(rng, n) (0==tor_weak_random_range((rng),(n)))
+int format_hex_number_sigsafe(unsigned int x, char *buf, int max_len);
+
#ifdef UTIL_PRIVATE
/* Prototypes for private functions only used by util.c (and unit tests) */
-int format_hex_number_for_helper_exit_status(unsigned int x, char *buf,
- int max_len);
-int format_helper_exit_status(unsigned char child_state,
+#ifndef _WIN32
+STATIC int format_helper_exit_status(unsigned char child_state,
int saved_errno, char *hex_errno);
/* Space for hex values of child state, a slash, saved_errno (with
@@ -533,6 +533,8 @@ int format_helper_exit_status(unsigned char child_state,
1 + sizeof(int) * 2 + 1)
#endif
+#endif
+
const char *libor_get_digests(void);
#endif
diff --git a/src/config/deanonymind.py b/src/config/deanonymind.py
index c86dadca9..31d0658ee 100755
--- a/src/config/deanonymind.py
+++ b/src/config/deanonymind.py
@@ -156,23 +156,34 @@ def apply_manual_changes(assignments, manual_assignments):
entry['end_num'] == manual_entry['end_num']:
if len(manual_entry['country_code']) != 2:
print '-%s' % (line, ) # only remove, don't replace
- else:
+ del manual_dict[start_num]
+ elif entry['country_code'] != \
+ manual_entry['country_code']:
new_line = format_line_with_other_country(entry,
manual_entry)
print '-%s\n+%s' % (line, new_line, )
result.append(new_line)
- del manual_dict[start_num]
+ del manual_dict[start_num]
+ else:
+ print ('Warning: not applying ineffective manual '
+ 'change:\n %s\n %s' % (line, manual_line, ))
+ result.append(line)
else:
- print ('Warning: only partial match between '
- 'original/automatically replaced assignment and '
- 'manual assignment:\n %s\n %s\nNot applying '
- 'manual change.' % (line, manual_line, ))
+ print ('Warning: not applying manual change that is only '
+ 'a partial match:\n %s\n %s' %
+ (line, manual_line, ))
result.append(line)
+ elif 'country_code' in entry and \
+ entry['country_code'] == 'A1':
+ print ('Warning: no manual replacement for A1 entry:\n %s'
+ % (line, ))
+ result.append(line)
else:
result.append(line)
if len(manual_dict) > 0:
- print ('Warning: could not apply all manual assignments: %s' %
- ('\n '.join(manual_dict.values())), )
+ print 'Warning: could not apply all manual assignments:'
+ for line in manual_dict.values():
+ print ' %s' % (line, )
return result
def write_file(path, assignments, long_format=True):
diff --git a/src/config/geoip-manual b/src/config/geoip-manual
index 99c897ff4..ff9be5691 100644
--- a/src/config/geoip-manual
+++ b/src/config/geoip-manual
@@ -3,11 +3,10 @@
# directory to process this file when producing a new geoip file. See
# README.geoip in the same directory for details.
-# Remove MaxMind entry 0.116.0.0-0.119.255.255 which MaxMind says is AT,
-# but which is part of reserved range 0.0.0.0/8. -KL 2012-06-13
-# Disabled, because MaxMind apparently removed this range from their
-# database. -KL 2013-02-08
-#"0.116.0.0","0.119.255.255","7602176","7864319","",""
+# GB, because previous MaxMind entry 31.6.16.0-31.6.25.255 is GB, and RIR
+# delegation files say entire range 31.6.0.0-31.6.63.255 is GB.
+# -KL 2013-03-07
+"31.6.26.0","31.6.27.255","520493568","520494079","GB","United Kingdom"
# NL, because previous MaxMind entry 31.171.128.0-31.171.133.255 is NL,
# and RIR delegation files say 31.171.128.0-31.171.135.255 is NL.
@@ -20,6 +19,17 @@
# -KL 2012-11-27
"37.139.64.0","37.139.64.0","629882880","629882880","EU","Europe"
+# US, because next MaxMind entry 38.99.145.0-38.99.149.255 is US and
+# RIR delegation files say entire range 38.0.0.0-38.255.255.255 is US.
+# -KL 2013-05-13
+"38.99.144.0","38.99.144.255","644059136","644059391","US","United States"
+
+# GB, because RIR delegation files say exactly this range
+# 46.16.32.0-46.16.39.255 is GB, even though neither previous nor next
+# MaxMind range is GB. Both previous and next MaxMind ranges match RIR
+# delegation files, too. -KL 2013-03-07
+"46.16.32.0","46.16.39.255","772808704","772810751","GB","United Kingdom"
+
# CH, because previous MaxMind entry 46.19.141.0-46.19.142.255 is CH, and
# RIR delegation files say 46.19.136.0-46.19.143.255 is CH.
# -KL 2012-11-27
@@ -30,17 +40,15 @@
# -KL 2012-11-27
"46.166.128.0","46.166.128.255","782663680","782663935","GB","United Kingdom"
-# US, though could as well be CA. Previous MaxMind entry
-# 64.237.32.52-64.237.34.127 is US, next MaxMind entry
-# 64.237.34.144-64.237.34.151 is CA, and RIR delegation files say the
-# entire block 64.237.32.0-64.237.63.255 is US. -KL 2012-11-27
-"64.237.34.128","64.237.34.143","1089282688","1089282703","US","United States"
+# GB, because previous MaxMind entry 46.166.129.0-46.166.134.255 is GB,
+# and RIR delegation files say entire range 46.166.128.0-46.166.191.255 is
+# GB. -KL 2013-03-07
+"46.166.135.0","46.166.139.255","782665472","782666751","GB","United Kingdom"
-# US, though could as well be UY. Previous MaxMind entry
-# 67.15.170.0-67.15.182.255 is US, next MaxMind entry
-# 67.15.183.128-67.15.183.159 is UY, and RIR delegation files say the
-# entire block 67.15.0.0-67.15.255.255 is US. -KL 2012-11-27
-"67.15.183.0","67.15.183.127","1125103360","1125103487","US","United States"
+# Removing, because RIR delegation files don't even have an entry for this
+# single-address range, and there's no previous or next range in MaxMind.
+# -KL 2013-03-07
+"64.185.237.110","64.185.237.110","1085926766","1085926766","",""
# US, because next MaxMind entry 67.43.145.0-67.43.155.255 is US, and RIR
# delegation files say 67.43.144.0-67.43.159.255 is US.
@@ -61,6 +69,24 @@
# US. -KL 2012-11-27
"70.232.245.60","70.232.245.255","1189672252","1189672447","US","United States"
+# SE, because previous MaxMind entry 80.67.11.200-80.67.13.255 is SE, and
+# RIR delegation files say entire range 80.67.0.0-80.67.15.255 is SE.
+# -KL 2013-03-07
+"80.67.14.0","80.67.15.255","1346571776","1346572287","SE","Sweden"
+
+# NL, because previous MaxMind entry 81.171.56.0-81.171.80.255 is NL, and
+# RIR delegation files say entire range 81.171.64.0-81.171.127.255 is NL.
+# -KL 2013-03-07
+"81.171.81.0","81.171.81.127","1370181888","1370182015","NL","Netherlands"
+
+# GB, because RIPE NCC says 85.237.192.0-85.237.223.255 is GB.
+"85.237.222.0","85.237.222.255","1441652224","1441652479","GB","United Kingdom"
+
+# BE, because next MaxMind entry 86.39.147.0-86.39.148.31 is BE, and RIR
+# delegation files say entire range 86.39.128.0-86.39.255.255 is BE.
+# -KL 2013-04-08
+"86.39.146.0","86.39.146.255","1445433856","1445434111","BE","Belgium"
+
# GB, despite neither previous (GE) nor next (LV) MaxMind entry being GB,
# but because RIR delegation files agree with both previous and next
# MaxMind entry and say GB for 91.228.0.0-91.228.3.255. -KL 2012-11-27
@@ -77,9 +103,14 @@
# -KL 2012-11-27
"91.238.214.0","91.238.215.255","1542379008","1542379519","GB","United Kingdom"
-# US, because next MaxMind entry 173.0.16.0-173.0.65.255 is US, and RIR
-# delegation files say 173.0.0.0-173.0.15.255 is US. -KL 2012-11-27
-"173.0.0.0","173.0.15.255","2902458368","2902462463","US","United States"
+# NL, because next MaxMind entry 176.56.173.0-176.56.173.63 is NL, and RIR
+# delegation files say 176.56.160.0-176.56.191.255 is NL. -KL 2013-05-13
+"176.56.172.0","176.56.172.255","2956504064","2956504319","NL","Netherlands"
+
+# NL, despite neither previous (RU) nor next (GB) MaxMind entry being NL,
+# but because RIR delegation files say entire range
+# 176.56.160.0-176.56.191.255 is NL. -KL 2013-05-13
+"176.56.174.0","176.56.174.255","2956504576","2956504831","NL","Netherlands"
# US, because next MaxMind entry 176.67.84.0-176.67.84.79 is US, and RIR
# delegation files say 176.67.80.0-176.67.87.255 is US. -KL 2012-11-27
@@ -90,6 +121,12 @@
# -KL 2012-11-27
"176.67.86.0","176.67.87.255","2957202944","2957203455","US","United States"
+# GB, because RIR delegation files say exactly this range
+# 185.25.84.0-185.25.87.255 is GB, even though neither previous nor next
+# MaxMind range is GB. Both previous and next MaxMind ranges match RIR
+# delegation files, too. -KL 2013-05-13
+"185.25.84.0","185.25.87.255","3105444864","3105445887","GB","United Kingdom"
+
# EU, despite neither previous (RU) nor next (UA) MaxMind entry being EU,
# but because RIR delegation files agree with both previous and next
# MaxMind entry and say EU for 193.200.150.0-193.200.150.255.
@@ -101,11 +138,29 @@
# -KL 2012-11-27
"199.96.87.128","199.96.87.255","3344979840","3344979967","US","United States"
+# US, because next MaxMind entry 199.101.193.0-199.101.195.255 is US, and,
+# together with next entries, matches RIR delegation file entry
+# 199.101.192.0-199.101.199.255 which is US. -KL 2013-05-13
+"199.101.192.0","199.101.192.255","3345334272","3345334527","US","United States"
+
+# US, because ARIN says 199.255.208.0-199.255.215.255 is US.
+"199.255.213.0","199.255.215.255","3355432192","3355432959","US","United States"
+
+# US, because next MaxMind entry 204.12.162.0-204.12.197.119 is US, and
+# RIR delegation files say 204.12.160.0-204.12.191.255 is US.
+# -KL 2013-05-13
+"204.12.160.0","204.12.161.255","3423379456","3423379967","US","United States"
+
# US, because previous MaxMind entry 209.58.176.144-209.59.31.255 is US,
# and RIR delegation files say 209.59.32.0-209.59.63.255 is US.
# -KL 2012-11-27
"209.59.32.0","209.59.63.255","3510312960","3510321151","US","United States"
+# EU, despite neither previous (RU) nor next (SE) MaxMind entry being EU,
+# but because RIR delegation files agree with previous MaxMind entry and
+# say EU for 217.15.160.0-217.15.175.255. -KL 2013-05-13
+"217.15.160.0","217.15.164.255","3641679872","3641681151","EU","Europe"
+
# FR, because previous MaxMind entry 217.15.166.0-217.15.166.255 is FR,
# and RIR delegation files contain a block 217.15.160.0-217.15.175.255
# which, however, is EU, not FR. But merging with next MaxMind entry
diff --git a/src/or/addressmap.c b/src/or/addressmap.c
index 79e4b7c5e..9bc79bd84 100644
--- a/src/or/addressmap.c
+++ b/src/or/addressmap.c
@@ -798,7 +798,7 @@ address_is_in_virtual_range(const char *address)
/** Return a random address conforming to the virtual address configuration
* in <b>conf</b>.
*/
-/* private */ void
+STATIC void
get_random_virtual_addr(const virtual_addr_conf_t *conf, tor_addr_t *addr_out)
{
uint8_t tmp[4];
diff --git a/src/or/addressmap.h b/src/or/addressmap.h
index 40210ee99..417832b31 100644
--- a/src/or/addressmap.h
+++ b/src/or/addressmap.h
@@ -7,6 +7,8 @@
#ifndef TOR_ADDRESSMAP_H
#define TOR_ADDRESSMAP_H
+#include "testsupport.h"
+
void addressmap_init(void);
void addressmap_clear_excluded_trackexithosts(const or_options_t *options);
void addressmap_clear_invalid_automaps(const or_options_t *options);
@@ -52,8 +54,8 @@ typedef struct virtual_addr_conf_t {
maskbits_t bits;
} virtual_addr_conf_t;
-void get_random_virtual_addr(const virtual_addr_conf_t *conf,
- tor_addr_t *addr_out);
+STATIC void get_random_virtual_addr(const virtual_addr_conf_t *conf,
+ tor_addr_t *addr_out);
#endif
#endif
diff --git a/src/or/buffers.c b/src/or/buffers.c
index c4c847ec8..cc5890416 100644
--- a/src/or/buffers.c
+++ b/src/or/buffers.c
@@ -1294,7 +1294,7 @@ buf_matches_at_pos(const buf_pos_t *pos, const char *s, size_t n)
/** Return the first position in <b>buf</b> at which the <b>n</b>-character
* string <b>s</b> occurs, or -1 if it does not occur. */
-/*private*/ int
+STATIC int
buf_find_string_offset(const buf_t *buf, const char *s, size_t n)
{
buf_pos_t pos;
diff --git a/src/or/buffers.h b/src/or/buffers.h
index c947f0ba9..910494a87 100644
--- a/src/or/buffers.h
+++ b/src/or/buffers.h
@@ -12,6 +12,8 @@
#ifndef TOR_BUFFERS_H
#define TOR_BUFFERS_H
+#include "testsupport.h"
+
buf_t *buf_new(void);
buf_t *buf_new_with_capacity(size_t size);
void buf_free(buf_t *buf);
@@ -89,7 +91,7 @@ int generic_buffer_set_to_copy(generic_buffer_t **output,
void assert_buf_ok(buf_t *buf);
#ifdef BUFFERS_PRIVATE
-int buf_find_string_offset(const buf_t *buf, const char *s, size_t n);
+STATIC int buf_find_string_offset(const buf_t *buf, const char *s, size_t n);
#endif
#endif
diff --git a/src/or/channel.c b/src/or/channel.c
index 4e9086f2e..98c23d91e 100644
--- a/src/or/channel.c
+++ b/src/or/channel.c
@@ -122,6 +122,8 @@ static cell_queue_entry_t *
cell_queue_entry_new_fixed(cell_t *cell);
static cell_queue_entry_t *
cell_queue_entry_new_var(var_cell_t *var_cell);
+static int is_destroy_cell(channel_t *chan,
+ const cell_queue_entry_t *q, circid_t *circid_out);
/* Functions to maintain the digest map */
static void channel_add_to_digest_map(channel_t *chan);
@@ -801,6 +803,7 @@ channel_free(channel_t *chan)
/* Get rid of cmux */
if (chan->cmux) {
circuitmux_detach_all_circuits(chan->cmux);
+ circuitmux_mark_destroyed_circids_usable(chan->cmux, chan);
circuitmux_free(chan->cmux);
chan->cmux = NULL;
}
@@ -1685,6 +1688,13 @@ channel_write_cell_queue_entry(channel_t *chan, cell_queue_entry_t *q)
chan->timestamp_last_added_nonpadding = approx_time();
}
+ {
+ circid_t circ_id;
+ if (is_destroy_cell(chan, q, &circ_id)) {
+ channel_note_destroy_not_pending(chan, circ_id);
+ }
+ }
+
/* Can we send it right out? If so, try */
if (TOR_SIMPLEQ_EMPTY(&chan->outgoing_queue) &&
chan->state == CHANNEL_STATE_OPEN) {
@@ -2607,6 +2617,54 @@ channel_queue_var_cell(channel_t *chan, var_cell_t *var_cell)
}
}
+/** If <b>packed_cell</b> on <b>chan</b> is a destroy cell, then set
+ * *<b>circid_out</b> to its circuit ID, and return true. Otherwise, return
+ * false. */
+/* XXXX Move this function. */
+int
+packed_cell_is_destroy(channel_t *chan,
+ const packed_cell_t *packed_cell,
+ circid_t *circid_out)
+{
+ if (chan->wide_circ_ids) {
+ if (packed_cell->body[4] == CELL_DESTROY) {
+ *circid_out = ntohl(get_uint32(packed_cell->body));
+ return 1;
+ }
+ } else {
+ if (packed_cell->body[2] == CELL_DESTROY) {
+ *circid_out = ntohs(get_uint16(packed_cell->body));
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/** DOCDOC */
+static int
+is_destroy_cell(channel_t *chan,
+ const cell_queue_entry_t *q, circid_t *circid_out)
+{
+ *circid_out = 0;
+ switch (q->type) {
+ case CELL_QUEUE_FIXED:
+ if (q->u.fixed.cell->command == CELL_DESTROY) {
+ *circid_out = q->u.fixed.cell->circ_id;
+ return 1;
+ }
+ break;
+ case CELL_QUEUE_VAR:
+ if (q->u.var.var_cell->command == CELL_DESTROY) {
+ *circid_out = q->u.var.var_cell->circ_id;
+ return 1;
+ }
+ break;
+ case CELL_QUEUE_PACKED:
+ return packed_cell_is_destroy(chan, q->u.packed.packed_cell, circid_out);
+ }
+ return 0;
+}
+
/**
* Send destroy cell on a channel
*
@@ -2618,25 +2676,20 @@ channel_queue_var_cell(channel_t *chan, var_cell_t *var_cell)
int
channel_send_destroy(circid_t circ_id, channel_t *chan, int reason)
{
- cell_t cell;
-
tor_assert(chan);
/* Check to make sure we can send on this channel first */
if (!(chan->state == CHANNEL_STATE_CLOSING ||
chan->state == CHANNEL_STATE_CLOSED ||
- chan->state == CHANNEL_STATE_ERROR)) {
- memset(&cell, 0, sizeof(cell_t));
- cell.circ_id = circ_id;
- cell.command = CELL_DESTROY;
- cell.payload[0] = (uint8_t) reason;
+ chan->state == CHANNEL_STATE_ERROR) &&
+ chan->cmux) {
+ channel_note_destroy_pending(chan, circ_id);
+ circuitmux_append_destroy_cell(chan, chan->cmux, circ_id, reason);
log_debug(LD_OR,
"Sending destroy (circID %u) on channel %p "
"(global ID " U64_FORMAT ")",
(unsigned)circ_id, chan,
U64_PRINTF_ARG(chan->global_identifier));
-
- channel_write_cell(chan, &cell);
} else {
log_warn(LD_BUG,
"Someone called channel_send_destroy() for circID %u "
diff --git a/src/or/channel.h b/src/or/channel.h
index 0933ec8d3..83d7e900f 100644
--- a/src/or/channel.h
+++ b/src/or/channel.h
@@ -477,5 +477,9 @@ uint64_t channel_count_xmitted(channel_t *chan);
uint64_t channel_listener_count_accepted(channel_listener_t *chan_l);
+int packed_cell_is_destroy(channel_t *chan,
+ const packed_cell_t *packed_cell,
+ circid_t *circid_out);
+
#endif
diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c
index daeaa37b1..5e51301ce 100644
--- a/src/or/circuitlist.c
+++ b/src/or/circuitlist.c
@@ -8,7 +8,7 @@
* \file circuitlist.c
* \brief Manage the global circuit list.
**/
-
+#define CIRCUITLIST_PRIVATE
#include "or.h"
#include "channel.h"
#include "circuitbuild.h"
@@ -41,7 +41,6 @@ circuit_t *global_circuitlist=NULL;
/** A list of all the circuits in CIRCUIT_STATE_CHAN_WAIT. */
static smartlist_t *circuits_pending_chans = NULL;
-static void circuit_free(circuit_t *circ);
static void circuit_free_cpath(crypt_path_t *cpath);
static void circuit_free_cpath_node(crypt_path_t *victim);
static void cpath_ref_decref(crypt_path_reference_t *cpath_ref);
@@ -207,18 +206,123 @@ circuit_set_circid_chan_helper(circuit_t *circ, int direction,
}
}
+/** Mark that circuit id <b>id</b> shouldn't be used on channel <b>chan</b>,
+ * even if there is no circuit on the channel. We use this to keep the
+ * circuit id from getting re-used while we have queued but not yet sent
+ * a destroy cell. */
+void
+channel_mark_circid_unusable(channel_t *chan, circid_t id)
+{
+ chan_circid_circuit_map_t search;
+ chan_circid_circuit_map_t *ent;
+
+ /* See if there's an entry there. That wouldn't be good. */
+ memset(&search, 0, sizeof(search));
+ search.chan = chan;
+ search.circ_id = id;
+ ent = HT_FIND(chan_circid_map, &chan_circid_map, &search);
+
+ if (ent && ent->circuit) {
+ /* we have a problem. */
+ log_warn(LD_BUG, "Tried to mark %u unusable on %p, but there was already "
+ "a circuit there.", (unsigned)id, chan);
+ } else if (ent) {
+ /* It's already marked. */
+ } else {
+ ent = tor_malloc_zero(sizeof(chan_circid_circuit_map_t));
+ ent->chan = chan;
+ ent->circ_id = id;
+ /* leave circuit at NULL */
+ HT_INSERT(chan_circid_map, &chan_circid_map, ent);
+ }
+}
+
+/** Mark that a circuit id <b>id</b> can be used again on <b>chan</b>.
+ * We use this to re-enable the circuit ID after we've sent a destroy cell.
+ */
+void
+channel_mark_circid_usable(channel_t *chan, circid_t id)
+{
+ chan_circid_circuit_map_t search;
+ chan_circid_circuit_map_t *ent;
+
+ /* See if there's an entry there. That wouldn't be good. */
+ memset(&search, 0, sizeof(search));
+ search.chan = chan;
+ search.circ_id = id;
+ ent = HT_REMOVE(chan_circid_map, &chan_circid_map, &search);
+ if (ent && ent->circuit) {
+ log_warn(LD_BUG, "Tried to mark %u usable on %p, but there was already "
+ "a circuit there.", (unsigned)id, chan);
+ return;
+ }
+ if (_last_circid_chan_ent == ent)
+ _last_circid_chan_ent = NULL;
+ tor_free(ent);
+}
+
+/** Called to indicate that a DESTROY is pending on <b>chan</b> with
+ * circuit ID <b>id</b>, but hasn't been sent yet. */
+void
+channel_note_destroy_pending(channel_t *chan, circid_t id)
+{
+ circuit_t *circ = circuit_get_by_circid_channel_even_if_marked(id,chan);
+ if (circ) {
+ if (circ->n_chan == chan && circ->n_circ_id == id) {
+ circ->n_delete_pending = 1;
+ } else {
+ or_circuit_t *orcirc = TO_OR_CIRCUIT(circ);
+ if (orcirc->p_chan == chan && orcirc->p_circ_id == id) {
+ circ->p_delete_pending = 1;
+ }
+ }
+ return;
+ }
+ channel_mark_circid_unusable(chan, id);
+}
+
+/** Called to indicate that a DESTROY is no longer pending on <b>chan</b> with
+ * circuit ID <b>id</b> -- typically, because it has been sent. */
+void
+channel_note_destroy_not_pending(channel_t *chan, circid_t id)
+{
+ circuit_t *circ = circuit_get_by_circid_channel_even_if_marked(id,chan);
+ if (circ) {
+ if (circ->n_chan == chan && circ->n_circ_id == id) {
+ circ->n_delete_pending = 0;
+ } else {
+ or_circuit_t *orcirc = TO_OR_CIRCUIT(circ);
+ if (orcirc->p_chan == chan && orcirc->p_circ_id == id) {
+ circ->p_delete_pending = 0;
+ }
+ }
+ /* XXXX this shouldn't happen; log a bug here. */
+ return;
+ }
+ channel_mark_circid_usable(chan, id);
+}
+
/** Set the p_conn field of a circuit <b>circ</b>, along
* with the corresponding circuit ID, and add the circuit as appropriate
* to the (chan,id)-\>circuit map. */
void
-circuit_set_p_circid_chan(or_circuit_t *circ, circid_t id,
+circuit_set_p_circid_chan(or_circuit_t *or_circ, circid_t id,
channel_t *chan)
{
- circuit_set_circid_chan_helper(TO_CIRCUIT(circ), CELL_DIRECTION_IN,
- id, chan);
+ circuit_t *circ = TO_CIRCUIT(or_circ);
+ channel_t *old_chan = or_circ->p_chan;
+ circid_t old_id = or_circ->p_circ_id;
+
+ circuit_set_circid_chan_helper(circ, CELL_DIRECTION_IN, id, chan);
if (chan)
- tor_assert(bool_eq(circ->p_chan_cells.n, circ->next_active_on_p_chan));
+ tor_assert(bool_eq(or_circ->p_chan_cells.n,
+ or_circ->next_active_on_p_chan));
+
+ if (circ->p_delete_pending && old_chan) {
+ channel_mark_circid_unusable(old_chan, old_id);
+ circ->p_delete_pending = 0;
+ }
}
/** Set the n_conn field of a circuit <b>circ</b>, along
@@ -228,10 +332,18 @@ void
circuit_set_n_circid_chan(circuit_t *circ, circid_t id,
channel_t *chan)
{
+ channel_t *old_chan = circ->n_chan;
+ circid_t old_id = circ->n_circ_id;
+
circuit_set_circid_chan_helper(circ, CELL_DIRECTION_OUT, id, chan);
if (chan)
tor_assert(bool_eq(circ->n_chan_cells.n, circ->next_active_on_n_chan));
+
+ if (circ->n_delete_pending && old_chan) {
+ channel_mark_circid_unusable(old_chan, old_id);
+ circ->n_delete_pending = 0;
+ }
}
/** Change the state of <b>circ</b> to <b>state</b>, adding it to or removing
@@ -623,7 +735,7 @@ or_circuit_new(circid_t p_circ_id, channel_t *p_chan)
/** Deallocate space associated with circ.
*/
-static void
+STATIC void
circuit_free(circuit_t *circ)
{
void *mem;
@@ -928,9 +1040,13 @@ circuit_get_by_global_id(uint32_t id)
* - circ-\>n_circ_id or circ-\>p_circ_id is equal to <b>circ_id</b>, and
* - circ is attached to <b>chan</b>, either as p_chan or n_chan.
* Return NULL if no such circuit exists.
+ *
+ * If <b>found_entry_out</b> is provided, set it to true if we have a
+ * placeholder entry for circid/chan, and leave it unset otherwise.
*/
static INLINE circuit_t *
-circuit_get_by_circid_channel_impl(circid_t circ_id, channel_t *chan)
+circuit_get_by_circid_channel_impl(circid_t circ_id, channel_t *chan,
+ int *found_entry_out)
{
chan_circid_circuit_map_t search;
chan_circid_circuit_map_t *found;
@@ -951,15 +1067,21 @@ circuit_get_by_circid_channel_impl(circid_t circ_id, channel_t *chan)
" circ_id %u, channel ID " U64_FORMAT " (%p)",
found->circuit, (unsigned)circ_id,
U64_PRINTF_ARG(chan->global_identifier), chan);
+ if (found_entry_out)
+ *found_entry_out = 1;
return found->circuit;
}
log_debug(LD_CIRC,
- "circuit_get_by_circid_channel_impl() found nothing for"
+ "circuit_get_by_circid_channel_impl() found %s for"
" circ_id %u, channel ID " U64_FORMAT " (%p)",
+ found ? "placeholder" : "nothing",
(unsigned)circ_id,
U64_PRINTF_ARG(chan->global_identifier), chan);
+ if (found_entry_out)
+ *found_entry_out = found ? 1 : 0;
+
return NULL;
/* The rest of this checks for bugs. Disabled by default. */
/* We comment it out because coverity complains otherwise.
@@ -993,7 +1115,7 @@ circuit_get_by_circid_channel_impl(circid_t circ_id, channel_t *chan)
circuit_t *
circuit_get_by_circid_channel(circid_t circ_id, channel_t *chan)
{
- circuit_t *circ = circuit_get_by_circid_channel_impl(circ_id, chan);
+ circuit_t *circ = circuit_get_by_circid_channel_impl(circ_id, chan, NULL);
if (!circ || circ->marked_for_close)
return NULL;
else
@@ -1009,7 +1131,7 @@ circuit_t *
circuit_get_by_circid_channel_even_if_marked(circid_t circ_id,
channel_t *chan)
{
- return circuit_get_by_circid_channel_impl(circ_id, chan);
+ return circuit_get_by_circid_channel_impl(circ_id, chan, NULL);
}
/** Return true iff the circuit ID <b>circ_id</b> is currently used by a
@@ -1017,7 +1139,9 @@ circuit_get_by_circid_channel_even_if_marked(circid_t circ_id,
int
circuit_id_in_use_on_channel(circid_t circ_id, channel_t *chan)
{
- return circuit_get_by_circid_channel_impl(circ_id, chan) != NULL;
+ int found = 0;
+ return circuit_get_by_circid_channel_impl(circ_id, chan, &found) != NULL
+ || found;
}
/** Return the circuit that a given edge connection is using. */
@@ -1689,15 +1813,16 @@ assert_circuit_ok(const circuit_t *c)
/* We use the _impl variant here to make sure we don't fail on marked
* circuits, which would not be returned by the regular function. */
circuit_t *c2 = circuit_get_by_circid_channel_impl(c->n_circ_id,
- c->n_chan);
+ c->n_chan, NULL);
tor_assert(c == c2);
}
}
if (or_circ && or_circ->p_chan) {
if (or_circ->p_circ_id) {
/* ibid */
- circuit_t *c2 = circuit_get_by_circid_channel_impl(or_circ->p_circ_id,
- or_circ->p_chan);
+ circuit_t *c2 =
+ circuit_get_by_circid_channel_impl(or_circ->p_circ_id,
+ or_circ->p_chan, NULL);
tor_assert(c == c2);
}
}
diff --git a/src/or/circuitlist.h b/src/or/circuitlist.h
index 874f68cd2..a5a54859b 100644
--- a/src/or/circuitlist.h
+++ b/src/or/circuitlist.h
@@ -12,6 +12,8 @@
#ifndef TOR_CIRCUITLIST_H
#define TOR_CIRCUITLIST_H
+#include "testsupport.h"
+
circuit_t * circuit_get_global_list_(void);
const char *circuit_state_to_string(int state);
const char *circuit_purpose_to_controller_string(uint8_t purpose);
@@ -23,6 +25,8 @@ void circuit_set_p_circid_chan(or_circuit_t *circ, circid_t id,
channel_t *chan);
void circuit_set_n_circid_chan(circuit_t *circ, circid_t id,
channel_t *chan);
+void channel_mark_circid_unusable(channel_t *chan, circid_t id);
+void channel_mark_circid_usable(channel_t *chan, circid_t id);
void circuit_set_state(circuit_t *circ, uint8_t state);
void circuit_close_all_marked(void);
int32_t circuit_initial_package_window(void);
@@ -63,5 +67,12 @@ void assert_circuit_ok(const circuit_t *c);
void circuit_free_all(void);
void circuits_handle_oom(size_t current_allocation);
+void channel_note_destroy_pending(channel_t *chan, circid_t id);
+void channel_note_destroy_not_pending(channel_t *chan, circid_t id);
+
+#ifdef CIRCUITLIST_PRIVATE
+STATIC void circuit_free(circuit_t *circ);
+#endif
+
#endif
diff --git a/src/or/circuitmux.c b/src/or/circuitmux.c
index 545cfd065..081416368 100644
--- a/src/or/circuitmux.c
+++ b/src/or/circuitmux.c
@@ -10,6 +10,7 @@
#include "channel.h"
#include "circuitlist.h"
#include "circuitmux.h"
+#include "relay.h"
/*
* Private typedefs for circuitmux.c
@@ -115,6 +116,22 @@ struct circuitmux_s {
*/
struct circuit_t *active_circuits_head, *active_circuits_tail;
+ /** List of queued destroy cells */
+ cell_queue_t destroy_cell_queue;
+ /** Boolean: True iff the last cell to circuitmux_get_first_active_circuit
+ * returned the destroy queue. Used to force alternation between
+ * destroy/non-destroy cells.
+ *
+ * XXXX There is no reason to think that alternating is a particularly good
+ * approach -- it's just designed to prevent destroys from starving other
+ * cells completely.
+ */
+ unsigned int last_cell_was_destroy : 1;
+ /** Destroy counter: increment this when a destroy gets queued, decrement
+ * when we unqueue it, so we can test to make sure they don't starve.
+ */
+ int64_t destroy_ctr;
+
/*
* Circuitmux policy; if this is non-NULL, it can override the built-
* in round-robin active circuits behavior. This is how EWMA works in
@@ -193,6 +210,11 @@ static void circuitmux_assert_okay_pass_one(circuitmux_t *cmux);
static void circuitmux_assert_okay_pass_two(circuitmux_t *cmux);
static void circuitmux_assert_okay_pass_three(circuitmux_t *cmux);
+/* Static global variables */
+
+/** Count the destroy balance to debug destroy queue logic */
+static int64_t global_destroy_ctr = 0;
+
/* Function definitions */
/**
@@ -476,6 +498,31 @@ circuitmux_detach_all_circuits(circuitmux_t *cmux)
cmux->n_cells = 0;
}
+/** Reclaim all circuit IDs currently marked as unusable on <b>chan</b> because
+ * of pending destroy cells in <b>cmux</b>.
+ *
+ * This function must be called AFTER circuits are unlinked from the (channel,
+ * circuid-id) map with circuit_unlink_all_from_channel(), but before calling
+ * circuitmux_free().
+ */
+void
+circuitmux_mark_destroyed_circids_usable(circuitmux_t *cmux, channel_t *chan)
+{
+ packed_cell_t *cell;
+ int n_bad = 0;
+ for (cell = cmux->destroy_cell_queue.head; cell; cell = cell->next) {
+ circid_t circid = 0;
+ if (packed_cell_is_destroy(chan, cell, &circid)) {
+ channel_mark_circid_usable(chan, circid);
+ } else {
+ ++n_bad;
+ }
+ }
+ if (n_bad)
+ log_warn(LD_BUG, "%d cell(s) on destroy queue did not look like a "
+ "DESTROY cell.", n_bad);
+}
+
/**
* Free a circuitmux_t; the circuits must be detached first with
* circuitmux_detach_all_circuits().
@@ -508,6 +555,30 @@ circuitmux_free(circuitmux_t *cmux)
tor_free(cmux->chanid_circid_map);
}
+ /*
+ * We're throwing away some destroys; log the counter and
+ * adjust the global counter by the queue size.
+ */
+ if (cmux->destroy_cell_queue.n > 0) {
+ cmux->destroy_ctr -= cmux->destroy_cell_queue.n;
+ global_destroy_ctr -= cmux->destroy_cell_queue.n;
+ log_debug(LD_CIRC,
+ "Freeing cmux at %p with %u queued destroys; the last cmux "
+ "destroy balance was "I64_FORMAT", global is "I64_FORMAT,
+ cmux, cmux->destroy_cell_queue.n,
+ I64_PRINTF_ARG(cmux->destroy_ctr),
+ I64_PRINTF_ARG(global_destroy_ctr));
+ } else {
+ log_debug(LD_CIRC,
+ "Freeing cmux at %p with no queued destroys, the cmux destroy "
+ "balance was "I64_FORMAT", global is "I64_FORMAT,
+ cmux,
+ I64_PRINTF_ARG(cmux->destroy_ctr),
+ I64_PRINTF_ARG(global_destroy_ctr));
+ }
+
+ cell_queue_clear(&cmux->destroy_cell_queue);
+
tor_free(cmux);
}
@@ -816,7 +887,7 @@ circuitmux_num_cells(circuitmux_t *cmux)
{
tor_assert(cmux);
- return cmux->n_cells;
+ return cmux->n_cells + cmux->destroy_cell_queue.n;
}
/**
@@ -851,9 +922,9 @@ circuitmux_num_circuits(circuitmux_t *cmux)
* Attach a circuit to a circuitmux, for the specified direction.
*/
-void
-circuitmux_attach_circuit(circuitmux_t *cmux, circuit_t *circ,
- cell_direction_t direction)
+MOCK_IMPL(void,
+circuitmux_attach_circuit,(circuitmux_t *cmux, circuit_t *circ,
+ cell_direction_t direction))
{
channel_t *chan = NULL;
uint64_t channel_id;
@@ -1000,8 +1071,8 @@ circuitmux_attach_circuit(circuitmux_t *cmux, circuit_t *circ,
* no-op if not attached.
*/
-void
-circuitmux_detach_circuit(circuitmux_t *cmux, circuit_t *circ)
+MOCK_IMPL(void,
+circuitmux_detach_circuit,(circuitmux_t *cmux, circuit_t *circ))
{
chanid_circid_muxinfo_t search, *hashent = NULL;
/*
@@ -1368,16 +1439,36 @@ circuitmux_set_num_cells(circuitmux_t *cmux, circuit_t *circ,
/**
* Pick a circuit to send from, using the active circuits list or a
* circuitmux policy if one is available. This is called from channel.c.
+ *
+ * If we would rather send a destroy cell, return NULL and set
+ * *<b>destroy_queue_out</b> to the destroy queue.
+ *
+ * If we have nothing to send, set *<b>destroy_queue_out</b> to NULL and
+ * return NULL.
*/
circuit_t *
-circuitmux_get_first_active_circuit(circuitmux_t *cmux)
+circuitmux_get_first_active_circuit(circuitmux_t *cmux,
+ cell_queue_t **destroy_queue_out)
{
circuit_t *circ = NULL;
tor_assert(cmux);
+ tor_assert(destroy_queue_out);
+
+ *destroy_queue_out = NULL;
+
+ if (cmux->destroy_cell_queue.n &&
+ (!cmux->last_cell_was_destroy || cmux->n_active_circuits == 0)) {
+ /* We have destroy cells to send, and either we just sent a relay cell,
+ * or we have no relay cells to send. */
+
+ /* XXXX We should let the cmux policy have some say in this eventually. */
+ /* XXXX Alternating is not a terribly brilliant approach here. */
+ *destroy_queue_out = &cmux->destroy_cell_queue;
- if (cmux->n_active_circuits > 0) {
+ cmux->last_cell_was_destroy = 1;
+ } else if (cmux->n_active_circuits > 0) {
/* We also must have a cell available for this to be the case */
tor_assert(cmux->n_cells > 0);
/* Do we have a policy-provided circuit selector? */
@@ -1389,7 +1480,11 @@ circuitmux_get_first_active_circuit(circuitmux_t *cmux)
tor_assert(cmux->active_circuits_head);
circ = cmux->active_circuits_head;
}
- } else tor_assert(cmux->n_cells == 0);
+ cmux->last_cell_was_destroy = 0;
+ } else {
+ tor_assert(cmux->n_cells == 0);
+ tor_assert(cmux->destroy_cell_queue.n == 0);
+ }
return circ;
}
@@ -1463,6 +1558,26 @@ circuitmux_notify_xmit_cells(circuitmux_t *cmux, circuit_t *circ,
circuitmux_assert_okay_paranoid(cmux);
}
+/**
+ * Notify the circuitmux that a destroy was sent, so we can update
+ * the counter.
+ */
+
+void
+circuitmux_notify_xmit_destroy(circuitmux_t *cmux)
+{
+ tor_assert(cmux);
+
+ --(cmux->destroy_ctr);
+ --(global_destroy_ctr);
+ log_debug(LD_CIRC,
+ "Cmux at %p sent a destroy, cmux counter is now "I64_FORMAT", "
+ "global counter is now "I64_FORMAT,
+ cmux,
+ I64_PRINTF_ARG(cmux->destroy_ctr),
+ I64_PRINTF_ARG(global_destroy_ctr));
+}
+
/*
* Circuitmux consistency checking assertions
*/
@@ -1743,3 +1858,40 @@ circuitmux_assert_okay_pass_three(circuitmux_t *cmux)
}
}
+/*DOCDOC */
+void
+circuitmux_append_destroy_cell(channel_t *chan,
+ circuitmux_t *cmux,
+ circid_t circ_id,
+ uint8_t reason)
+{
+ cell_t cell;
+ memset(&cell, 0, sizeof(cell_t));
+ cell.circ_id = circ_id;
+ cell.command = CELL_DESTROY;
+ cell.payload[0] = (uint8_t) reason;
+
+ cell_queue_append_packed_copy(&cmux->destroy_cell_queue, &cell,
+ chan->wide_circ_ids, 0);
+
+ /* Destroy entering the queue, update counters */
+ ++(cmux->destroy_ctr);
+ ++global_destroy_ctr;
+ log_debug(LD_CIRC,
+ "Cmux at %p queued a destroy for circ %u, cmux counter is now "
+ I64_FORMAT", global counter is now "I64_FORMAT,
+ cmux, circ_id,
+ I64_PRINTF_ARG(cmux->destroy_ctr),
+ I64_PRINTF_ARG(global_destroy_ctr));
+
+ /* XXXX Duplicate code from append_cell_to_circuit_queue */
+ if (!channel_has_queued_writes(chan)) {
+ /* There is no data at all waiting to be sent on the outbuf. Add a
+ * cell, so that we can notice when it gets flushed, flushed_some can
+ * get called, and we can start putting more data onto the buffer then.
+ */
+ log_debug(LD_GENERAL, "Primed a buffer.");
+ channel_flush_from_first_active_circuit(chan, 1);
+ }
+}
+
diff --git a/src/or/circuitmux.h b/src/or/circuitmux.h
index 25644ffab..ee2f5d153 100644
--- a/src/or/circuitmux.h
+++ b/src/or/circuitmux.h
@@ -10,6 +10,7 @@
#define TOR_CIRCUITMUX_H
#include "or.h"
+#include "testsupport.h"
typedef struct circuitmux_policy_s circuitmux_policy_t;
typedef struct circuitmux_policy_data_s circuitmux_policy_data_t;
@@ -120,17 +121,27 @@ unsigned int circuitmux_num_circuits(circuitmux_t *cmux);
unsigned int circuitmux_num_active_circuits(circuitmux_t *cmux);
/* Channel interface */
-circuit_t * circuitmux_get_first_active_circuit(circuitmux_t *cmux);
+circuit_t * circuitmux_get_first_active_circuit(circuitmux_t *cmux,
+ cell_queue_t **destroy_queue_out);
void circuitmux_notify_xmit_cells(circuitmux_t *cmux, circuit_t *circ,
unsigned int n_cells);
+void circuitmux_notify_xmit_destroy(circuitmux_t *cmux);
/* Circuit interface */
-void circuitmux_attach_circuit(circuitmux_t *cmux, circuit_t *circ,
- cell_direction_t direction);
-void circuitmux_detach_circuit(circuitmux_t *cmux, circuit_t *circ);
+MOCK_DECL(void, circuitmux_attach_circuit, (circuitmux_t *cmux,
+ circuit_t *circ,
+ cell_direction_t direction));
+MOCK_DECL(void, circuitmux_detach_circuit,
+ (circuitmux_t *cmux, circuit_t *circ));
void circuitmux_clear_num_cells(circuitmux_t *cmux, circuit_t *circ);
void circuitmux_set_num_cells(circuitmux_t *cmux, circuit_t *circ,
unsigned int n_cells);
+void circuitmux_append_destroy_cell(channel_t *chan,
+ circuitmux_t *cmux, circid_t circ_id,
+ uint8_t reason);
+void circuitmux_mark_destroyed_circids_usable(circuitmux_t *cmux,
+ channel_t *chan);
+
#endif /* TOR_CIRCUITMUX_H */
diff --git a/src/or/circuitstats.c b/src/or/circuitstats.c
index 1d7812bf2..95129f9a4 100644
--- a/src/or/circuitstats.c
+++ b/src/or/circuitstats.c
@@ -29,9 +29,13 @@
/* XXXX024 Make this static; add accessor functions. */
circuit_build_times_t circ_times;
+#ifdef TOR_UNIT_TESTS
/** If set, we're running the unit tests: we should avoid clobbering
* our state file or accessing get_options() or get_or_state() */
static int unit_tests = 0;
+#else
+#define unit_tests 0
+#endif
/**
* This function decides if CBT learning should be disabled. It returns
@@ -438,7 +442,7 @@ circuit_build_times_get_initial_timeout(void)
* Leave estimated parameters, timeout and network liveness intact
* for future use.
*/
-void
+STATIC void
circuit_build_times_reset(circuit_build_times_t *cbt)
{
memset(cbt->circuit_build_times, 0, sizeof(cbt->circuit_build_times));
@@ -949,7 +953,7 @@ circuit_build_times_parse_state(circuit_build_times_t *cbt,
* an acceptable approximation because we are only concerned with the
* accuracy of the CDF of the tail.
*/
-int
+STATIC int
circuit_build_times_update_alpha(circuit_build_times_t *cbt)
{
build_time_t *x=cbt->circuit_build_times;
@@ -1033,7 +1037,7 @@ circuit_build_times_update_alpha(circuit_build_times_t *cbt)
*
* Return value is in milliseconds.
*/
-double
+STATIC double
circuit_build_times_calculate_timeout(circuit_build_times_t *cbt,
double quantile)
{
@@ -1050,6 +1054,7 @@ circuit_build_times_calculate_timeout(circuit_build_times_t *cbt,
return ret;
}
+#ifdef TOR_UNIT_TESTS
/** Pareto CDF */
double
circuit_build_times_cdf(circuit_build_times_t *cbt, double x)
@@ -1060,7 +1065,9 @@ circuit_build_times_cdf(circuit_build_times_t *cbt, double x)
tor_assert(0 <= ret && ret <= 1.0);
return ret;
}
+#endif
+#ifdef TOR_UNIT_TESTS
/**
* Generate a synthetic time using our distribution parameters.
*
@@ -1093,7 +1100,9 @@ circuit_build_times_generate_sample(circuit_build_times_t *cbt,
tor_assert(ret > 0);
return ret;
}
+#endif
+#ifdef TOR_UNIT_TESTS
/**
* Estimate an initial alpha parameter by solving the quantile
* function with a quantile point and a specific timeout value.
@@ -1114,6 +1123,7 @@ circuit_build_times_initial_alpha(circuit_build_times_t *cbt,
(tor_mathlog(cbt->Xm)-tor_mathlog(timeout_ms));
tor_assert(cbt->alpha > 0);
}
+#endif
/**
* Returns true if we need circuits to be built
@@ -1282,7 +1292,7 @@ circuit_build_times_network_check_live(circuit_build_times_t *cbt)
* to restart the process of building test circuits and estimating a
* new timeout.
*/
-int
+STATIC int
circuit_build_times_network_check_changed(circuit_build_times_t *cbt)
{
int total_build_times = cbt->total_build_times;
@@ -1546,6 +1556,8 @@ circuit_build_times_set_timeout(circuit_build_times_t *cbt)
cbt->total_build_times);
}
}
+
+#ifdef TOR_UNIT_TESTS
/** Make a note that we're running unit tests (rather than running Tor
* itself), so we avoid clobbering our state file. */
void
@@ -1553,4 +1565,5 @@ circuitbuild_running_unit_tests(void)
{
unit_tests = 1;
}
+#endif
diff --git a/src/or/circuitstats.h b/src/or/circuitstats.h
index 87dce99f4..53ba2b2d2 100644
--- a/src/or/circuitstats.h
+++ b/src/or/circuitstats.h
@@ -38,19 +38,23 @@ double circuit_build_times_timeout_rate(const circuit_build_times_t *cbt);
double circuit_build_times_close_rate(const circuit_build_times_t *cbt);
#ifdef CIRCUITSTATS_PRIVATE
-double circuit_build_times_calculate_timeout(circuit_build_times_t *cbt,
+STATIC double circuit_build_times_calculate_timeout(circuit_build_times_t *cbt,
double quantile);
+STATIC int circuit_build_times_update_alpha(circuit_build_times_t *cbt);
+STATIC void circuit_build_times_reset(circuit_build_times_t *cbt);
+
+/* Network liveness functions */
+STATIC int circuit_build_times_network_check_changed(
+ circuit_build_times_t *cbt);
+#endif
+
+#ifdef TOR_UNIT_TESTS
build_time_t circuit_build_times_generate_sample(circuit_build_times_t *cbt,
double q_lo, double q_hi);
+double circuit_build_times_cdf(circuit_build_times_t *cbt, double x);
void circuit_build_times_initial_alpha(circuit_build_times_t *cbt,
double quantile, double time_ms);
-int circuit_build_times_update_alpha(circuit_build_times_t *cbt);
-double circuit_build_times_cdf(circuit_build_times_t *cbt, double x);
void circuitbuild_running_unit_tests(void);
-void circuit_build_times_reset(circuit_build_times_t *cbt);
-
-/* Network liveness functions */
-int circuit_build_times_network_check_changed(circuit_build_times_t *cbt);
#endif
/* Network liveness functions */
@@ -58,8 +62,5 @@ void circuit_build_times_network_is_live(circuit_build_times_t *cbt);
int circuit_build_times_network_check_live(circuit_build_times_t *cbt);
void circuit_build_times_network_circ_success(circuit_build_times_t *cbt);
-/* DOCDOC circuit_build_times_get_bw_scale */
-int circuit_build_times_get_bw_scale(networkstatus_t *ns);
-
#endif
diff --git a/src/or/config.c b/src/or/config.c
index 725190a96..6d3b13338 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -9,8 +9,6 @@
* \brief Code to parse and interpret configuration files.
**/
-#define CONFIG_PRIVATE
-
#include "or.h"
#include "addressmap.h"
#include "channel.h"
@@ -40,6 +38,7 @@
#include "rendservice.h"
#include "rephist.h"
#include "router.h"
+#include "sandbox.h"
#include "util.h"
#include "routerlist.h"
#include "routerset.h"
@@ -370,6 +369,7 @@ static config_var_t option_vars_[] = {
V(RunAsDaemon, BOOL, "0"),
// V(RunTesting, BOOL, "0"),
OBSOLETE("RunTesting"), // currently unused
+ V(Sandbox, BOOL, "0"),
V(SafeLogging, STRING, "1"),
V(SafeSocks, BOOL, "0"),
V(ServerDNSAllowBrokenConfig, BOOL, "1"),
@@ -405,7 +405,7 @@ static config_var_t option_vars_[] = {
V(UseEntryGuards, BOOL, "1"),
V(UseEntryGuardsAsDirGuards, BOOL, "1"),
V(UseMicrodescriptors, AUTOBOOL, "auto"),
- V(UseNTorHandshake, AUTOBOOL, "auto"),
+ V(UseNTorHandshake, AUTOBOOL, "1"),
V(User, STRING, NULL),
V(UserspaceIOCPBuffers, BOOL, "0"),
VAR("V1AuthoritativeDirectory",BOOL, V1AuthoritativeDir, "0"),
@@ -414,6 +414,7 @@ static config_var_t option_vars_[] = {
V(TestingV3AuthInitialVotingInterval, INTERVAL, "30 minutes"),
V(TestingV3AuthInitialVoteDelay, INTERVAL, "5 minutes"),
V(TestingV3AuthInitialDistDelay, INTERVAL, "5 minutes"),
+ V(TestingV3AuthVotingStartOffset, INTERVAL, "0"),
V(V3AuthVotingInterval, INTERVAL, "1 hour"),
V(V3AuthVoteDelay, INTERVAL, "5 minutes"),
V(V3AuthDistDelay, INTERVAL, "5 minutes"),
@@ -434,6 +435,23 @@ static config_var_t option_vars_[] = {
VAR("__OwningControllerProcess",STRING,OwningControllerProcess, NULL),
V(MinUptimeHidServDirectoryV2, INTERVAL, "25 hours"),
V(VoteOnHidServDirectoriesV2, BOOL, "1"),
+ V(TestingServerDownloadSchedule, CSV_INTERVAL, "0, 0, 0, 60, 60, 120, "
+ "300, 900, 2147483647"),
+ V(TestingClientDownloadSchedule, CSV_INTERVAL, "0, 0, 60, 300, 600, "
+ "2147483647"),
+ V(TestingServerConsensusDownloadSchedule, CSV_INTERVAL, "0, 0, 60, "
+ "300, 600, 1800, 1800, 1800, 1800, "
+ "1800, 3600, 7200"),
+ V(TestingClientConsensusDownloadSchedule, CSV_INTERVAL, "0, 0, 60, "
+ "300, 600, 1800, 3600, 3600, 3600, "
+ "10800, 21600, 43200"),
+ V(TestingBridgeDownloadSchedule, CSV_INTERVAL, "3600, 900, 900, 3600"),
+ V(TestingClientMaxIntervalWithoutRequest, INTERVAL, "10 minutes"),
+ V(TestingDirConnectionMaxStall, INTERVAL, "5 minutes"),
+ V(TestingConsensusMaxDownloadTries, UINT, "8"),
+ V(TestingDescriptorMaxDownloadTries, UINT, "8"),
+ V(TestingMicrodescMaxDownloadTries, UINT, "8"),
+ V(TestingCertMaxDownloadTries, UINT, "8"),
VAR("___UsingTestNetworkDefaults", BOOL, UsingTestNetworkDefaults_, "0"),
{ NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
@@ -459,9 +477,25 @@ static const config_var_t testing_tor_network_defaults[] = {
V(TestingV3AuthInitialVotingInterval, INTERVAL, "5 minutes"),
V(TestingV3AuthInitialVoteDelay, INTERVAL, "20 seconds"),
V(TestingV3AuthInitialDistDelay, INTERVAL, "20 seconds"),
+ V(TestingV3AuthVotingStartOffset, INTERVAL, "0"),
V(TestingAuthDirTimeToLearnReachability, INTERVAL, "0 minutes"),
V(TestingEstimatedDescriptorPropagationTime, INTERVAL, "0 minutes"),
V(MinUptimeHidServDirectoryV2, INTERVAL, "0 minutes"),
+ V(TestingServerDownloadSchedule, CSV_INTERVAL, "0, 0, 0, 5, 10, 15, "
+ "20, 30, 60"),
+ V(TestingClientDownloadSchedule, CSV_INTERVAL, "0, 0, 5, 10, 15, 20, "
+ "30, 60"),
+ V(TestingServerConsensusDownloadSchedule, CSV_INTERVAL, "0, 0, 5, 10, "
+ "15, 20, 30, 60"),
+ V(TestingClientConsensusDownloadSchedule, CSV_INTERVAL, "0, 0, 5, 10, "
+ "15, 20, 30, 60"),
+ V(TestingBridgeDownloadSchedule, CSV_INTERVAL, "60, 30, 30, 60"),
+ V(TestingClientMaxIntervalWithoutRequest, INTERVAL, "5 seconds"),
+ V(TestingDirConnectionMaxStall, INTERVAL, "30 seconds"),
+ V(TestingConsensusMaxDownloadTries, UINT, "80"),
+ V(TestingDescriptorMaxDownloadTries, UINT, "80"),
+ V(TestingMicrodescMaxDownloadTries, UINT, "80"),
+ V(TestingCertMaxDownloadTries, UINT, "80"),
VAR("___UsingTestNetworkDefaults", BOOL, UsingTestNetworkDefaults_, "1"),
{ NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
@@ -476,6 +510,7 @@ static char *get_windows_conf_root(void);
#endif
static int options_validate(or_options_t *old_options,
or_options_t *options,
+ or_options_t *default_options,
int from_setconf, char **msg);
static int options_act_reversible(const or_options_t *old_options, char **msg);
static int options_act(const or_options_t *old_options);
@@ -488,7 +523,6 @@ static int options_transition_affects_descriptor(
const or_options_t *old_options, const or_options_t *new_options);
static int check_nickname_list(const char *lst, const char *name, char **msg);
-static int parse_bridge_line(const char *line, int validate_only);
static int parse_client_transport_line(const char *line, int validate_only);
static int parse_server_transport_line(const char *line, int validate_only);
@@ -971,6 +1005,7 @@ options_act_reversible(const or_options_t *old_options, char **msg)
int set_conn_limit = 0;
int r = -1;
int logs_marked = 0;
+ int old_min_log_level = get_min_log_level();
/* Daemonize _first_, since we only want to open most of this stuff in
* the subprocess. Libevent bases can't be reliably inherited across
@@ -1109,6 +1144,8 @@ options_act_reversible(const or_options_t *old_options, char **msg)
goto rollback;
}
+ sandbox_set_debugging_fd(get_err_logging_fd());
+
commit:
r = 0;
if (logs_marked) {
@@ -1119,6 +1156,13 @@ options_act_reversible(const or_options_t *old_options, char **msg)
control_adjust_event_log_severity();
tor_free(severity);
}
+ if (get_min_log_level() >= LOG_INFO &&
+ get_min_log_level() != old_min_log_level) {
+ log_warn(LD_GENERAL, "Your log may contain sensitive information - you're "
+ "logging above \"notice\". Please log safely. Don't log unless "
+ "it serves an important reason. Overwrite the log afterwards.");
+ }
+
SMARTLIST_FOREACH(replaced_listeners, connection_t *, conn,
{
log_notice(LD_NET, "Closing old %s on %s:%d",
@@ -1301,14 +1345,23 @@ options_act(const or_options_t *old_options)
}
#endif
+ if (options->SafeLogging_ != SAFELOG_SCRUB_ALL &&
+ (!old_options || old_options->SafeLogging_ != options->SafeLogging_)) {
+ log_warn(LD_GENERAL, "Your log may contain sensitive information - you "
+ "disabled SafeLogging. Please log safely. Don't log unless it "
+ "serves an important reason. Overwrite the log afterwards.");
+ }
+
if (options->Bridges) {
mark_bridge_list();
for (cl = options->Bridges; cl; cl = cl->next) {
- if (parse_bridge_line(cl->value, 0)<0) {
+ bridge_line_t *bridge_line = parse_bridge_line(cl->value);
+ if (!bridge_line) {
log_warn(LD_BUG,
"Previously validated Bridge line could not be added!");
return -1;
}
+ bridge_add_from_config(bridge_line);
}
sweep_bridge_list();
}
@@ -1851,7 +1904,8 @@ options_trial_assign(config_line_t *list, int use_defaults,
return r;
}
- if (options_validate(get_options_mutable(), trial_options, 1, msg) < 0) {
+ if (options_validate(get_options_mutable(), trial_options,
+ global_default_options, 1, msg) < 0) {
config_free(&options_format, trial_options);
return SETOPT_ERR_PARSE; /*XXX make this a separate return value. */
}
@@ -2281,10 +2335,11 @@ compute_publishserverdescriptor(or_options_t *options)
* */
#define RECOMMENDED_MIN_CIRCUIT_BUILD_TIMEOUT (10)
-/** Return 0 if every setting in <b>options</b> is reasonable, and a
- * permissible transition from <b>old_options</b>. Else return -1.
- * Should have no side effects, except for normalizing the contents of
- * <b>options</b>.
+/** Return 0 if every setting in <b>options</b> is reasonable, is a
+ * permissible transition from <b>old_options</b>, and none of the
+ * testing-only settings differ from <b>default_options</b> unless in
+ * testing mode. Else return -1. Should have no side effects, except for
+ * normalizing the contents of <b>options</b>.
*
* On error, tor_strdup an error explanation into *<b>msg</b>.
*
@@ -2295,7 +2350,7 @@ compute_publishserverdescriptor(or_options_t *options)
*/
static int
options_validate(or_options_t *old_options, or_options_t *options,
- int from_setconf, char **msg)
+ or_options_t *default_options, int from_setconf, char **msg)
{
int i;
config_line_t *cl;
@@ -2962,14 +3017,14 @@ options_validate(or_options_t *old_options, or_options_t *options,
size_t len;
len = strlen(options->Socks5ProxyUsername);
- if (len < 1 || len > 255)
+ if (len < 1 || len > MAX_SOCKS5_AUTH_FIELD_SIZE)
REJECT("Socks5ProxyUsername must be between 1 and 255 characters.");
if (!options->Socks5ProxyPassword)
REJECT("Socks5ProxyPassword must be included with Socks5ProxyUsername.");
len = strlen(options->Socks5ProxyPassword);
- if (len < 1 || len > 255)
+ if (len < 1 || len > MAX_SOCKS5_AUTH_FIELD_SIZE)
REJECT("Socks5ProxyPassword must be between 1 and 255 characters.");
} else if (options->Socks5ProxyPassword)
REJECT("Socks5ProxyPassword must be included with Socks5ProxyUsername.");
@@ -3053,8 +3108,10 @@ options_validate(or_options_t *old_options, or_options_t *options,
REJECT("If you set UseBridges, you must set TunnelDirConns.");
for (cl = options->Bridges; cl; cl = cl->next) {
- if (parse_bridge_line(cl->value, 1)<0)
- REJECT("Bridge line did not parse. See logs for details.");
+ bridge_line_t *bridge_line = parse_bridge_line(cl->value);
+ if (!bridge_line)
+ REJECT("Bridge line did not parse. See logs for details.");
+ bridge_line_free(bridge_line);
}
for (cl = options->ClientTransportPlugin; cl; cl = cl->next) {
@@ -3182,35 +3239,46 @@ options_validate(or_options_t *old_options, or_options_t *options,
"ignore you.");
}
- /*XXXX checking for defaults manually like this is a bit fragile.*/
-
- /* Keep changes to hard-coded values synchronous to man page and default
- * values table. */
- if (options->TestingV3AuthInitialVotingInterval != 30*60 &&
- !options->TestingTorNetwork && !options->UsingTestNetworkDefaults_) {
- REJECT("TestingV3AuthInitialVotingInterval may only be changed in testing "
- "Tor networks!");
- } else if (options->TestingV3AuthInitialVotingInterval < MIN_VOTE_INTERVAL) {
+#define CHECK_DEFAULT(arg) \
+ STMT_BEGIN \
+ if (!options->TestingTorNetwork && \
+ !options->UsingTestNetworkDefaults_ && \
+ !config_is_same(&options_format,options, \
+ default_options,#arg)) { \
+ REJECT(#arg " may only be changed in testing Tor " \
+ "networks!"); \
+ } STMT_END
+ CHECK_DEFAULT(TestingV3AuthInitialVotingInterval);
+ CHECK_DEFAULT(TestingV3AuthInitialVoteDelay);
+ CHECK_DEFAULT(TestingV3AuthInitialDistDelay);
+ CHECK_DEFAULT(TestingV3AuthVotingStartOffset);
+ CHECK_DEFAULT(TestingAuthDirTimeToLearnReachability);
+ CHECK_DEFAULT(TestingEstimatedDescriptorPropagationTime);
+ CHECK_DEFAULT(TestingServerDownloadSchedule);
+ CHECK_DEFAULT(TestingClientDownloadSchedule);
+ CHECK_DEFAULT(TestingServerConsensusDownloadSchedule);
+ CHECK_DEFAULT(TestingClientConsensusDownloadSchedule);
+ CHECK_DEFAULT(TestingBridgeDownloadSchedule);
+ CHECK_DEFAULT(TestingClientMaxIntervalWithoutRequest);
+ CHECK_DEFAULT(TestingDirConnectionMaxStall);
+ CHECK_DEFAULT(TestingConsensusMaxDownloadTries);
+ CHECK_DEFAULT(TestingDescriptorMaxDownloadTries);
+ CHECK_DEFAULT(TestingMicrodescMaxDownloadTries);
+ CHECK_DEFAULT(TestingCertMaxDownloadTries);
+#undef CHECK_DEFAULT
+
+ if (options->TestingV3AuthInitialVotingInterval < MIN_VOTE_INTERVAL) {
REJECT("TestingV3AuthInitialVotingInterval is insanely low.");
} else if (((30*60) % options->TestingV3AuthInitialVotingInterval) != 0) {
REJECT("TestingV3AuthInitialVotingInterval does not divide evenly into "
"30 minutes.");
}
- if (options->TestingV3AuthInitialVoteDelay != 5*60 &&
- !options->TestingTorNetwork && !options->UsingTestNetworkDefaults_) {
-
- REJECT("TestingV3AuthInitialVoteDelay may only be changed in testing "
- "Tor networks!");
- } else if (options->TestingV3AuthInitialVoteDelay < MIN_VOTE_SECONDS) {
+ if (options->TestingV3AuthInitialVoteDelay < MIN_VOTE_SECONDS) {
REJECT("TestingV3AuthInitialVoteDelay is way too low.");
}
- if (options->TestingV3AuthInitialDistDelay != 5*60 &&
- !options->TestingTorNetwork && !options->UsingTestNetworkDefaults_) {
- REJECT("TestingV3AuthInitialDistDelay may only be changed in testing "
- "Tor networks!");
- } else if (options->TestingV3AuthInitialDistDelay < MIN_DIST_SECONDS) {
+ if (options->TestingV3AuthInitialDistDelay < MIN_DIST_SECONDS) {
REJECT("TestingV3AuthInitialDistDelay is way too low.");
}
@@ -3221,26 +3289,61 @@ options_validate(or_options_t *old_options, or_options_t *options,
"must be less than half TestingV3AuthInitialVotingInterval");
}
- if (options->TestingAuthDirTimeToLearnReachability != 30*60 &&
- !options->TestingTorNetwork && !options->UsingTestNetworkDefaults_) {
- REJECT("TestingAuthDirTimeToLearnReachability may only be changed in "
- "testing Tor networks!");
- } else if (options->TestingAuthDirTimeToLearnReachability < 0) {
+ if (options->TestingV3AuthVotingStartOffset >
+ MIN(options->TestingV3AuthInitialVotingInterval,
+ options->V3AuthVotingInterval)) {
+ REJECT("TestingV3AuthVotingStartOffset is higher than the voting "
+ "interval.");
+ }
+
+ if (options->TestingAuthDirTimeToLearnReachability < 0) {
REJECT("TestingAuthDirTimeToLearnReachability must be non-negative.");
} else if (options->TestingAuthDirTimeToLearnReachability > 2*60*60) {
COMPLAIN("TestingAuthDirTimeToLearnReachability is insanely high.");
}
- if (options->TestingEstimatedDescriptorPropagationTime != 10*60 &&
- !options->TestingTorNetwork && !options->UsingTestNetworkDefaults_) {
- REJECT("TestingEstimatedDescriptorPropagationTime may only be changed in "
- "testing Tor networks!");
- } else if (options->TestingEstimatedDescriptorPropagationTime < 0) {
+ if (options->TestingEstimatedDescriptorPropagationTime < 0) {
REJECT("TestingEstimatedDescriptorPropagationTime must be non-negative.");
} else if (options->TestingEstimatedDescriptorPropagationTime > 60*60) {
COMPLAIN("TestingEstimatedDescriptorPropagationTime is insanely high.");
}
+ if (options->TestingClientMaxIntervalWithoutRequest < 1) {
+ REJECT("TestingClientMaxIntervalWithoutRequest is way too low.");
+ } else if (options->TestingClientMaxIntervalWithoutRequest > 3600) {
+ COMPLAIN("TestingClientMaxIntervalWithoutRequest is insanely high.");
+ }
+
+ if (options->TestingDirConnectionMaxStall < 5) {
+ REJECT("TestingDirConnectionMaxStall is way too low.");
+ } else if (options->TestingDirConnectionMaxStall > 3600) {
+ COMPLAIN("TestingDirConnectionMaxStall is insanely high.");
+ }
+
+ if (options->TestingConsensusMaxDownloadTries < 2) {
+ REJECT("TestingConsensusMaxDownloadTries must be greater than 1.");
+ } else if (options->TestingConsensusMaxDownloadTries > 800) {
+ COMPLAIN("TestingConsensusMaxDownloadTries is insanely high.");
+ }
+
+ if (options->TestingDescriptorMaxDownloadTries < 2) {
+ REJECT("TestingDescriptorMaxDownloadTries must be greater than 1.");
+ } else if (options->TestingDescriptorMaxDownloadTries > 800) {
+ COMPLAIN("TestingDescriptorMaxDownloadTries is insanely high.");
+ }
+
+ if (options->TestingMicrodescMaxDownloadTries < 2) {
+ REJECT("TestingMicrodescMaxDownloadTries must be greater than 1.");
+ } else if (options->TestingMicrodescMaxDownloadTries > 800) {
+ COMPLAIN("TestingMicrodescMaxDownloadTries is insanely high.");
+ }
+
+ if (options->TestingCertMaxDownloadTries < 2) {
+ REJECT("TestingCertMaxDownloadTries must be greater than 1.");
+ } else if (options->TestingCertMaxDownloadTries > 800) {
+ COMPLAIN("TestingCertMaxDownloadTries is insanely high.");
+ }
+
if (options->TestingTorNetwork) {
log_warn(LD_CONFIG, "TestingTorNetwork is set. This will make your node "
"almost unusable in the public Tor network, and is "
@@ -3859,7 +3962,8 @@ options_init_from_string(const char *cf_defaults, const char *cf,
}
/* Validate newoptions */
- if (options_validate(oldoptions, newoptions, 0, msg) < 0) {
+ if (options_validate(oldoptions, newoptions, newdefaultoptions,
+ 0, msg) < 0) {
err = SETOPT_ERR_PARSE; /*XXX make this a separate return value.*/
goto err;
}
@@ -4116,21 +4220,72 @@ options_init_logs(or_options_t *options, int validate_only)
return ok?0:-1;
}
+/** Given a smartlist of SOCKS arguments to be passed to a transport
+ * proxy in <b>args</b>, validate them and return -1 if they are
+ * corrupted. Return 0 if they seem OK. */
+static int
+validate_transport_socks_arguments(const smartlist_t *args)
+{
+ char *socks_string = NULL;
+ size_t socks_string_len;
+
+ tor_assert(args);
+ tor_assert(smartlist_len(args) > 0);
+
+ SMARTLIST_FOREACH_BEGIN(args, const char *, s) {
+ if (!string_is_key_value(LOG_WARN, s)) { /* items should be k=v items */
+ log_warn(LD_CONFIG, "'%s' is not a k=v item.", s);
+ return -1;
+ }
+ } SMARTLIST_FOREACH_END(s);
+
+ socks_string = pt_stringify_socks_args(args);
+ if (!socks_string)
+ return -1;
+
+ socks_string_len = strlen(socks_string);
+ tor_free(socks_string);
+
+ if (socks_string_len > MAX_SOCKS5_AUTH_SIZE_TOTAL) {
+ log_warn(LD_CONFIG, "SOCKS arguments can't be more than %u bytes (%lu).",
+ MAX_SOCKS5_AUTH_SIZE_TOTAL,
+ (unsigned long) socks_string_len);
+ return -1;
+ }
+
+ return 0;
+}
+
+/** Deallocate a bridge_line_t structure. */
+/* private */ void
+bridge_line_free(bridge_line_t *bridge_line)
+{
+ if (!bridge_line)
+ return;
+
+ if (bridge_line->socks_args) {
+ SMARTLIST_FOREACH(bridge_line->socks_args, char*, s, tor_free(s));
+ smartlist_free(bridge_line->socks_args);
+ }
+ tor_free(bridge_line->transport_name);
+ tor_free(bridge_line);
+}
+
/** Read the contents of a Bridge line from <b>line</b>. Return 0
* if the line is well-formed, and -1 if it isn't. If
* <b>validate_only</b> is 0, and the line is well-formed, then add
- * the bridge described in the line to our internal bridge list. */
-static int
-parse_bridge_line(const char *line, int validate_only)
+ * the bridge described in the line to our internal bridge list.
+ *
+ * Bridge line format:
+ * Bridge [transport] IP:PORT [id-fingerprint] [k=v] [k=v] ...
+ */
+/* private */ bridge_line_t *
+parse_bridge_line(const char *line)
{
smartlist_t *items = NULL;
- int r;
char *addrport=NULL, *fingerprint=NULL;
- char *transport_name=NULL;
- char *field1=NULL;
- tor_addr_t addr;
- uint16_t port = 0;
- char digest[DIGEST_LEN];
+ char *field=NULL;
+ bridge_line_t *bridge_line = tor_malloc_zero(sizeof(bridge_line_t));
items = smartlist_new();
smartlist_split_string(items, line, NULL,
@@ -4140,68 +4295,102 @@ parse_bridge_line(const char *line, int validate_only)
goto err;
}
- /* field1 is either a transport name or addrport */
- field1 = smartlist_get(items, 0);
+ /* first field is either a transport name or addrport */
+ field = smartlist_get(items, 0);
smartlist_del_keeporder(items, 0);
- if (!(strstr(field1, ".") || strstr(field1, ":"))) {
- /* new-style bridge line */
- transport_name = field1;
+ if (string_is_C_identifier(field)) {
+ /* It's a transport name. */
+ bridge_line->transport_name = field;
if (smartlist_len(items) < 1) {
log_warn(LD_CONFIG, "Too few items to Bridge line.");
goto err;
}
- addrport = smartlist_get(items, 0);
+ addrport = smartlist_get(items, 0); /* Next field is addrport then. */
smartlist_del_keeporder(items, 0);
} else {
- addrport = field1;
+ addrport = field;
}
- if (tor_addr_port_lookup(addrport, &addr, &port)<0) {
+ /* Parse addrport. */
+ if (tor_addr_port_lookup(addrport,
+ &bridge_line->addr, &bridge_line->port)<0) {
log_warn(LD_CONFIG, "Error parsing Bridge address '%s'", addrport);
goto err;
}
- if (!port) {
+ if (!bridge_line->port) {
log_info(LD_CONFIG,
"Bridge address '%s' has no port; using default port 443.",
addrport);
- port = 443;
+ bridge_line->port = 443;
}
+ /* If transports are enabled, next field could be a fingerprint or a
+ socks argument. If transports are disabled, next field must be
+ a fingerprint. */
if (smartlist_len(items)) {
- fingerprint = smartlist_join_strings(items, "", 0, NULL);
+ if (bridge_line->transport_name) { /* transports enabled: */
+ field = smartlist_get(items, 0);
+ smartlist_del_keeporder(items, 0);
+
+ /* If it's a key=value pair, then it's a SOCKS argument for the
+ transport proxy... */
+ if (string_is_key_value(LOG_DEBUG, field)) {
+ bridge_line->socks_args = smartlist_new();
+ smartlist_add(bridge_line->socks_args, field);
+ } else { /* ...otherwise, it's the bridge fingerprint. */
+ fingerprint = field;
+ }
+
+ } else { /* transports disabled: */
+ fingerprint = smartlist_join_strings(items, "", 0, NULL);
+ }
+ }
+
+ /* Handle fingerprint, if it was provided. */
+ if (fingerprint) {
if (strlen(fingerprint) != HEX_DIGEST_LEN) {
log_warn(LD_CONFIG, "Key digest for Bridge is wrong length.");
goto err;
}
- if (base16_decode(digest, DIGEST_LEN, fingerprint, HEX_DIGEST_LEN)<0) {
+ if (base16_decode(bridge_line->digest, DIGEST_LEN,
+ fingerprint, HEX_DIGEST_LEN)<0) {
log_warn(LD_CONFIG, "Unable to decode Bridge key digest.");
goto err;
}
}
- if (!validate_only) {
- log_debug(LD_DIR, "Bridge at %s (transport: %s) (%s)",
- fmt_addrport(&addr, port),
- transport_name ? transport_name : "no transport",
- fingerprint ? fingerprint : "no key listed");
- bridge_add_from_config(&addr, port,
- fingerprint ? digest : NULL, transport_name);
+ /* If we are using transports, any remaining items in the smartlist
+ should be k=v values. */
+ if (bridge_line->transport_name && smartlist_len(items)) {
+ if (!bridge_line->socks_args)
+ bridge_line->socks_args = smartlist_new();
+
+ /* append remaining items of 'items' to 'socks_args' */
+ smartlist_add_all(bridge_line->socks_args, items);
+ smartlist_clear(items);
+
+ tor_assert(smartlist_len(bridge_line->socks_args) > 0);
+ }
+
+ if (bridge_line->socks_args) {
+ if (validate_transport_socks_arguments(bridge_line->socks_args) < 0)
+ goto err;
}
- r = 0;
goto done;
err:
- r = -1;
+ bridge_line_free(bridge_line);
+ bridge_line = NULL;
done:
SMARTLIST_FOREACH(items, char*, s, tor_free(s));
smartlist_free(items);
tor_free(addrport);
- tor_free(transport_name);
tor_free(fingerprint);
- return r;
+
+ return bridge_line;
}
/** Read the contents of a ClientTransportPlugin line from
@@ -5885,6 +6074,43 @@ options_get_datadir_fname2_suffix(const or_options_t *options,
return fname;
}
+/** Check wether the data directory has a private subdirectory
+ * <b>subdir</b>. If not, try to create it. Return 0 on success,
+ * -1 otherwise. */
+int
+check_or_create_data_subdir(const char *subdir)
+{
+ char *statsdir = get_datadir_fname(subdir);
+ int return_val = 0;
+
+ if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0) {
+ log_warn(LD_HIST, "Unable to create %s/ directory!", subdir);
+ return_val = -1;
+ }
+ tor_free(statsdir);
+ return return_val;
+}
+
+/** Create a file named <b>fname</b> with contents <b>str</b> in the
+ * subdirectory <b>subdir</b> of the data directory. <b>descr</b>
+ * should be a short description of the file's content and will be
+ * used for the warning message, if it's present and the write process
+ * fails. Return 0 on success, -1 otherwise.*/
+int
+write_to_data_subdir(const char* subdir, const char* fname,
+ const char* str, const char* descr)
+{
+ char *filename = get_datadir_fname2(subdir, fname);
+ int return_val = 0;
+
+ if (write_str_to_file(filename, str, 0) < 0) {
+ log_warn(LD_HIST, "Unable to write %s to disk!", descr ? descr : fname);
+ return_val = -1;
+ }
+ tor_free(filename);
+ return return_val;
+}
+
/** Given a file name check to see whether the file exists but has not been
* modified for a very long time. If so, remove it. */
void
@@ -5974,6 +6200,7 @@ getinfo_helper_config(control_connection_t *conn,
case CONFIG_TYPE_ISOTIME: type = "Time"; break;
case CONFIG_TYPE_ROUTERSET: type = "RouterList"; break;
case CONFIG_TYPE_CSV: type = "CommaList"; break;
+ case CONFIG_TYPE_CSV_INTERVAL: type = "TimeIntervalCommaList"; break;
case CONFIG_TYPE_LINELIST: type = "LineList"; break;
case CONFIG_TYPE_LINELIST_S: type = "Dependant"; break;
case CONFIG_TYPE_LINELIST_V: type = "Virtual"; break;
diff --git a/src/or/config.h b/src/or/config.h
index ef4acac51..c35214cd0 100644
--- a/src/or/config.h
+++ b/src/or/config.h
@@ -59,6 +59,10 @@ char *options_get_datadir_fname2_suffix(const or_options_t *options,
#define get_datadir_fname_suffix(sub1, suffix) \
get_datadir_fname2_suffix((sub1), NULL, (suffix))
+int check_or_create_data_subdir(const char *subdir);
+int write_to_data_subdir(const char* subdir, const char* fname,
+ const char* str, const char* descr);
+
int get_num_cpus(const or_options_t *options);
const smartlist_t *get_configured_ports(void);
@@ -86,10 +90,7 @@ uint32_t get_effective_bwburst(const or_options_t *options);
char *get_transport_bindaddr_from_config(const char *transport);
-#ifdef CONFIG_PRIVATE
-/* Used only by config.c and test.c */
or_options_t *options_new(void);
-#endif
void config_register_addressmaps(const or_options_t *options);
/* XXXX024 move to connection_edge.h */
@@ -98,5 +99,19 @@ int addressmap_register_auto(const char *from, const char *to,
addressmap_entry_source_t addrmap_source,
const char **msg);
+/** Represents the information stored in a torrc Bridge line. */
+typedef struct bridge_line_t {
+ tor_addr_t addr; /* The IP address of the bridge. */
+ uint16_t port; /* The TCP port of the bridge. */
+ char *transport_name; /* The name of the pluggable transport that
+ should be used to connect to the bridge. */
+ char digest[DIGEST_LEN]; /* The bridge's identity key digest. */
+ smartlist_t *socks_args; /* SOCKS arguments for the pluggable
+ transport proxy. */
+} bridge_line_t;
+
+void bridge_line_free(bridge_line_t *bridge_line);
+bridge_line_t *parse_bridge_line(const char *line);
+
#endif
diff --git a/src/or/confparse.c b/src/or/confparse.c
index 8863d9240..eb0362f49 100644
--- a/src/or/confparse.c
+++ b/src/or/confparse.c
@@ -223,6 +223,8 @@ config_assign_value(const config_format_t *fmt, void *options,
int i, ok;
const config_var_t *var;
void *lvalue;
+ int *csv_int;
+ smartlist_t *csv_str;
CONFIG_CHECK(fmt, options);
@@ -357,6 +359,36 @@ config_assign_value(const config_format_t *fmt, void *options,
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
break;
+ case CONFIG_TYPE_CSV_INTERVAL:
+ if (*(smartlist_t**)lvalue) {
+ SMARTLIST_FOREACH(*(smartlist_t**)lvalue, int *, cp, tor_free(cp));
+ smartlist_clear(*(smartlist_t**)lvalue);
+ } else {
+ *(smartlist_t**)lvalue = smartlist_new();
+ }
+ csv_str = smartlist_new();
+ smartlist_split_string(csv_str, c->value, ",",
+ SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
+ SMARTLIST_FOREACH_BEGIN(csv_str, char *, str)
+ {
+ i = config_parse_interval(str, &ok);
+ if (!ok) {
+ tor_asprintf(msg,
+ "Interval in '%s %s' is malformed or out of bounds.",
+ c->key, c->value);
+ SMARTLIST_FOREACH(csv_str, char *, cp, tor_free(cp));
+ smartlist_clear(csv_str);
+ return -1;
+ }
+ csv_int = tor_malloc_zero(sizeof(int));
+ *csv_int = i;
+ smartlist_add(*(smartlist_t**)lvalue, csv_int);
+ }
+ SMARTLIST_FOREACH_END(str);
+ SMARTLIST_FOREACH(csv_str, char *, cp, tor_free(cp));
+ smartlist_clear(csv_str);
+ break;
+
case CONFIG_TYPE_LINELIST:
case CONFIG_TYPE_LINELIST_S:
{
@@ -555,6 +587,7 @@ config_get_assigned_option(const config_format_t *fmt, const void *options,
const config_var_t *var;
const void *value;
config_line_t *result;
+ smartlist_t *csv_str;
tor_assert(options && key);
CONFIG_CHECK(fmt, options);
@@ -637,6 +670,20 @@ config_get_assigned_option(const config_format_t *fmt, const void *options,
else
result->value = tor_strdup("");
break;
+ case CONFIG_TYPE_CSV_INTERVAL:
+ if (*(smartlist_t**)value) {
+ csv_str = smartlist_new();
+ SMARTLIST_FOREACH_BEGIN(*(smartlist_t**)value, int *, i)
+ {
+ smartlist_add_asprintf(csv_str, "%d", *i);
+ }
+ SMARTLIST_FOREACH_END(i);
+ result->value = smartlist_join_strings(csv_str, ",", 0, NULL);
+ SMARTLIST_FOREACH(csv_str, char *, cp, tor_free(cp));
+ smartlist_free(csv_str);
+ } else
+ result->value = tor_strdup("");
+ break;
case CONFIG_TYPE_OBSOLETE:
log_fn(LOG_INFO, LD_CONFIG,
"You asked me for the value of an obsolete config option '%s'.",
@@ -826,6 +873,13 @@ config_clear(const config_format_t *fmt, void *options,
*(smartlist_t **)lvalue = NULL;
}
break;
+ case CONFIG_TYPE_CSV_INTERVAL:
+ if (*(smartlist_t**)lvalue) {
+ SMARTLIST_FOREACH(*(smartlist_t **)lvalue, int *, cp, tor_free(cp));
+ smartlist_free(*(smartlist_t **)lvalue);
+ *(smartlist_t **)lvalue = NULL;
+ }
+ break;
case CONFIG_TYPE_LINELIST:
case CONFIG_TYPE_LINELIST_S:
config_free_lines(*(config_line_t **)lvalue);
diff --git a/src/or/confparse.h b/src/or/confparse.h
index 1b987f3bf..d82e1096c 100644
--- a/src/or/confparse.h
+++ b/src/or/confparse.h
@@ -26,6 +26,9 @@ typedef enum config_type_t {
CONFIG_TYPE_ISOTIME, /**< An ISO-formatted time relative to UTC. */
CONFIG_TYPE_CSV, /**< A list of strings, separated by commas and
* optional whitespace. */
+ CONFIG_TYPE_CSV_INTERVAL, /**< A list of strings, separated by commas and
+ * optional whitespace, representing intervals in
+ * seconds, with optional units */
CONFIG_TYPE_LINELIST, /**< Uninterpreted config lines */
CONFIG_TYPE_LINELIST_S, /**< Uninterpreted, context-sensitive config lines,
* mixed with other keywords. */
diff --git a/src/or/connection.c b/src/or/connection.c
index 6e754a0f7..6a3cc7bec 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -44,6 +44,7 @@
#include "router.h"
#include "transports.h"
#include "routerparse.h"
+#include "transports.h"
#ifdef USE_BUFFEREVENTS
#include <event2/event.h>
@@ -876,8 +877,11 @@ check_location_for_unix_socket(const or_options_t *options, const char *path)
int r = -1;
char *p = tor_strdup(path);
cpd_check_t flags = CPD_CHECK_MODE_ONLY;
- if (get_parent_directory(p)<0)
+ if (get_parent_directory(p)<0 || p[0] != '/') {
+ log_warn(LD_GENERAL, "Bad unix socket address '%s'. Tor does not support "
+ "relative paths for unix sockets.", path);
goto done;
+ }
if (options->ControlSocketsGroupWritable)
flags |= CPD_GROUP_OK;
@@ -939,8 +943,8 @@ connection_listener_new(const struct sockaddr *listensockaddr,
const port_cfg_t *port_cfg)
{
listener_connection_t *lis_conn;
- connection_t *conn;
- tor_socket_t s; /* the socket we're going to make */
+ connection_t *conn = NULL;
+ tor_socket_t s = TOR_INVALID_SOCKET; /* the socket we're going to make */
or_options_t const *options = get_options();
#if defined(HAVE_PWD_H) && defined(HAVE_SYS_UN_H)
struct passwd *pw = NULL;
@@ -988,7 +992,7 @@ connection_listener_new(const struct sockaddr *listensockaddr,
/* We need to set IPV6_V6ONLY so that this socket can't get used for
* IPv4 connections. */
if (setsockopt(s,IPPROTO_IPV6, IPV6_V6ONLY,
- (void*)&one, sizeof(one))<0) {
+ (void*)&one, sizeof(one)) < 0) {
int e = tor_socket_errno(s);
log_warn(LD_NET, "Error setting IPV6_V6ONLY flag: %s",
tor_socket_strerror(e));
@@ -1004,7 +1008,6 @@ connection_listener_new(const struct sockaddr *listensockaddr,
helpfulhint = ". Is Tor already running?";
log_warn(LD_NET, "Could not bind to %s:%u: %s%s", address, usePort,
tor_socket_strerror(e), helpfulhint);
- tor_close_socket(s);
goto err;
}
@@ -1012,7 +1015,6 @@ connection_listener_new(const struct sockaddr *listensockaddr,
if (listen(s,SOMAXCONN) < 0) {
log_warn(LD_NET, "Could not listen on %s:%u: %s", address, usePort,
tor_socket_strerror(tor_socket_errno(s)));
- tor_close_socket(s);
goto err;
}
}
@@ -1061,7 +1063,6 @@ connection_listener_new(const struct sockaddr *listensockaddr,
if (bind(s, listensockaddr, (socklen_t)sizeof(struct sockaddr_un)) == -1) {
log_warn(LD_NET,"Bind to %s failed: %s.", address,
tor_socket_strerror(tor_socket_errno(s)));
- tor_close_socket(s);
goto err;
}
#ifdef HAVE_PWD_H
@@ -1070,12 +1071,10 @@ connection_listener_new(const struct sockaddr *listensockaddr,
if (pw == NULL) {
log_warn(LD_NET,"Unable to chown() %s socket: user %s not found.",
address, options->User);
- tor_close_socket(s);
goto err;
} else if (chown(address, pw->pw_uid, pw->pw_gid) < 0) {
log_warn(LD_NET,"Unable to chown() %s socket: %s.",
address, strerror(errno));
- tor_close_socket(s);
goto err;
}
}
@@ -1085,35 +1084,32 @@ connection_listener_new(const struct sockaddr *listensockaddr,
* platforms. */
if (chmod(address, 0660) < 0) {
log_warn(LD_FS,"Unable to make %s group-writable.", address);
- tor_close_socket(s);
goto err;
}
}
- if (listen(s,SOMAXCONN) < 0) {
+ if (listen(s, SOMAXCONN) < 0) {
log_warn(LD_NET, "Could not listen on %s: %s", address,
tor_socket_strerror(tor_socket_errno(s)));
- tor_close_socket(s);
goto err;
}
#else
(void)options;
#endif /* HAVE_SYS_UN_H */
} else {
- log_err(LD_BUG,"Got unexpected address family %d.",
- listensockaddr->sa_family);
- tor_assert(0);
+ log_err(LD_BUG, "Got unexpected address family %d.",
+ listensockaddr->sa_family);
+ tor_assert(0);
}
- if (set_socket_nonblocking(s) == -1) {
- tor_close_socket(s);
+ if (set_socket_nonblocking(s) == -1)
goto err;
- }
lis_conn = listener_connection_new(type, listensockaddr->sa_family);
conn = TO_CONN(lis_conn);
conn->socket_family = listensockaddr->sa_family;
conn->s = s;
+ s = TOR_INVALID_SOCKET; /* Prevent double-close */
conn->address = tor_strdup(address);
conn->port = gotPort;
tor_addr_copy(&conn->addr, &addr);
@@ -1149,7 +1145,6 @@ connection_listener_new(const struct sockaddr *listensockaddr,
if (connection_add(conn) < 0) { /* no space, forget it */
log_warn(LD_NET,"connection_add for listener failed. Giving up.");
- connection_free(conn);
goto err;
}
@@ -1168,6 +1163,11 @@ connection_listener_new(const struct sockaddr *listensockaddr,
return conn;
err:
+ if (SOCKET_OK(s))
+ tor_close_socket(s);
+ if (conn)
+ connection_free(conn);
+
return NULL;
}
@@ -1580,6 +1580,32 @@ connection_proxy_state_to_string(int state)
return states[state];
}
+/** Returns the global proxy type used by tor. Use this function for
+ * logging or high-level purposes, don't use it to fill the
+ * <b>proxy_type</b> field of or_connection_t; use the actual proxy
+ * protocol instead.*/
+static int
+get_proxy_type(void)
+{
+ const or_options_t *options = get_options();
+
+ if (options->HTTPSProxy)
+ return PROXY_CONNECT;
+ else if (options->Socks4Proxy)
+ return PROXY_SOCKS4;
+ else if (options->Socks5Proxy)
+ return PROXY_SOCKS5;
+ else if (options->ClientTransportPlugin)
+ return PROXY_PLUGGABLE;
+ else
+ return PROXY_NONE;
+}
+
+/* One byte for the version, one for the command, two for the
+ port, and four for the addr... and, one more for the
+ username NUL: */
+#define SOCKS4_STANDARD_BUFFER_SIZE (1 + 1 + 2 + 4 + 1)
+
/** Write a proxy request of <b>type</b> (socks4, socks5, https) to conn
* for conn->addr:conn->port, authenticating with the auth details given
* in the configuration (if available). SOCKS 5 and HTTP CONNECT proxies
@@ -1634,17 +1660,45 @@ connection_proxy_connect(connection_t *conn, int type)
}
case PROXY_SOCKS4: {
- unsigned char buf[9];
+ unsigned char *buf;
uint16_t portn;
uint32_t ip4addr;
+ size_t buf_size = 0;
+ char *socks_args_string = NULL;
- /* Send a SOCKS4 connect request with empty user id */
+ /* Send a SOCKS4 connect request */
if (tor_addr_family(&conn->addr) != AF_INET) {
log_warn(LD_NET, "SOCKS4 client is incompatible with IPv6");
return -1;
}
+ { /* If we are here because we are trying to connect to a
+ pluggable transport proxy, check if we have any SOCKS
+ arguments to transmit. If we do, compress all arguments to
+ a single string in 'socks_args_string': */
+
+ if (get_proxy_type() == PROXY_PLUGGABLE) {
+ socks_args_string =
+ pt_get_socks_args_for_proxy_addrport(&conn->addr, conn->port);
+ if (socks_args_string)
+ log_debug(LD_NET, "Sending out '%s' as our SOCKS argument string.",
+ socks_args_string);
+ }
+ }
+
+ { /* Figure out the buffer size we need for the SOCKS message: */
+
+ buf_size = SOCKS4_STANDARD_BUFFER_SIZE;
+
+ /* If we have a SOCKS argument string, consider its size when
+ calculating the buffer size: */
+ if (socks_args_string)
+ buf_size += strlen(socks_args_string);
+ }
+
+ buf = tor_malloc_zero(buf_size);
+
ip4addr = tor_addr_to_ipv4n(&conn->addr);
portn = htons(conn->port);
@@ -1652,9 +1706,23 @@ connection_proxy_connect(connection_t *conn, int type)
buf[1] = SOCKS_COMMAND_CONNECT; /* command */
memcpy(buf + 2, &portn, 2); /* port */
memcpy(buf + 4, &ip4addr, 4); /* addr */
- buf[8] = 0; /* userid (empty) */
- connection_write_to_buf((char *)buf, sizeof(buf), conn);
+ /* Next packet field is the userid. If we have pluggable
+ transport SOCKS arguments, we have to embed them
+ there. Otherwise, we use an empty userid. */
+ if (socks_args_string) { /* place the SOCKS args string: */
+ tor_assert(strlen(socks_args_string) > 0);
+ tor_assert(buf_size >=
+ SOCKS4_STANDARD_BUFFER_SIZE + strlen(socks_args_string));
+ strlcpy((char *)buf + 8, socks_args_string, buf_size - 8);
+ tor_free(socks_args_string);
+ } else {
+ buf[8] = 0; /* no userid */
+ }
+
+ connection_write_to_buf((char *)buf, buf_size, conn);
+ tor_free(buf);
+
conn->proxy_state = PROXY_SOCKS4_WANT_CONNECT_OK;
break;
}
@@ -1666,8 +1734,13 @@ connection_proxy_connect(connection_t *conn, int type)
buf[0] = 5; /* version */
+ /* We have to use SOCKS5 authentication, if we have a
+ Socks5ProxyUsername or if we want to pass arguments to our
+ pluggable transport proxy: */
+ if ((options->Socks5ProxyUsername) ||
+ (get_proxy_type() == PROXY_PLUGGABLE &&
+ (get_socks_args_by_bridge_addrport(&conn->addr, conn->port)))) {
/* number of auth methods */
- if (options->Socks5ProxyUsername) {
buf[1] = 2;
buf[2] = 0x00; /* no authentication */
buf[3] = 0x02; /* rfc1929 Username/Passwd auth */
@@ -1861,15 +1934,49 @@ connection_read_proxy_handshake(connection_t *conn)
unsigned char buf[1024];
size_t reqsize, usize, psize;
const char *user, *pass;
+ char *socks_args_string = NULL;
+
+ if (get_proxy_type() == PROXY_PLUGGABLE) {
+ socks_args_string =
+ pt_get_socks_args_for_proxy_addrport(&conn->addr, conn->port);
+ if (!socks_args_string) {
+ log_warn(LD_NET, "Could not create SOCKS args string.");
+ ret = -1;
+ break;
+ }
+
+ log_debug(LD_NET, "SOCKS5 arguments: %s", socks_args_string);
+ tor_assert(strlen(socks_args_string) > 0);
+ tor_assert(strlen(socks_args_string) <= MAX_SOCKS5_AUTH_SIZE_TOTAL);
+
+ if (strlen(socks_args_string) > MAX_SOCKS5_AUTH_FIELD_SIZE) {
+ user = socks_args_string;
+ usize = MAX_SOCKS5_AUTH_FIELD_SIZE;
+ pass = socks_args_string + MAX_SOCKS5_AUTH_FIELD_SIZE;
+ psize = strlen(socks_args_string) - MAX_SOCKS5_AUTH_FIELD_SIZE;
+ } else {
+ user = socks_args_string;
+ usize = strlen(socks_args_string);
+ pass = "\0";
+ psize = 1;
+ }
+ } else if (get_options()->Socks5ProxyUsername) {
+ user = get_options()->Socks5ProxyUsername;
+ pass = get_options()->Socks5ProxyPassword;
+ tor_assert(user && pass);
+ usize = strlen(user);
+ psize = strlen(pass);
+ } else {
+ log_err(LD_BUG, "We entered %s for no reason!", __func__);
+ tor_fragile_assert();
+ ret = -1;
+ break;
+ }
- user = get_options()->Socks5ProxyUsername;
- pass = get_options()->Socks5ProxyPassword;
- tor_assert(user && pass);
-
- /* XXX len of user and pass must be <= 255 !!! */
- usize = strlen(user);
- psize = strlen(pass);
- tor_assert(usize <= 255 && psize <= 255);
+ /* Username and password lengths should have been checked
+ above and during torrc parsing. */
+ tor_assert(usize <= MAX_SOCKS5_AUTH_FIELD_SIZE &&
+ psize <= MAX_SOCKS5_AUTH_FIELD_SIZE);
reqsize = 3 + usize + psize;
buf[0] = 1; /* negotiation version */
@@ -1878,6 +1985,9 @@ connection_read_proxy_handshake(connection_t *conn)
buf[2 + usize] = psize;
memcpy(buf + 3 + usize, pass, psize);
+ if (socks_args_string)
+ tor_free(socks_args_string);
+
connection_write_to_buf((char *)buf, reqsize, conn);
conn->proxy_state = PROXY_SOCKS5_WANT_AUTH_RFC1929_OK;
@@ -3288,8 +3398,8 @@ connection_outbuf_too_full(connection_t *conn)
/** Try to flush more bytes onto <b>conn</b>-\>s.
*
- * This function gets called either from conn_write() in main.c
- * when poll() has declared that conn wants to write, or below
+ * This function gets called either from conn_write_callback() in main.c
+ * when libevent tells us that conn wants to write, or below
* from connection_write_to_buf() when an entire TLS record is ready.
*
* Update <b>conn</b>-\>timestamp_lastwritten to now, and call flush_buf
@@ -4366,7 +4476,7 @@ get_proxy_addrport(tor_addr_t *addr, uint16_t *port, int *proxy_type,
options->Bridges) {
const transport_t *transport = NULL;
int r;
- r = find_transport_by_bridge_addrport(&conn->addr, conn->port, &transport);
+ r = get_transport_by_bridge_addrport(&conn->addr, conn->port, &transport);
if (r<0)
return -1;
if (transport) { /* transport found */
@@ -4381,24 +4491,6 @@ get_proxy_addrport(tor_addr_t *addr, uint16_t *port, int *proxy_type,
return 0;
}
-/** Returns the global proxy type used by tor. */
-static int
-get_proxy_type(void)
-{
- const or_options_t *options = get_options();
-
- if (options->HTTPSProxy)
- return PROXY_CONNECT;
- else if (options->Socks4Proxy)
- return PROXY_SOCKS4;
- else if (options->Socks5Proxy)
- return PROXY_SOCKS5;
- else if (options->ClientTransportPlugin)
- return PROXY_PLUGGABLE;
- else
- return PROXY_NONE;
-}
-
/** Log a failed connection to a proxy server.
* <b>conn</b> is the connection we use the proxy server for. */
void
diff --git a/src/or/connection.h b/src/or/connection.h
index c78fe6e65..3e656ec06 100644
--- a/src/or/connection.h
+++ b/src/or/connection.h
@@ -89,6 +89,14 @@ int connection_connect(connection_t *conn, const char *address,
const tor_addr_t *addr,
uint16_t port, int *socket_error);
+/** Maximum size of information that we can fit into SOCKS5 username
+ or password fields. */
+#define MAX_SOCKS5_AUTH_FIELD_SIZE 255
+
+/** Total maximum size of information that we can fit into SOCKS5
+ username and password fields. */
+#define MAX_SOCKS5_AUTH_SIZE_TOTAL 2*MAX_SOCKS5_AUTH_FIELD_SIZE
+
int connection_proxy_connect(connection_t *conn, int type);
int connection_read_proxy_handshake(connection_t *conn);
void log_failed_proxy_connection(connection_t *conn);
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c
index bb7ffb9a4..33585a094 100644
--- a/src/or/connection_edge.c
+++ b/src/or/connection_edge.c
@@ -407,7 +407,7 @@ connection_edge_finished_flushing(edge_connection_t *conn)
* that the name resolution that led us to <b>addr</b> will be valid for
* <b>ttl</b> seconds. Return -1 on error, or the number of bytes used on
* success. */
-/* private */int
+STATIC int
connected_cell_format_payload(uint8_t *payload_out,
const tor_addr_t *addr,
uint32_t ttl)
@@ -2265,7 +2265,7 @@ connection_ap_handshake_socks_reply(entry_connection_t *conn, char *reply,
* Return -1 in the case where want to send a RELAY_END cell, and < -1 when
* we don't.
**/
-/* static */ int
+STATIC int
begin_cell_parse(const cell_t *cell, begin_cell_t *bcell,
uint8_t *end_reason_out)
{
diff --git a/src/or/connection_edge.h b/src/or/connection_edge.h
index ea284cbcf..e3a95ad9e 100644
--- a/src/or/connection_edge.h
+++ b/src/or/connection_edge.h
@@ -12,6 +12,8 @@
#ifndef TOR_CONNECTION_EDGE_H
#define TOR_CONNECTION_EDGE_H
+#include "testsupport.h"
+
#define connection_mark_unattached_ap(conn, endreason) \
connection_mark_unattached_ap_((conn), (endreason), __LINE__, SHORT_FILE__)
@@ -130,9 +132,9 @@ typedef struct begin_cell_t {
unsigned is_begindir : 1;
} begin_cell_t;
-int begin_cell_parse(const cell_t *cell, begin_cell_t *bcell,
+STATIC int begin_cell_parse(const cell_t *cell, begin_cell_t *bcell,
uint8_t *end_reason_out);
-int connected_cell_format_payload(uint8_t *payload_out,
+STATIC int connected_cell_format_payload(uint8_t *payload_out,
const tor_addr_t *addr,
uint32_t ttl);
#endif
diff --git a/src/or/control.c b/src/or/control.c
index a88de12d6..3f8d47c55 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -334,7 +334,7 @@ connection_write_str_to_buf(const char *s, control_connection_t *conn)
* the end. Replace all LF characters sequences with CRLF. Return the number
* of bytes in *<b>out</b>.
*/
-/* static */ size_t
+STATIC size_t
write_escaped_data(const char *data, size_t len, char **out)
{
size_t sz_out = len+8;
@@ -382,7 +382,7 @@ write_escaped_data(const char *data, size_t len, char **out)
* that appears at the start of a line, and replacing all CRLF sequences
* with LF. Return the number of
* bytes in *<b>out</b>. */
-/* static */ size_t
+STATIC size_t
read_escaped_data(const char *data, size_t len, char **out)
{
char *outp;
@@ -1572,7 +1572,8 @@ munge_extrainfo_into_routerinfo(const char *ri_body,
if (!(cp = tor_memstr(ei_body, ei_len, kwd)))
continue;
++cp;
- eol = memchr(cp, '\n', ei_len - (cp-ei_body));
+ if (!(eol = memchr(cp, '\n', ei_len - (cp-ei_body))))
+ continue;
memcpy(outp, cp, eol-cp+1);
outp += eol-cp+1;
}
diff --git a/src/or/control.h b/src/or/control.h
index 61062da2c..d0f682067 100644
--- a/src/or/control.h
+++ b/src/or/control.h
@@ -91,8 +91,8 @@ void control_event_clients_seen(const char *controller_str);
#ifdef CONTROL_PRIVATE
/* Used only by control.c and test.c */
-size_t write_escaped_data(const char *data, size_t len, char **out);
-size_t read_escaped_data(const char *data, size_t len, char **out);
+STATIC size_t write_escaped_data(const char *data, size_t len, char **out);
+STATIC size_t read_escaped_data(const char *data, size_t len, char **out);
#endif
#endif
diff --git a/src/or/directory.c b/src/or/directory.c
index b4381ac0d..88d671779 100644
--- a/src/or/directory.c
+++ b/src/or/directory.c
@@ -3723,57 +3723,27 @@ dir_networkstatus_download_failed(smartlist_t *failed, int status_code)
} SMARTLIST_FOREACH_END(fp);
}
-/** Schedule for when servers should download things in general. */
-static const int server_dl_schedule[] = {
- 0, 0, 0, 60, 60, 60*2, 60*5, 60*15, INT_MAX
-};
-/** Schedule for when clients should download things in general. */
-static const int client_dl_schedule[] = {
- 0, 0, 60, 60*5, 60*10, INT_MAX
-};
-/** Schedule for when servers should download consensuses. */
-static const int server_consensus_dl_schedule[] = {
- 0, 0, 60, 60*5, 60*10, 60*30, 60*30, 60*30, 60*30, 60*30, 60*60, 60*60*2
-};
-/** Schedule for when clients should download consensuses. */
-static const int client_consensus_dl_schedule[] = {
- 0, 0, 60, 60*5, 60*10, 60*30, 60*60, 60*60, 60*60, 60*60*3, 60*60*6, 60*60*12
-};
-/** Schedule for when clients should download bridge descriptors. */
-static const int bridge_dl_schedule[] = {
- 60*60, 15*60, 15*60, 60*60
-};
-
-/** Decide which download schedule we want to use, and then return a
- * pointer to it along with a pointer to its length. Helper function for
- * download_status_increment_failure() and download_status_reset(). */
-static void
-find_dl_schedule_and_len(download_status_t *dls, int server,
- const int **schedule, size_t *schedule_len)
+/** Decide which download schedule we want to use based on descriptor type
+ * in <b>dls</b> and whether we are acting as directory <b>server</b>, and
+ * then return a list of int pointers defining download delays in seconds.
+ * Helper function for download_status_increment_failure() and
+ * download_status_reset(). */
+static const smartlist_t *
+find_dl_schedule_and_len(download_status_t *dls, int server)
{
switch (dls->schedule) {
case DL_SCHED_GENERIC:
- if (server) {
- *schedule = server_dl_schedule;
- *schedule_len = sizeof(server_dl_schedule)/sizeof(int);
- } else {
- *schedule = client_dl_schedule;
- *schedule_len = sizeof(client_dl_schedule)/sizeof(int);
- }
- break;
+ if (server)
+ return get_options()->TestingServerDownloadSchedule;
+ else
+ return get_options()->TestingClientDownloadSchedule;
case DL_SCHED_CONSENSUS:
- if (server) {
- *schedule = server_consensus_dl_schedule;
- *schedule_len = sizeof(server_consensus_dl_schedule)/sizeof(int);
- } else {
- *schedule = client_consensus_dl_schedule;
- *schedule_len = sizeof(client_consensus_dl_schedule)/sizeof(int);
- }
- break;
+ if (server)
+ return get_options()->TestingServerConsensusDownloadSchedule;
+ else
+ return get_options()->TestingClientConsensusDownloadSchedule;
case DL_SCHED_BRIDGE:
- *schedule = bridge_dl_schedule;
- *schedule_len = sizeof(bridge_dl_schedule)/sizeof(int);
- break;
+ return get_options()->TestingBridgeDownloadSchedule;
default:
tor_assert(0);
}
@@ -3787,8 +3757,7 @@ time_t
download_status_increment_failure(download_status_t *dls, int status_code,
const char *item, int server, time_t now)
{
- const int *schedule;
- size_t schedule_len;
+ const smartlist_t *schedule;
int increment;
tor_assert(dls);
if (status_code != 503 || server) {
@@ -3796,14 +3765,14 @@ download_status_increment_failure(download_status_t *dls, int status_code,
++dls->n_download_failures;
}
- find_dl_schedule_and_len(dls, server, &schedule, &schedule_len);
+ schedule = find_dl_schedule_and_len(dls, server);
- if (dls->n_download_failures < schedule_len)
- increment = schedule[dls->n_download_failures];
+ if (dls->n_download_failures < smartlist_len(schedule))
+ increment = *(int *)smartlist_get(schedule, dls->n_download_failures);
else if (dls->n_download_failures == IMPOSSIBLE_TO_DOWNLOAD)
increment = INT_MAX;
else
- increment = schedule[schedule_len-1];
+ increment = *(int *)smartlist_get(schedule, smartlist_len(schedule) - 1);
if (increment < INT_MAX)
dls->next_attempt_at = now+increment;
@@ -3836,14 +3805,11 @@ download_status_increment_failure(download_status_t *dls, int status_code,
void
download_status_reset(download_status_t *dls)
{
- const int *schedule;
- size_t schedule_len;
-
- find_dl_schedule_and_len(dls, get_options()->DirPort_set,
- &schedule, &schedule_len);
+ const smartlist_t *schedule = find_dl_schedule_and_len(
+ dls, get_options()->DirPort_set);
dls->n_download_failures = 0;
- dls->next_attempt_at = time(NULL) + schedule[0];
+ dls->next_attempt_at = time(NULL) + *(int *)smartlist_get(schedule, 0);
}
/** Return the number of failures on <b>dls</b> since the last success (if
@@ -3888,7 +3854,8 @@ dir_routerdesc_download_failed(smartlist_t *failed, int status_code,
} else {
dls = router_get_dl_status_by_descriptor_digest(digest);
}
- if (!dls || dls->n_download_failures >= MAX_ROUTERDESC_DOWNLOAD_FAILURES)
+ if (!dls || dls->n_download_failures >=
+ get_options()->TestingDescriptorMaxDownloadTries)
continue;
download_status_increment_failure(dls, status_code, cp, server, now);
} SMARTLIST_FOREACH_END(cp);
@@ -3919,7 +3886,8 @@ dir_microdesc_download_failed(smartlist_t *failed,
if (!rs)
continue;
dls = &rs->dl_status;
- if (dls->n_download_failures >= MAX_MICRODESC_DOWNLOAD_FAILURES)
+ if (dls->n_download_failures >=
+ get_options()->TestingMicrodescMaxDownloadTries)
continue;
{
char buf[BASE64_DIGEST256_LEN+1];
diff --git a/src/or/dirserv.c b/src/or/dirserv.c
index 3e46153a5..3243ac47c 100644
--- a/src/or/dirserv.c
+++ b/src/or/dirserv.c
@@ -1907,7 +1907,7 @@ router_counts_toward_thresholds(const node_t *node, time_t now,
* the Weighted Fractional Uptime history, and use them to set thresholds for
* the Stable, Fast, and Guard flags. Update the fields stable_uptime,
* stable_mtbf, enough_mtbf_info, guard_wfu, guard_tk, fast_bandwidth,
- * guard_bandwidh_including_exits, guard_bandwidth_excluding_exits,
+ * guard_bandwidth_including_exits, and guard_bandwidth_excluding_exits.
*
* Also, set the is_exit flag of each router appropriately. */
static void
@@ -2082,7 +2082,7 @@ static digestmap_t *mbw_cache = NULL;
/** Store a measured bandwidth cache entry when reading the measured
* bandwidths file. */
-void
+STATIC void
dirserv_cache_measured_bw(const measured_bw_line_t *parsed_line,
time_t as_of)
{
@@ -2112,7 +2112,7 @@ dirserv_cache_measured_bw(const measured_bw_line_t *parsed_line,
}
/** Clear and free the measured bandwidth cache */
-void
+STATIC void
dirserv_clear_measured_bw_cache(void)
{
if (mbw_cache) {
@@ -2123,7 +2123,7 @@ dirserv_clear_measured_bw_cache(void)
}
/** Scan the measured bandwidth cache and remove expired entries */
-void
+STATIC void
dirserv_expire_measured_bw_cache(time_t now)
{
@@ -2145,7 +2145,7 @@ dirserv_expire_measured_bw_cache(time_t now)
}
/** Get the current size of the measured bandwidth cache */
-int
+STATIC int
dirserv_get_measured_bw_cache_size(void)
{
if (mbw_cache) return digestmap_size(mbw_cache);
@@ -2155,7 +2155,7 @@ dirserv_get_measured_bw_cache_size(void)
/** Query the cache by identity digest, return value indicates whether
* we found it. The bw_out and as_of_out pointers receive the cached
* bandwidth value and the time it was cached if not NULL. */
-int
+STATIC int
dirserv_query_measured_bw_cache_kb(const char *node_id, long *bw_kb_out,
time_t *as_of_out)
{
@@ -2176,7 +2176,7 @@ dirserv_query_measured_bw_cache_kb(const char *node_id, long *bw_kb_out,
}
/** Predicate wrapper for dirserv_query_measured_bw_cache() */
-int
+STATIC int
dirserv_has_measured_bw(const char *node_id)
{
return dirserv_query_measured_bw_cache_kb(node_id, NULL, NULL);
@@ -2754,7 +2754,7 @@ clear_status_flags_on_sybil(routerstatus_t *rs)
* into a measured_bw_line_t output structure. Returns -1 on failure
* or 0 on success.
*/
-int
+STATIC int
measured_bw_line_parse(measured_bw_line_t *out, const char *orig_line)
{
char *line = tor_strdup(orig_line);
@@ -2835,7 +2835,7 @@ measured_bw_line_parse(measured_bw_line_t *out, const char *orig_line)
* of bandwidth statuses. Returns true if a line is found,
* false otherwise.
*/
-int
+STATIC int
measured_bw_line_apply(measured_bw_line_t *parsed_line,
smartlist_t *routerstatuses)
{
@@ -3093,7 +3093,8 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
else
last_consensus_interval = options->TestingV3AuthInitialVotingInterval;
v3_out->valid_after =
- dirvote_get_start_of_next_interval(now, (int)last_consensus_interval);
+ dirvote_get_start_of_next_interval(now, (int)last_consensus_interval,
+ options->TestingV3AuthVotingStartOffset);
format_iso_time(tbuf, v3_out->valid_after);
log_notice(LD_DIR,"Choosing valid-after time in vote as %s: "
"consensus_set=%d, last_interval=%d",
@@ -3167,7 +3168,7 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
/** For v2 authoritative directories only: Replace the contents of
* <b>the_v2_networkstatus</b> with a newly generated network status
* object. */
-cached_dir_t *
+STATIC cached_dir_t *
generate_v2_networkstatus_opinion(void)
{
cached_dir_t *r = NULL;
diff --git a/src/or/dirserv.h b/src/or/dirserv.h
index f9d36d760..7221fc995 100644
--- a/src/or/dirserv.h
+++ b/src/or/dirserv.h
@@ -12,6 +12,8 @@
#ifndef TOR_DIRSERV_H
#define TOR_DIRSERV_H
+#include "testsupport.h"
+
/** What fraction (1 over this number) of the relay ID space do we
* (as a directory authority) launch connections to at each reachability
* test? */
@@ -119,20 +121,21 @@ cached_dir_t *new_cached_dir(char *s, time_t published);
/* Put the MAX_MEASUREMENT_AGE #define here so unit tests can see it */
#define MAX_MEASUREMENT_AGE (3*24*60*60) /* 3 days */
-int measured_bw_line_parse(measured_bw_line_t *out, const char *line);
+STATIC int measured_bw_line_parse(measured_bw_line_t *out, const char *line);
-int measured_bw_line_apply(measured_bw_line_t *parsed_line,
+STATIC int measured_bw_line_apply(measured_bw_line_t *parsed_line,
smartlist_t *routerstatuses);
-void dirserv_cache_measured_bw(const measured_bw_line_t *parsed_line,
+STATIC void dirserv_cache_measured_bw(const measured_bw_line_t *parsed_line,
time_t as_of);
-void dirserv_clear_measured_bw_cache(void);
-void dirserv_expire_measured_bw_cache(time_t now);
-int dirserv_get_measured_bw_cache_size(void);
-int dirserv_query_measured_bw_cache_kb(const char *node_id, long *bw_out,
- time_t *as_of_out);
-int dirserv_has_measured_bw(const char *node_id);
-cached_dir_t *generate_v2_networkstatus_opinion(void);
+STATIC void dirserv_clear_measured_bw_cache(void);
+STATIC void dirserv_expire_measured_bw_cache(time_t now);
+STATIC int dirserv_get_measured_bw_cache_size(void);
+STATIC int dirserv_query_measured_bw_cache_kb(const char *node_id,
+ long *bw_out,
+ time_t *as_of_out);
+STATIC int dirserv_has_measured_bw(const char *node_id);
+STATIC cached_dir_t *generate_v2_networkstatus_opinion(void);
#endif
int dirserv_read_measured_bandwidths(const char *from_file,
diff --git a/src/or/dirvote.c b/src/or/dirvote.c
index e0af66e22..12ceba854 100644
--- a/src/or/dirvote.c
+++ b/src/or/dirvote.c
@@ -60,7 +60,7 @@ static char *make_consensus_method_list(int low, int high, const char *sep);
/** Return a new string containing the string representation of the vote in
* <b>v3_ns</b>, signed with our v3 signing key <b>private_signing_key</b>.
* For v3 authorities. */
-char *
+STATIC char *
format_networkstatus_vote(crypto_pk_t *private_signing_key,
networkstatus_t *v3_ns)
{
@@ -587,7 +587,7 @@ compute_consensus_versions_list(smartlist_t *lst, int n_versioning)
/** Helper: given a list of valid networkstatus_t, return a new string
* containing the contents of the consensus network parameter set.
*/
-/* private */ char *
+STATIC char *
dirvote_compute_params(smartlist_t *votes, int method, int total_authorities)
{
int i;
@@ -2533,12 +2533,13 @@ dirvote_get_preferred_voting_intervals(vote_timing_t *timing_out)
timing_out->dist_delay = options->V3AuthDistDelay;
}
-/** Return the start of the next interval of size <b>interval</b> (in seconds)
- * after <b>now</b>. Midnight always starts a fresh interval, and if the last
- * interval of a day would be truncated to less than half its size, it is
- * rolled into the previous interval. */
+/** Return the start of the next interval of size <b>interval</b> (in
+ * seconds) after <b>now</b>, plus <b>offset</b>. Midnight always
+ * starts a fresh interval, and if the last interval of a day would be
+ * truncated to less than half its size, it is rolled into the
+ * previous interval. */
time_t
-dirvote_get_start_of_next_interval(time_t now, int interval)
+dirvote_get_start_of_next_interval(time_t now, int interval, int offset)
{
struct tm tm;
time_t midnight_today=0;
@@ -2566,6 +2567,10 @@ dirvote_get_start_of_next_interval(time_t now, int interval)
if (next + interval/2 > midnight_tomorrow)
next = midnight_tomorrow;
+ next += offset;
+ if (next - interval > now)
+ next -= interval;
+
return next;
}
@@ -2629,8 +2634,10 @@ dirvote_recalculate_timing(const or_options_t *options, time_t now)
vote_delay = dist_delay = interval / 4;
start = voting_schedule.interval_starts =
- dirvote_get_start_of_next_interval(now,interval);
- end = dirvote_get_start_of_next_interval(start+1, interval);
+ dirvote_get_start_of_next_interval(now,interval,
+ options->TestingV3AuthVotingStartOffset);
+ end = dirvote_get_start_of_next_interval(start+1, interval,
+ options->TestingV3AuthVotingStartOffset);
tor_assert(end > start);
diff --git a/src/or/dirvote.h b/src/or/dirvote.h
index b23645212..3a4951a95 100644
--- a/src/or/dirvote.h
+++ b/src/or/dirvote.h
@@ -12,10 +12,12 @@
#ifndef TOR_DIRVOTE_H
#define TOR_DIRVOTE_H
+#include "testsupport.h"
+
/** Lowest allowable value for VoteSeconds. */
-#define MIN_VOTE_SECONDS 20
+#define MIN_VOTE_SECONDS 2
/** Lowest allowable value for DistSeconds. */
-#define MIN_DIST_SECONDS 20
+#define MIN_DIST_SECONDS 2
/** Smallest allowable voting interval. */
#define MIN_VOTE_INTERVAL 300
@@ -86,7 +88,9 @@ authority_cert_t *authority_cert_dup(authority_cert_t *cert);
/* vote scheduling */
void dirvote_get_preferred_voting_intervals(vote_timing_t *timing_out);
-time_t dirvote_get_start_of_next_interval(time_t now, int interval);
+time_t dirvote_get_start_of_next_interval(time_t now,
+ int interval,
+ int offset);
void dirvote_recalculate_timing(const or_options_t *options, time_t now);
void dirvote_act(const or_options_t *options, time_t now);
@@ -134,9 +138,9 @@ document_signature_t *voter_get_sig_by_algorithm(
digest_algorithm_t alg);
#ifdef DIRVOTE_PRIVATE
-char *format_networkstatus_vote(crypto_pk_t *private_key,
+STATIC char *format_networkstatus_vote(crypto_pk_t *private_key,
networkstatus_t *v3_ns);
-char *dirvote_compute_params(smartlist_t *votes, int method,
+STATIC char *dirvote_compute_params(smartlist_t *votes, int method,
int total_authorities);
#endif
diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c
index 7a1f67d16..70f7c878e 100644
--- a/src/or/entrynodes.c
+++ b/src/or/entrynodes.c
@@ -54,6 +54,10 @@ typedef struct {
/** When should we next try to fetch a descriptor for this bridge? */
download_status_t fetch_status;
+
+ /** A smartlist of k=v values to be passed to the SOCKS proxy, if
+ transports are used for this bridge. */
+ smartlist_t *socks_args;
} bridge_info_t;
/** A list of our chosen entry guards. */
@@ -1574,6 +1578,11 @@ bridge_free(bridge_info_t *bridge)
return;
tor_free(bridge->transport_name);
+ if (bridge->socks_args) {
+ SMARTLIST_FOREACH(bridge->socks_args, char*, s, tor_free(s));
+ smartlist_free(bridge->socks_args);
+ }
+
tor_free(bridge);
}
@@ -1752,30 +1761,51 @@ bridge_resolve_conflicts(const tor_addr_t *addr, uint16_t port,
} SMARTLIST_FOREACH_END(bridge);
}
-/** Remember a new bridge at <b>addr</b>:<b>port</b>. If <b>digest</b>
- * is set, it tells us the identity key too. If we already had the
- * bridge in our list, unmark it, and don't actually add anything new.
- * If <b>transport_name</b> is non-NULL - the bridge is associated with a
- * pluggable transport - we assign the transport to the bridge. */
+/** Register the bridge information in <b>bridge_line</b> to the
+ * bridge subsystem. Steals reference of <b>bridge_line</b>. */
void
-bridge_add_from_config(const tor_addr_t *addr, uint16_t port,
- const char *digest, const char *transport_name)
+bridge_add_from_config(bridge_line_t *bridge_line)
{
bridge_info_t *b;
- bridge_resolve_conflicts(addr, port, digest, transport_name);
+ { /* Log the bridge we are about to register: */
+ log_debug(LD_GENERAL, "Registering bridge at %s (transport: %s) (%s)",
+ fmt_addrport(&bridge_line->addr, bridge_line->port),
+ bridge_line->transport_name ?
+ bridge_line->transport_name : "no transport",
+ tor_digest_is_zero(bridge_line->digest) ?
+ "no key listed" : hex_str(bridge_line->digest, DIGEST_LEN));
+
+ if (bridge_line->socks_args) { /* print socks arguments */
+ int i = 0;
+
+ tor_assert(smartlist_len(bridge_line->socks_args) > 0);
+
+ log_debug(LD_GENERAL, "Bridge uses %d SOCKS arguments:",
+ smartlist_len(bridge_line->socks_args));
+ SMARTLIST_FOREACH(bridge_line->socks_args, const char *, arg,
+ log_debug(LD_CONFIG, "%d: %s", ++i, arg));
+ }
+ }
+
+ bridge_resolve_conflicts(&bridge_line->addr,
+ bridge_line->port,
+ bridge_line->digest,
+ bridge_line->transport_name);
b = tor_malloc_zero(sizeof(bridge_info_t));
- tor_addr_copy(&b->addr, addr);
- b->port = port;
- if (digest)
- memcpy(b->identity, digest, DIGEST_LEN);
- if (transport_name)
- b->transport_name = tor_strdup(transport_name);
+ tor_addr_copy(&b->addr, &bridge_line->addr);
+ b->port = bridge_line->port;
+ memcpy(b->identity, bridge_line->digest, DIGEST_LEN);
+ if (bridge_line->transport_name)
+ b->transport_name = bridge_line->transport_name;
b->fetch_status.schedule = DL_SCHED_BRIDGE;
+ b->socks_args = bridge_line->socks_args;
if (!bridge_list)
bridge_list = smartlist_new();
+ tor_free(bridge_line); /* Deallocate bridge_line now. */
+
smartlist_add(bridge_list, b);
}
@@ -1836,7 +1866,7 @@ find_transport_name_by_bridge_addrport(const tor_addr_t *addr, uint16_t port)
* transport, but the transport could not be found.
*/
int
-find_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port,
+get_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port,
const transport_t **transport)
{
*transport = NULL;
@@ -1863,6 +1893,17 @@ find_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port,
return 0;
}
+/** Return a smartlist containing all the SOCKS arguments that we
+ * should pass to the SOCKS proxy. */
+const smartlist_t *
+get_socks_args_by_bridge_addrport(const tor_addr_t *addr, uint16_t port)
+{
+ bridge_info_t *bridge = get_configured_bridge_by_addr_port_digest(addr,
+ port,
+ NULL);
+ return bridge ? bridge->socks_args : NULL;
+}
+
/** We need to ask <b>bridge</b> for its server descriptor. */
static void
launch_direct_bridge_descriptor_fetch(bridge_info_t *bridge)
diff --git a/src/or/entrynodes.h b/src/or/entrynodes.h
index 52b8dc00e..533f2027a 100644
--- a/src/or/entrynodes.h
+++ b/src/or/entrynodes.h
@@ -97,9 +97,8 @@ int routerinfo_is_a_configured_bridge(const routerinfo_t *ri);
int node_is_a_configured_bridge(const node_t *node);
void learned_router_identity(const tor_addr_t *addr, uint16_t port,
const char *digest);
-void bridge_add_from_config(const tor_addr_t *addr, uint16_t port,
- const char *digest,
- const char *transport_name);
+struct bridge_line_t;
+void bridge_add_from_config(struct bridge_line_t *bridge_line);
void retry_bridge_descriptor_fetch_directly(const char *digest);
void fetch_bridge_descriptors(const or_options_t *options, time_t now);
void learned_bridge_descriptor(routerinfo_t *ri, int from_cache);
@@ -109,13 +108,17 @@ int entries_known_but_down(const or_options_t *options);
void entries_retry_all(const or_options_t *options);
int any_bridge_supports_microdescriptors(void);
+const smartlist_t *get_socks_args_by_bridge_addrport(const tor_addr_t *addr,
+ uint16_t port);
+
+int any_bridges_dont_support_microdescriptors(void);
void entry_guards_free_all(void);
const char *find_transport_name_by_bridge_addrport(const tor_addr_t *addr,
uint16_t port);
struct transport_t;
-int find_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port,
+int get_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port,
const struct transport_t **transport);
int validate_pluggable_transports_config(void);
diff --git a/src/or/geoip.c b/src/or/geoip.c
index e2e98e8ec..020075f80 100644
--- a/src/or/geoip.c
+++ b/src/or/geoip.c
@@ -120,7 +120,7 @@ geoip_add_entry(const tor_addr_t *low, const tor_addr_t *high,
/** Add an entry to the GeoIP table indicated by <b>family</b>,
* parsing it from <b>line</b>. The format is as for geoip_load_file(). */
-/*private*/ int
+STATIC int
geoip_parse_entry(const char *line, sa_family_t family)
{
tor_addr_t low_addr, high_addr;
@@ -363,7 +363,7 @@ geoip_load_file(sa_family_t family, const char *filename)
* be less than geoip_get_n_countries(). To decode it, call
* geoip_get_country_name().
*/
-int
+STATIC int
geoip_get_country_by_ipv4(uint32_t ipaddr)
{
geoip_ipv4_entry_t *ent;
@@ -379,7 +379,7 @@ geoip_get_country_by_ipv4(uint32_t ipaddr)
* 0 for the 'unknown country'. The return value will always be less than
* geoip_get_n_countries(). To decode it, call geoip_get_country_name().
*/
-int
+STATIC int
geoip_get_country_by_ipv6(const struct in6_addr *addr)
{
geoip_ipv6_entry_t *ent;
@@ -1132,7 +1132,7 @@ geoip_format_dirreq_stats(time_t now)
time_t
geoip_dirreq_stats_write(time_t now)
{
- char *statsdir = NULL, *filename = NULL, *str = NULL;
+ char *str = NULL;
if (!start_of_dirreq_stats_interval)
return 0; /* Not initialized. */
@@ -1146,21 +1146,13 @@ geoip_dirreq_stats_write(time_t now)
str = geoip_format_dirreq_stats(now);
/* Write dirreq-stats string to disk. */
- statsdir = get_datadir_fname("stats");
- if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0) {
- log_warn(LD_HIST, "Unable to create stats/ directory!");
- goto done;
+ if (!check_or_create_data_subdir("stats")) {
+ write_to_data_subdir("stats", "dirreq-stats", str, "dirreq statistics");
+ /* Reset measurement interval start. */
+ geoip_reset_dirreq_stats(now);
}
- filename = get_datadir_fname2("stats", "dirreq-stats");
- if (write_str_to_file(filename, str, 0) < 0)
- log_warn(LD_HIST, "Unable to write dirreq statistics to disk!");
-
- /* Reset measurement interval start. */
- geoip_reset_dirreq_stats(now);
done:
- tor_free(statsdir);
- tor_free(filename);
tor_free(str);
return start_of_dirreq_stats_interval + WRITE_STATS_INTERVAL;
}
@@ -1297,7 +1289,7 @@ format_bridge_stats_controller(time_t now)
time_t
geoip_bridge_stats_write(time_t now)
{
- char *filename = NULL, *val = NULL, *statsdir = NULL;
+ char *val = NULL;
/* Check if 24 hours have passed since starting measurements. */
if (now < start_of_bridge_stats_interval + WRITE_STATS_INTERVAL)
@@ -1317,24 +1309,20 @@ geoip_bridge_stats_write(time_t now)
start_of_bridge_stats_interval = now;
/* Write it to disk. */
- statsdir = get_datadir_fname("stats");
- if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0)
- goto done;
- filename = get_datadir_fname2("stats", "bridge-stats");
-
- write_str_to_file(filename, bridge_stats_extrainfo, 0);
-
- /* Tell the controller, "hey, there are clients!" */
- {
- char *controller_str = format_bridge_stats_controller(now);
- if (controller_str)
- control_event_clients_seen(controller_str);
- tor_free(controller_str);
+ if (!check_or_create_data_subdir("stats")) {
+ write_to_data_subdir("stats", "bridge-stats",
+ bridge_stats_extrainfo, "bridge statistics");
+
+ /* Tell the controller, "hey, there are clients!" */
+ {
+ char *controller_str = format_bridge_stats_controller(now);
+ if (controller_str)
+ control_event_clients_seen(controller_str);
+ tor_free(controller_str);
+ }
}
- done:
- tor_free(filename);
- tor_free(statsdir);
+ done:
return start_of_bridge_stats_interval + WRITE_STATS_INTERVAL;
}
@@ -1436,7 +1424,7 @@ geoip_format_entry_stats(time_t now)
time_t
geoip_entry_stats_write(time_t now)
{
- char *statsdir = NULL, *filename = NULL, *str = NULL;
+ char *str = NULL;
if (!start_of_entry_stats_interval)
return 0; /* Not initialized. */
@@ -1450,21 +1438,14 @@ geoip_entry_stats_write(time_t now)
str = geoip_format_entry_stats(now);
/* Write entry-stats string to disk. */
- statsdir = get_datadir_fname("stats");
- if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0) {
- log_warn(LD_HIST, "Unable to create stats/ directory!");
- goto done;
- }
- filename = get_datadir_fname2("stats", "entry-stats");
- if (write_str_to_file(filename, str, 0) < 0)
- log_warn(LD_HIST, "Unable to write entry statistics to disk!");
+ if (!check_or_create_data_subdir("stats")) {
+ write_to_data_subdir("stats", "entry-stats", str, "entry statistics");
- /* Reset measurement interval start. */
- geoip_reset_entry_stats(now);
+ /* Reset measurement interval start. */
+ geoip_reset_entry_stats(now);
+ }
done:
- tor_free(statsdir);
- tor_free(filename);
tor_free(str);
return start_of_entry_stats_interval + WRITE_STATS_INTERVAL;
}
diff --git a/src/or/geoip.h b/src/or/geoip.h
index ebefee5f4..d67007298 100644
--- a/src/or/geoip.h
+++ b/src/or/geoip.h
@@ -12,10 +12,12 @@
#ifndef TOR_GEOIP_H
#define TOR_GEOIP_H
+#include "testsupport.h"
+
#ifdef GEOIP_PRIVATE
-int geoip_parse_entry(const char *line, sa_family_t family);
-int geoip_get_country_by_ipv4(uint32_t ipaddr);
-int geoip_get_country_by_ipv6(const struct in6_addr *addr);
+STATIC int geoip_parse_entry(const char *line, sa_family_t family);
+STATIC int geoip_get_country_by_ipv4(uint32_t ipaddr);
+STATIC int geoip_get_country_by_ipv6(const struct in6_addr *addr);
#endif
int should_record_bridge_info(const or_options_t *options);
int geoip_load_file(sa_family_t family, const char *filename);
diff --git a/src/or/hibernate.c b/src/or/hibernate.c
index a41257133..22c0f253d 100644
--- a/src/or/hibernate.c
+++ b/src/or/hibernate.c
@@ -1010,6 +1010,7 @@ getinfo_helper_accounting(control_connection_t *conn,
return 0;
}
+#ifdef TOR_UNIT_TESTS
/**
* Manually change the hibernation state. Private; used only by the unit
* tests.
@@ -1019,4 +1020,5 @@ hibernate_set_state_for_testing_(hibernate_state_t newstate)
{
hibernate_state = newstate;
}
+#endif
diff --git a/src/or/hibernate.h b/src/or/hibernate.h
index d2d6989e1..18832fbc6 100644
--- a/src/or/hibernate.h
+++ b/src/or/hibernate.h
@@ -45,8 +45,10 @@ typedef enum {
HIBERNATE_STATE_INITIAL=5
} hibernate_state_t;
+#ifdef TOR_UNIT_TESTS
void hibernate_set_state_for_testing_(hibernate_state_t newstate);
#endif
+#endif
#endif
diff --git a/src/or/include.am b/src/or/include.am
index 65dbeff53..f5002e698 100644
--- a/src/or/include.am
+++ b/src/or/include.am
@@ -1,5 +1,13 @@
bin_PROGRAMS+= src/or/tor
-noinst_LIBRARIES+= src/or/libtor.a
+noinst_LIBRARIES += \
+ src/or/libtor.a
+if UNITTESTS_ENABLED
+noinst_LIBRARIES += \
+ src/or/libtor-testing.a
+endif
+if COVERAGE_ENABLED
+noinst_PROGRAMS+= src/or/tor-cov
+endif
if BUILD_NT_SERVICES
tor_platform_source=src/or/ntmain.c
@@ -21,7 +29,7 @@ else
onion_ntor_source=
endif
-src_or_libtor_a_SOURCES = \
+LIBTOR_A_SOURCES = \
src/or/addressmap.c \
src/or/buffers.c \
src/or/channel.c \
@@ -77,6 +85,9 @@ src_or_libtor_a_SOURCES = \
$(onion_ntor_source) \
src/or/config_codedigest.c
+src_or_libtor_a_SOURCES = $(LIBTOR_A_SOURCES)
+src_or_libtor_testing_a_SOURCES = $(LIBTOR_A_SOURCES)
+
#libtor_a_LIBADD = ../common/libor.a ../common/libor-crypto.a \
# ../common/libor-event.a
@@ -90,6 +101,9 @@ AM_CPPFLAGS += -DSHARE_DATADIR="\"$(datadir)\"" \
-DLOCALSTATEDIR="\"$(localstatedir)\"" \
-DBINDIR="\"$(bindir)\""
+src_or_libtor_testing_a_CPPFLAGS = -DTOR_UNIT_TESTS $(AM_CPPFLAGS)
+src_or_libtor_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+
# -L flags need to go in LDFLAGS. -l flags need to go in LDADD.
# This seems to matter nowhere but on windows, but I assure you that it
# matters a lot there, and is quite hard to debug if you forget to do it.
@@ -102,6 +116,18 @@ src_or_tor_LDADD = src/or/libtor.a src/common/libor.a \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \
@TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
+if COVERAGE_ENABLED
+src_or_tor_cov_SOURCES = src/or/tor_main.c
+src_or_tor_cov_CPPFLAGS = -DTOR_UNIT_TESTS $(AM_CPPFLAGS)
+src_or_tor_cov_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+src_or_tor_cov_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ @TOR_LDFLAGS_libevent@
+src_or_tor_cov_LDADD = src/or/libtor-testing.a src/common/libor-testing.a \
+ src/common/libor-crypto-testing.a $(LIBDONNA) \
+ src/common/libor-event-testing.a \
+ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \
+ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
+endif
+
ORHEADERS = \
src/or/addressmap.h \
src/or/buffers.h \
diff --git a/src/or/main.c b/src/or/main.c
index bd23141b9..d1728250a 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -10,7 +10,6 @@
* connections, implements main loop, and drives scheduled events.
**/
-#define MAIN_PRIVATE
#include "or.h"
#include "addressmap.h"
#include "buffers.h"
@@ -57,6 +56,7 @@
#include <openssl/crypto.h>
#endif
#include "memarea.h"
+#include "../common/sandbox.h"
#ifdef HAVE_EVENT2_EVENT_H
#include <event2/event.h>
@@ -155,8 +155,6 @@ int can_complete_circuit=0;
/** How often do we 'forgive' undownloadable router descriptors and attempt
* to download them again? */
#define DESCRIPTOR_FAILURE_RESET_INTERVAL (60*60)
-/** How long do we let a directory connection stall before expiring it? */
-#define DIR_CONN_MAX_STALL (5*60)
/** Decides our behavior when no logs are configured/before any
* logs have been configured. For 0, we log notice to stdout as normal.
@@ -1028,9 +1026,11 @@ run_connection_housekeeping(int i, time_t now)
* if a server or received if a client) for 5 min */
if (conn->type == CONN_TYPE_DIR &&
((DIR_CONN_IS_SERVER(conn) &&
- conn->timestamp_lastwritten + DIR_CONN_MAX_STALL < now) ||
+ conn->timestamp_lastwritten
+ + options->TestingDirConnectionMaxStall < now) ||
(!DIR_CONN_IS_SERVER(conn) &&
- conn->timestamp_lastread + DIR_CONN_MAX_STALL < now))) {
+ conn->timestamp_lastread
+ + options->TestingDirConnectionMaxStall < now))) {
log_info(LD_DIR,"Expiring wedged directory conn (fd %d, purpose %d)",
(int)conn->s, conn->purpose);
/* This check is temporary; it's to let us know whether we should consider
@@ -1153,6 +1153,7 @@ run_scheduled_events(time_t now)
static time_t time_to_check_v3_certificate = 0;
static time_t time_to_check_listeners = 0;
static time_t time_to_check_descriptor = 0;
+ static time_t time_to_download_networkstatus = 0;
static time_t time_to_shrink_memory = 0;
static time_t time_to_try_getting_descriptors = 0;
static time_t time_to_reset_descriptor_failures = 0;
@@ -1442,10 +1443,18 @@ run_scheduled_events(time_t now)
networkstatus_v2_list_clean(now);
/* Remove dead routers. */
routerlist_remove_old_routers();
+ }
- /* Also, once per minute, check whether we want to download any
- * networkstatus documents.
- */
+ /* 2c. Every minute (or every second if TestingTorNetwork), check
+ * whether we want to download any networkstatus documents. */
+
+/* How often do we check whether we should download network status
+ * documents? */
+#define networkstatus_dl_check_interval(o) ((o)->TestingTorNetwork ? 1 : 60)
+
+ if (time_to_download_networkstatus < now && !options->DisableNetwork) {
+ time_to_download_networkstatus =
+ now + networkstatus_dl_check_interval(options);
update_networkstatus_downloads(now);
}
@@ -1865,7 +1874,7 @@ do_hup(void)
}
/** Tor main loop. */
-/* static */ int
+int
do_main_loop(void)
{
int loop_result;
@@ -2292,7 +2301,7 @@ handle_signals(int is_parent)
/** Main entry point for the Tor command-line client.
*/
-/* static */ int
+int
tor_init(int argc, char *argv[])
{
char buf[256];
@@ -2558,7 +2567,7 @@ tor_cleanup(void)
}
/** Read/create keys as needed, and echo our fingerprint to stdout. */
-/* static */ int
+static int
do_list_fingerprint(void)
{
char buf[FINGERPRINT_LEN+1];
@@ -2588,7 +2597,7 @@ do_list_fingerprint(void)
/** Entry point for password hashing: take the desired password from
* the command line, and print its salted hash to stdout. **/
-/* static */ void
+static void
do_hash_password(void)
{
@@ -2695,6 +2704,14 @@ tor_main(int argc, char *argv[])
#endif
if (tor_init(argc, argv)<0)
return -1;
+
+ if (get_options()->Sandbox) {
+ if (tor_global_sandbox()) {
+ log_err(LD_BUG,"Failed to create syscall sandbox filter");
+ return -1;
+ }
+ }
+
switch (get_options()->command) {
case CMD_RUN_TOR:
#ifdef NT_SERVICE
diff --git a/src/or/main.h b/src/or/main.h
index 338449b6a..85621a32b 100644
--- a/src/or/main.h
+++ b/src/or/main.h
@@ -66,12 +66,8 @@ void tor_free_all(int postfork);
int tor_main(int argc, char *argv[]);
-#ifdef MAIN_PRIVATE
int do_main_loop(void);
-int do_list_fingerprint(void);
-void do_hash_password(void);
int tor_init(int argc, char **argv);
-#endif
#endif
diff --git a/src/or/microdesc.c b/src/or/microdesc.c
index b93bd83af..8c763c672 100644
--- a/src/or/microdesc.c
+++ b/src/or/microdesc.c
@@ -139,7 +139,7 @@ get_microdesc_cache(void)
* ending at <b>eos</b>, and store them in <b>cache</b>. If <b>no_save</b>,
* mark them as non-writable to disk. If <b>where</b> is SAVED_IN_CACHE,
* leave their bodies as pointers to the mmap'd cache. If where is
- * <b>SAVED_NOWHERE</b>, do not allow annotations. If listed_at is positive,
+ * <b>SAVED_NOWHERE</b>, do not allow annotations. If listed_at is not -1,
* set the last_listed field of every microdesc to listed_at. If
* requested_digests is non-null, then it contains a list of digests we mean
* to allow, so we should reject any non-requested microdesc with a different
@@ -159,7 +159,7 @@ microdescs_add_to_cache(microdesc_cache_t *cache,
descriptors = microdescs_parse_from_string(s, eos,
allow_annotations,
copy_body);
- if (listed_at > 0) {
+ if (listed_at != (time_t)-1) {
SMARTLIST_FOREACH(descriptors, microdesc_t *, md,
md->last_listed = listed_at);
}
@@ -687,7 +687,7 @@ microdesc_list_missing_digest256(networkstatus_t *ns, microdesc_cache_t *cache,
continue;
if (downloadable_only &&
!download_status_is_ready(&rs->dl_status, now,
- MAX_MICRODESC_DOWNLOAD_FAILURES))
+ get_options()->TestingMicrodescMaxDownloadTries))
continue;
if (skip && digestmap_get(skip, rs->descriptor_digest))
continue;
diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c
index 871584154..3f995a9f6 100644
--- a/src/or/networkstatus.c
+++ b/src/or/networkstatus.c
@@ -1203,8 +1203,6 @@ we_want_to_fetch_flavor(const or_options_t *options, int flavor)
return flavor == usable_consensus_flavor();
}
-/** How many times will we try to fetch a consensus before we give up? */
-#define CONSENSUS_NETWORKSTATUS_MAX_DL_TRIES 8
/** How long will we hang onto a possibly live consensus for which we're
* fetching certs before we check whether there is a better one? */
#define DELAY_WHILE_FETCHING_CERTS (20*60)
@@ -1238,7 +1236,7 @@ update_consensus_networkstatus_downloads(time_t now)
resource = networkstatus_get_flavor_name(i);
if (!download_status_is_ready(&consensus_dl_status[i], now,
- CONSENSUS_NETWORKSTATUS_MAX_DL_TRIES))
+ options->TestingConsensusMaxDownloadTries))
continue; /* We failed downloading a consensus too recently. */
if (connection_dir_get_by_purpose_and_resource(
DIR_PURPOSE_FETCH_CONSENSUS, resource))
diff --git a/src/or/ntmain.c b/src/or/ntmain.c
index 8b67b8682..2fa074d0b 100644
--- a/src/or/ntmain.c
+++ b/src/or/ntmain.c
@@ -3,7 +3,6 @@
* Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-#define MAIN_PRIVATE
#include "or.h"
#include "config.h"
#include "main.h"
diff --git a/src/or/or.h b/src/or/or.h
index 0b8d057aa..568958d61 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -238,7 +238,9 @@ typedef enum {
#define PROXY_SOCKS5 3
/* !!!! If there is ever a PROXY_* type over 2, we must grow the proxy_type
* field in or_connection_t */
-/* pluggable transports proxy type */
+
+/* Pluggable transport proxy type. Don't use this in or_connection_t,
+ * instead use the actual underlying proxy type (see above). */
#define PROXY_PLUGGABLE 4
/* Proxy client handshake states */
@@ -823,9 +825,15 @@ typedef enum {
/** Maximum number of queued cells on a circuit for which we are the
* midpoint before we give up and kill it. This must be >= circwindow
* to avoid killing innocent circuits, and >= circwindow*2 to give
- * leaky-pipe a chance for being useful someday.
+ * leaky-pipe a chance of working someday. The ORCIRC_MAX_MIDDLE_KILL_THRESH
+ * ratio controls the margin of error between emitting a warning and
+ * killing the circuit.
+ */
+#define ORCIRC_MAX_MIDDLE_CELLS (CIRCWINDOW_START_MAX*2)
+/** Ratio of hard (circuit kill) to soft (warning) thresholds for the
+ * ORCIRC_MAX_MIDDLE_CELLS tests.
*/
-#define ORCIRC_MAX_MIDDLE_CELLS (21*(CIRCWINDOW_START_MAX)/10)
+#define ORCIRC_MAX_MIDDLE_KILL_THRESH (1.1f)
/* Cell commands. These values are defined in tor-spec.txt. */
#define CELL_PADDING 0
@@ -2286,14 +2294,6 @@ typedef struct node_t {
} node_t;
-/** How many times will we try to download a router's descriptor before giving
- * up? */
-#define MAX_ROUTERDESC_DOWNLOAD_FAILURES 8
-
-/** How many times will we try to download a microdescriptor before giving
- * up? */
-#define MAX_MICRODESC_DOWNLOAD_FAILURES 8
-
/** Contents of a v2 (non-consensus, non-vote) network status object. */
typedef struct networkstatus_v2_t {
/** When did we receive the network-status document? */
@@ -2503,10 +2503,6 @@ typedef struct desc_store_t {
* filename for a temporary file when rebuilding the store, and .new to this
* filename for the journal. */
const char *fname_base;
- /** Alternative (obsolete) value for fname_base: if the file named by
- * fname_base isn't present, we read from here instead, but we never write
- * here. */
- const char *fname_alt_base;
/** Human-readable description of what this store contains. */
const char *description;
@@ -2796,6 +2792,13 @@ typedef struct circuit_t {
* allowing n_streams to add any more cells. (OR circuit only.) */
unsigned int streams_blocked_on_p_chan : 1;
+ /** True iff we have queued a delete backwards on this circuit, but not put
+ * it on the output buffer. */
+ unsigned int p_delete_pending : 1;
+ /** True iff we have queued a delete forwards on this circuit, but not put
+ * it on the output buffer. */
+ unsigned int n_delete_pending : 1;
+
uint8_t state; /**< Current status of this circuit. */
uint8_t purpose; /**< Why are we creating this circuit? */
@@ -3176,6 +3179,12 @@ typedef struct or_circuit_t {
* exit-ward queues of this circuit; reset every time when writing
* buffer stats to disk. */
uint64_t total_cell_waiting_time;
+
+ /** Maximum cell queue size for a middle relay; this is stored per circuit
+ * so append_cell_to_circuit_queue() can adjust it if it changes. If set
+ * to zero, it is initialized to the default value.
+ */
+ uint32_t max_middle_cells;
} or_circuit_t;
/** Convert a circuit subtype to a circuit_t. */
@@ -3750,6 +3759,7 @@ typedef struct {
SAFELOG_SCRUB_ALL, SAFELOG_SCRUB_RELAY, SAFELOG_SCRUB_NONE
} SafeLogging_;
+ int Sandbox; /**< Boolean: should sandboxing be enabled? */
int SafeSocks; /**< Boolean: should we outright refuse application
* connections that use socks4 or socks5-with-local-dns? */
#define LOG_PROTOCOL_WARN (get_options()->ProtocolWarnings ? \
@@ -3920,6 +3930,10 @@ typedef struct {
* signatures. Only altered on testing networks.*/
int TestingV3AuthInitialDistDelay;
+ /** Offset in seconds added to the starting time for consensus
+ voting. Only altered on testing networks. */
+ int TestingV3AuthVotingStartOffset;
+
/** If an authority has been around for less than this amount of time, it
* does not believe its reachability information is accurate. Only
* altered on testing networks. */
@@ -3930,6 +3944,51 @@ typedef struct {
* networks. */
int TestingEstimatedDescriptorPropagationTime;
+ /** Schedule for when servers should download things in general. Only
+ * altered on testing networks. */
+ smartlist_t *TestingServerDownloadSchedule;
+
+ /** Schedule for when clients should download things in general. Only
+ * altered on testing networks. */
+ smartlist_t *TestingClientDownloadSchedule;
+
+ /** Schedule for when servers should download consensuses. Only altered
+ * on testing networks. */
+ smartlist_t *TestingServerConsensusDownloadSchedule;
+
+ /** Schedule for when clients should download consensuses. Only altered
+ * on testing networks. */
+ smartlist_t *TestingClientConsensusDownloadSchedule;
+
+ /** Schedule for when clients should download bridge descriptors. Only
+ * altered on testing networks. */
+ smartlist_t *TestingBridgeDownloadSchedule;
+
+ /** When directory clients have only a few descriptors to request, they
+ * batch them until they have more, or until this amount of time has
+ * passed. Only altered on testing networks. */
+ int TestingClientMaxIntervalWithoutRequest;
+
+ /** How long do we let a directory connection stall before expiring
+ * it? Only altered on testing networks. */
+ int TestingDirConnectionMaxStall;
+
+ /** How many times will we try to fetch a consensus before we give
+ * up? Only altered on testing networks. */
+ int TestingConsensusMaxDownloadTries;
+
+ /** How many times will we try to download a router's descriptor before
+ * giving up? Only altered on testing networks. */
+ int TestingDescriptorMaxDownloadTries;
+
+ /** How many times will we try to download a microdescriptor before
+ * giving up? Only altered on testing networks. */
+ int TestingMicrodescMaxDownloadTries;
+
+ /** How many times will we try to fetch a certificate before giving
+ * up? Only altered on testing networks. */
+ int TestingCertMaxDownloadTries;
+
/** If true, we take part in a testing network. Change the defaults of a
* couple of other configuration options and allow to change the values
* of certain configuration options. */
diff --git a/src/or/relay.c b/src/or/relay.c
index 3138c5e8d..7ec7e0302 100644
--- a/src/or/relay.c
+++ b/src/or/relay.c
@@ -58,6 +58,9 @@ static void adjust_exit_policy_from_exitpolicy_failure(origin_circuit_t *circ,
entry_connection_t *conn,
node_t *node,
const tor_addr_t *addr);
+#if 0
+static int get_max_middle_cells(void);
+#endif
/** Stop reading on edge connections when we have this many cells
* waiting on the appropriate queue. */
@@ -966,7 +969,7 @@ remap_event_helper(entry_connection_t *conn, const tor_addr_t *new_addr)
* <b>addr_out</b> to the address we're connected to, and <b>ttl_out</b> to
* the ttl of that address, in seconds, and return 0. On failure, return
* -1. */
-int
+STATIC int
connected_cell_parse(const relay_header_t *rh, const cell_t *cell,
tor_addr_t *addr_out, int *ttl_out)
{
@@ -1494,7 +1497,8 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
if (layer_hint) {
if (layer_hint->package_window + CIRCWINDOW_INCREMENT >
CIRCWINDOW_START_MAX) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ static struct ratelim_t exit_warn_ratelim = RATELIM_INIT(600);
+ log_fn_ratelim(&exit_warn_ratelim, LOG_WARN, LD_PROTOCOL,
"Unexpected sendme cell from exit relay. "
"Closing circ.");
return -END_CIRC_REASON_TORPROTOCOL;
@@ -1506,7 +1510,8 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
} else {
if (circ->package_window + CIRCWINDOW_INCREMENT >
CIRCWINDOW_START_MAX) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ static struct ratelim_t client_warn_ratelim = RATELIM_INIT(600);
+ log_fn_ratelim(&client_warn_ratelim, LOG_WARN, LD_PROTOCOL,
"Unexpected sendme cell from client. "
"Closing circ (window %d).",
circ->package_window);
@@ -2146,11 +2151,11 @@ cell_queue_append(cell_queue_t *queue, packed_cell_t *cell)
/** Append a newly allocated copy of <b>cell</b> to the end of <b>queue</b> */
void
cell_queue_append_packed_copy(cell_queue_t *queue, const cell_t *cell,
- int wide_circ_ids)
+ int wide_circ_ids, int use_stats)
{
packed_cell_t *copy = packed_cell_copy(cell, wide_circ_ids);
/* Remember the time when this cell was put in the queue. */
- if (get_options()->CellStatistics) {
+ if (get_options()->CellStatistics && use_stats) {
struct timeval now;
uint32_t added;
insertion_time_queue_t *it_queue = queue->insertion_times;
@@ -2368,7 +2373,7 @@ channel_flush_from_first_active_circuit(channel_t *chan, int max)
{
circuitmux_t *cmux = NULL;
int n_flushed = 0;
- cell_queue_t *queue;
+ cell_queue_t *queue, *destroy_queue=NULL;
circuit_t *circ;
or_circuit_t *or_circ;
int streams_blocked;
@@ -2381,7 +2386,18 @@ channel_flush_from_first_active_circuit(channel_t *chan, int max)
/* Main loop: pick a circuit, send a cell, update the cmux */
while (n_flushed < max) {
- circ = circuitmux_get_first_active_circuit(cmux);
+ circ = circuitmux_get_first_active_circuit(cmux, &destroy_queue);
+ if (destroy_queue) {
+ /* this code is duplicated from some of the logic below. Ugly! XXXX */
+ tor_assert(destroy_queue->n > 0);
+ cell = cell_queue_pop(destroy_queue);
+ channel_write_packed_cell(chan, cell);
+ /* Update the cmux destroy counter */
+ circuitmux_notify_xmit_destroy(cmux);
+ cell = NULL;
+ ++n_flushed;
+ continue;
+ }
/* If it returns NULL, no cells left to send */
if (!circ) break;
assert_cmux_ok_paranoid(chan);
@@ -2482,6 +2498,20 @@ channel_flush_from_first_active_circuit(channel_t *chan, int max)
return n_flushed;
}
+#if 0
+/** Indicate the current preferred cap for middle circuits; zero disables
+ * the cap. Right now it's just a constant, ORCIRC_MAX_MIDDLE_CELLS, but
+ * the logic in append_cell_to_circuit_queue() is written to be correct
+ * if we want to base it on a consensus param or something that might change
+ * in the future.
+ */
+static int
+get_max_middle_cells(void)
+{
+ return ORCIRC_MAX_MIDDLE_CELLS;
+}
+#endif
+
/** Add <b>cell</b> to the queue of <b>circ</b> writing to <b>chan</b>
* transmitting in <b>direction</b>. */
void
@@ -2492,6 +2522,9 @@ append_cell_to_circuit_queue(circuit_t *circ, channel_t *chan,
or_circuit_t *orcirc = NULL;
cell_queue_t *queue;
int streams_blocked;
+#if 0
+ uint32_t tgt_max_middle_cells, p_len, n_len, tmp, hard_max_middle_cells;
+#endif
if (circ->marked_for_close)
return;
@@ -2513,28 +2546,81 @@ append_cell_to_circuit_queue(circuit_t *circ, channel_t *chan,
if ((circ->n_chan != NULL) && CIRCUIT_IS_ORCIRC(circ)) {
orcirc = TO_OR_CIRCUIT(circ);
if (orcirc->p_chan) {
- if (queue->n + 1 >= ORCIRC_MAX_MIDDLE_CELLS) {
- /* Queueing this cell would put queue over the cap */
- log_warn(LD_CIRC,
- "Got a cell exceeding the cap of %u in the %s direction "
- "on middle circ ID %u on chan ID " U64_FORMAT
- "; killing the circuit.",
- ORCIRC_MAX_MIDDLE_CELLS,
- (direction == CELL_DIRECTION_OUT) ? "n" : "p",
- (direction == CELL_DIRECTION_OUT) ?
- circ->n_circ_id : orcirc->p_circ_id,
- U64_PRINTF_ARG(
+ /* We are a middle circuit if we have both n_chan and p_chan */
+ /* We'll need to know the current preferred maximum */
+ tgt_max_middle_cells = get_max_middle_cells();
+ if (tgt_max_middle_cells > 0) {
+ /* Do we need to initialize middle_max_cells? */
+ if (orcirc->max_middle_cells == 0) {
+ orcirc->max_middle_cells = tgt_max_middle_cells;
+ } else {
+ if (tgt_max_middle_cells > orcirc->max_middle_cells) {
+ /* If we want to increase the cap, we can do so right away */
+ orcirc->max_middle_cells = tgt_max_middle_cells;
+ } else if (tgt_max_middle_cells < orcirc->max_middle_cells) {
+ /*
+ * If we're shrinking the cap, we can't shrink past either queue;
+ * compare tgt_max_middle_cells rather than tgt_max_middle_cells *
+ * ORCIRC_MAX_MIDDLE_KILL_THRESH so the queues don't shrink enough
+ * to generate spurious warnings, either.
+ */
+ n_len = circ->n_chan_cells.n;
+ p_len = orcirc->p_chan_cells.n;
+ tmp = tgt_max_middle_cells;
+ if (tmp < n_len) tmp = n_len;
+ if (tmp < p_len) tmp = p_len;
+ orcirc->max_middle_cells = tmp;
+ }
+ /* else no change */
+ }
+ } else {
+ /* tgt_max_middle_cells == 0 indicates we should disable the cap */
+ orcirc->max_middle_cells = 0;
+ }
+
+ /* Now we know orcirc->max_middle_cells is set correctly */
+ if (orcirc->max_middle_cells > 0) {
+ hard_max_middle_cells =
+ (uint32_t)(((double)orcirc->max_middle_cells) *
+ ORCIRC_MAX_MIDDLE_KILL_THRESH);
+
+ if ((unsigned)queue->n + 1 >= hard_max_middle_cells) {
+ /* Queueing this cell would put queue over the kill theshold */
+ log_warn(LD_CIRC,
+ "Got a cell exceeding the hard cap of %u in the "
+ "%s direction on middle circ ID %u on chan ID "
+ U64_FORMAT "; killing the circuit.",
+ hard_max_middle_cells,
+ (direction == CELL_DIRECTION_OUT) ? "n" : "p",
(direction == CELL_DIRECTION_OUT) ?
- circ->n_chan->global_identifier :
- orcirc->p_chan->global_identifier));
- circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT);
- return;
+ circ->n_circ_id : orcirc->p_circ_id,
+ U64_PRINTF_ARG(
+ (direction == CELL_DIRECTION_OUT) ?
+ circ->n_chan->global_identifier :
+ orcirc->p_chan->global_identifier));
+ circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT);
+ return;
+ } else if ((unsigned)queue->n + 1 == orcirc->max_middle_cells) {
+ /* Only use ==, not >= for this test so we don't spam the log */
+ log_warn(LD_CIRC,
+ "While trying to queue a cell, reached the soft cap of %u "
+ "in the %s direction on middle circ ID %u "
+ "on chan ID " U64_FORMAT ".",
+ orcirc->max_middle_cells,
+ (direction == CELL_DIRECTION_OUT) ? "n" : "p",
+ (direction == CELL_DIRECTION_OUT) ?
+ circ->n_circ_id : orcirc->p_circ_id,
+ U64_PRINTF_ARG(
+ (direction == CELL_DIRECTION_OUT) ?
+ circ->n_chan->global_identifier :
+ orcirc->p_chan->global_identifier));
+ }
}
}
}
#endif
- cell_queue_append_packed_copy(queue, cell, chan->wide_circ_ids);
+ cell_queue_append_packed_copy(queue, cell, chan->wide_circ_ids, 1);
if (PREDICT_UNLIKELY(cell_queues_check_size())) {
/* We ran the OOM handler */
diff --git a/src/or/relay.h b/src/or/relay.h
index 1fef10a7d..4be3194e5 100644
--- a/src/or/relay.h
+++ b/src/or/relay.h
@@ -54,7 +54,7 @@ void packed_cell_free(packed_cell_t *cell);
void cell_queue_clear(cell_queue_t *queue);
void cell_queue_append(cell_queue_t *queue, packed_cell_t *cell);
void cell_queue_append_packed_copy(cell_queue_t *queue, const cell_t *cell,
- int wide_circ_ids);
+ int wide_circ_ids, int use_stats);
void append_cell_to_circuit_queue(circuit_t *circ, channel_t *chan,
cell_t *cell, cell_direction_t direction,
@@ -75,10 +75,11 @@ void circuit_clear_cell_queue(circuit_t *circ, channel_t *chan);
void stream_choice_seed_weak_rng(void);
-#ifdef RELAY_PRIVATE
int relay_crypt(circuit_t *circ, cell_t *cell, cell_direction_t cell_direction,
crypt_path_t **layer_hint, char *recognized);
-int connected_cell_parse(const relay_header_t *rh, const cell_t *cell,
+
+#ifdef RELAY_PRIVATE
+STATIC int connected_cell_parse(const relay_header_t *rh, const cell_t *cell,
tor_addr_t *addr_out, int *ttl_out);
#endif
diff --git a/src/or/rephist.c b/src/or/rephist.c
index 55f321d5f..c84322a67 100644
--- a/src/or/rephist.c
+++ b/src/or/rephist.c
@@ -2313,7 +2313,7 @@ rep_hist_format_exit_stats(time_t now)
time_t
rep_hist_exit_stats_write(time_t now)
{
- char *statsdir = NULL, *filename = NULL, *str = NULL;
+ char *str = NULL;
if (!start_of_exit_stats_interval)
return 0; /* Not initialized. */
@@ -2329,19 +2329,12 @@ rep_hist_exit_stats_write(time_t now)
rep_hist_reset_exit_stats(now);
/* Try to write to disk. */
- statsdir = get_datadir_fname("stats");
- if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0) {
- log_warn(LD_HIST, "Unable to create stats/ directory!");
- goto done;
+ if (!check_or_create_data_subdir("stats")) {
+ write_to_data_subdir("stats", "exit-stats", str, "exit port statistics");
}
- filename = get_datadir_fname2("stats", "exit-stats");
- if (write_str_to_file(filename, str, 0) < 0)
- log_warn(LD_HIST, "Unable to write exit port statistics to disk!");
done:
tor_free(str);
- tor_free(statsdir);
- tor_free(filename);
return start_of_exit_stats_interval + WRITE_STATS_INTERVAL;
}
@@ -2598,7 +2591,7 @@ time_t
rep_hist_buffer_stats_write(time_t now)
{
circuit_t *circ;
- char *statsdir = NULL, *filename = NULL, *str = NULL;
+ char *str = NULL;
if (!start_of_buffer_stats_interval)
return 0; /* Not initialized. */
@@ -2617,19 +2610,12 @@ rep_hist_buffer_stats_write(time_t now)
rep_hist_reset_buffer_stats(now);
/* Try to write to disk. */
- statsdir = get_datadir_fname("stats");
- if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0) {
- log_warn(LD_HIST, "Unable to create stats/ directory!");
- goto done;
+ if (!check_or_create_data_subdir("stats")) {
+ write_to_data_subdir("stats", "buffer-stats", str, "buffer statistics");
}
- filename = get_datadir_fname2("stats", "buffer-stats");
- if (write_str_to_file(filename, str, 0) < 0)
- log_warn(LD_HIST, "Unable to write buffer stats to disk!");
done:
tor_free(str);
- tor_free(filename);
- tor_free(statsdir);
return start_of_buffer_stats_interval + WRITE_STATS_INTERVAL;
}
@@ -2741,7 +2727,7 @@ rep_hist_format_desc_stats(time_t now)
time_t
rep_hist_desc_stats_write(time_t now)
{
- char *statsdir = NULL, *filename = NULL, *str = NULL;
+ char *filename = NULL, *str = NULL;
if (!start_of_served_descs_stats_interval)
return 0; /* We're not collecting stats. */
@@ -2751,10 +2737,8 @@ rep_hist_desc_stats_write(time_t now)
str = rep_hist_format_desc_stats(now);
tor_assert(str != NULL);
- statsdir = get_datadir_fname("stats");
- if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0) {
- log_warn(LD_HIST, "Unable to create stats/ directory!");
- goto done;
+ if (check_or_create_data_subdir("stats") < 0) {
+ goto done;
}
filename = get_datadir_fname2("stats", "served-desc-stats");
if (append_bytes_to_file(filename, str, strlen(str), 0) < 0)
@@ -2763,7 +2747,6 @@ rep_hist_desc_stats_write(time_t now)
rep_hist_reset_desc_stats(now);
done:
- tor_free(statsdir);
tor_free(filename);
tor_free(str);
return start_of_served_descs_stats_interval + WRITE_STATS_INTERVAL;
@@ -2981,7 +2964,7 @@ rep_hist_format_conn_stats(time_t now)
time_t
rep_hist_conn_stats_write(time_t now)
{
- char *statsdir = NULL, *filename = NULL, *str = NULL;
+ char *str = NULL;
if (!start_of_conn_stats_interval)
return 0; /* Not initialized. */
@@ -2995,19 +2978,12 @@ rep_hist_conn_stats_write(time_t now)
rep_hist_reset_conn_stats(now);
/* Try to write to disk. */
- statsdir = get_datadir_fname("stats");
- if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0) {
- log_warn(LD_HIST, "Unable to create stats/ directory!");
- goto done;
+ if (!check_or_create_data_subdir("stats")) {
+ write_to_data_subdir("stats", "conn-stats", str, "connection statistics");
}
- filename = get_datadir_fname2("stats", "conn-stats");
- if (write_str_to_file(filename, str, 0) < 0)
- log_warn(LD_HIST, "Unable to write conn stats to disk!");
done:
tor_free(str);
- tor_free(filename);
- tor_free(statsdir);
return start_of_conn_stats_interval + WRITE_STATS_INTERVAL;
}
diff --git a/src/or/replaycache.c b/src/or/replaycache.c
index 59b98489b..122efb703 100644
--- a/src/or/replaycache.c
+++ b/src/or/replaycache.c
@@ -63,7 +63,7 @@ replaycache_new(time_t horizon, time_t interval)
/** See documentation for replaycache_add_and_test()
*/
-int
+STATIC int
replaycache_add_and_test_internal(
time_t present, replaycache_t *r, const void *data, int len,
time_t *elapsed)
@@ -127,14 +127,13 @@ replaycache_add_and_test_internal(
/** See documentation for replaycache_scrub_if_needed()
*/
-void
+STATIC void
replaycache_scrub_if_needed_internal(time_t present, replaycache_t *r)
{
digestmap_iter_t *itr = NULL;
const char *digest;
void *valp;
time_t *access_time;
- char scrub_this;
/* sanity check */
if (!r || !(r->digests_seen)) {
@@ -152,20 +151,10 @@ replaycache_scrub_if_needed_internal(time_t present, replaycache_t *r)
/* okay, scrub time */
itr = digestmap_iter_init(r->digests_seen);
while (!digestmap_iter_done(itr)) {
- scrub_this = 0;
digestmap_iter_get(itr, &digest, &valp);
access_time = (time_t *)valp;
- if (access_time) {
- /* aged out yet? */
- if (*access_time < present - r->horizon) scrub_this = 1;
- } else {
- /* Buh? Get rid of it, anyway */
- log_info(LD_BUG, "replaycache_scrub_if_needed_internal() saw a NULL"
- " entry in the digestmap.");
- scrub_this = 1;
- }
-
- if (scrub_this) {
+ /* aged out yet? */
+ if (*access_time < present - r->horizon) {
/* Advance the iterator and remove this one */
itr = digestmap_iter_next_rmv(r->digests_seen, itr);
/* Free the value removed */
diff --git a/src/or/replaycache.h b/src/or/replaycache.h
index de20cab62..c60c40810 100644
--- a/src/or/replaycache.h
+++ b/src/or/replaycache.h
@@ -45,10 +45,10 @@ replaycache_t * replaycache_new(time_t horizon, time_t interval);
* testing. For everything else, use the wrappers below instead.
*/
-int replaycache_add_and_test_internal(
+STATIC int replaycache_add_and_test_internal(
time_t present, replaycache_t *r, const void *data, int len,
time_t *elapsed);
-void replaycache_scrub_if_needed_internal(
+STATIC void replaycache_scrub_if_needed_internal(
time_t present, replaycache_t *r);
#endif /* REPLAYCACHE_PRIVATE */
diff --git a/src/or/router.c b/src/or/router.c
index 6069da8f0..1063eda04 100644
--- a/src/or/router.c
+++ b/src/or/router.c
@@ -2249,7 +2249,7 @@ router_guess_address_from_dir_headers(uint32_t *guess)
* string describing the version of Tor and the operating system we're
* currently running on.
*/
-void
+STATIC void
get_platform_str(char *platform, size_t len)
{
tor_snprintf(platform, len, "Tor %s on %s",
diff --git a/src/or/router.h b/src/or/router.h
index 60095d087..1079ec78c 100644
--- a/src/or/router.h
+++ b/src/or/router.h
@@ -12,6 +12,8 @@
#ifndef TOR_ROUTER_H
#define TOR_ROUTER_H
+#include "testsupport.h"
+
crypto_pk_t *get_onion_key(void);
time_t get_onion_key_set_at(void);
void set_server_identity_key(crypto_pk_t *k);
@@ -146,7 +148,7 @@ smartlist_t *router_get_all_orports(const routerinfo_t *ri);
#ifdef ROUTER_PRIVATE
/* Used only by router.c and test.c */
-void get_platform_str(char *platform, size_t len);
+STATIC void get_platform_str(char *platform, size_t len);
#endif
#endif
diff --git a/src/or/routerlist.c b/src/or/routerlist.c
index c2220f4ca..46da17e03 100644
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@ -629,9 +629,6 @@ authority_cert_dl_looks_uncertain(const char *id_digest)
return n_failures >= N_AUTH_CERT_DL_FAILURES_TO_BUG_USER;
}
-/** How many times will we try to fetch a certificate before giving up? */
-#define MAX_CERT_DL_FAILURES 8
-
/** Try to download any v3 authority certificates that we may be missing. If
* <b>status</b> is provided, try to get all the ones that were used to sign
* <b>status</b>. Additionally, try to have a non-expired certificate for
@@ -703,7 +700,7 @@ authority_certs_fetch_missing(networkstatus_t *status, time_t now)
} SMARTLIST_FOREACH_END(cert);
if (!found &&
download_status_is_ready(&(cl->dl_status_by_id), now,
- MAX_CERT_DL_FAILURES) &&
+ get_options()->TestingCertMaxDownloadTries) &&
!digestmap_get(pending_id, ds->v3_identity_digest)) {
log_info(LD_DIR,
"No current certificate known for authority %s "
@@ -765,7 +762,7 @@ authority_certs_fetch_missing(networkstatus_t *status, time_t now)
}
if (download_status_is_ready_by_sk_in_cl(
cl, sig->signing_key_digest,
- now, MAX_CERT_DL_FAILURES) &&
+ now, get_options()->TestingCertMaxDownloadTries) &&
!fp_pair_map_get_by_digests(pending_cert,
voter->identity_digest,
sig->signing_key_digest)) {
@@ -1126,32 +1123,18 @@ router_rebuild_store(int flags, desc_store_t *store)
static int
router_reload_router_list_impl(desc_store_t *store)
{
- char *fname = NULL, *altname = NULL, *contents = NULL;
+ char *fname = NULL, *contents = NULL;
struct stat st;
- int read_from_old_location = 0;
int extrainfo = (store->type == EXTRAINFO_STORE);
- time_t now = time(NULL);
store->journal_len = store->store_len = 0;
fname = get_datadir_fname(store->fname_base);
- if (store->fname_alt_base)
- altname = get_datadir_fname(store->fname_alt_base);
if (store->mmap) /* get rid of it first */
tor_munmap_file(store->mmap);
store->mmap = NULL;
store->mmap = tor_mmap_file(fname);
- if (!store->mmap && altname && file_status(altname) == FN_FILE) {
- read_from_old_location = 1;
- log_notice(LD_DIR, "Couldn't read %s; trying to load routers from old "
- "location %s.", fname, altname);
- if ((store->mmap = tor_mmap_file(altname)))
- read_from_old_location = 1;
- }
- if (altname && !read_from_old_location) {
- remove_file_if_very_old(altname, now);
- }
if (store->mmap) {
store->store_len = store->mmap->size;
if (extrainfo)
@@ -1168,14 +1151,6 @@ router_reload_router_list_impl(desc_store_t *store)
fname = get_datadir_fname_suffix(store->fname_base, ".new");
if (file_status(fname) == FN_FILE)
contents = read_file_to_str(fname, RFTS_BIN|RFTS_IGNORE_MISSING, &st);
- if (read_from_old_location) {
- tor_free(altname);
- altname = get_datadir_fname_suffix(store->fname_alt_base, ".new");
- if (!contents)
- contents = read_file_to_str(altname, RFTS_BIN|RFTS_IGNORE_MISSING, &st);
- else
- remove_file_if_very_old(altname, now);
- }
if (contents) {
if (extrainfo)
router_load_extrainfo_from_string(contents, NULL,SAVED_IN_JOURNAL,
@@ -1188,9 +1163,8 @@ router_reload_router_list_impl(desc_store_t *store)
}
tor_free(fname);
- tor_free(altname);
- if (store->journal_len || read_from_old_location) {
+ if (store->journal_len) {
/* Always clear the journal on startup.*/
router_rebuild_store(RRS_FORCE, store);
} else if (!extrainfo) {
@@ -1827,7 +1801,7 @@ router_get_advertised_bandwidth_capped(const routerinfo_t *router)
* doubles, convert them to uint64_t, and try to scale them linearly so as to
* much of the range of uint64_t. If <b>total_out</b> is provided, set it to
* the sum of all elements in the array _before_ scaling. */
-/* private */ void
+STATIC void
scale_array_elements_to_u64(u64_dbl_t *entries, int n_entries,
uint64_t *total_out)
{
@@ -1870,7 +1844,7 @@ gt_i64_timei(uint64_t a, uint64_t b)
* value, and return the index of that element. If all elements are 0, choose
* an index at random. Return -1 on error.
*/
-/* private */ int
+STATIC int
choose_array_element_by_weight(const u64_dbl_t *entries, int n_entries)
{
int i, i_chosen=-1, n_chosen=0;
@@ -2570,19 +2544,6 @@ router_is_named(const routerinfo_t *router)
tor_memeq(digest, router->cache_info.identity_digest, DIGEST_LEN));
}
-/** Return true iff the digest of <b>router</b>'s identity key,
- * encoded in hexadecimal, matches <b>hexdigest</b> (which is
- * optionally prefixed with a single dollar sign). Return false if
- * <b>hexdigest</b> is malformed, or it doesn't match. */
-static INLINE int
-router_hex_digest_matches(const routerinfo_t *router, const char *hexdigest)
-{
- return hex_digest_nickname_matches(hexdigest,
- router->cache_info.identity_digest,
- router->nickname,
- router_is_named(router));
-}
-
/** Return true iff <b>digest</b> is the digest of the identity key of a
* trusted directory matching at least one bit of <b>type</b>. If <b>type</b>
* is zero, any authority is okay. */
@@ -2777,7 +2738,6 @@ router_get_routerlist(void)
routerlist->extra_info_map = eimap_new();
routerlist->desc_store.fname_base = "cached-descriptors";
- routerlist->desc_store.fname_alt_base = "cached-routers";
routerlist->extrainfo_store.fname_base = "cached-extrainfo";
routerlist->desc_store.type = ROUTER_STORE;
@@ -4487,12 +4447,8 @@ initiate_descriptor_downloads(const routerstatus_t *source,
* try to split our requests into at least this many requests. */
#define MIN_REQUESTS 3
/** If we want fewer than this many descriptors, wait until we
- * want more, or until MAX_CLIENT_INTERVAL_WITHOUT_REQUEST has
- * passed. */
+ * want more, or until TestingClientMaxIntervalWithoutRequest has passed. */
#define MAX_DL_TO_DELAY 16
-/** When directory clients have only a few servers to request, they batch
- * them until they have more, or until this amount of time has passed. */
-#define MAX_CLIENT_INTERVAL_WITHOUT_REQUEST (10*60)
/** Given a <b>purpose</b> (FETCH_MICRODESC or FETCH_SERVERDESC) and a list of
* router descriptor digests or microdescriptor digest256s in
@@ -4524,7 +4480,7 @@ launch_descriptor_downloads(int purpose,
should_delay = 0;
} else {
should_delay = (last_descriptor_download_attempted +
- MAX_CLIENT_INTERVAL_WITHOUT_REQUEST) > now;
+ options->TestingClientMaxIntervalWithoutRequest) > now;
if (!should_delay && n_downloadable) {
if (last_descriptor_download_attempted) {
log_info(LD_DIR,
@@ -4797,7 +4753,7 @@ update_consensus_router_descriptor_downloads(time_t now, int is_vote,
continue; /* We have an in-progress download. */
}
if (!download_status_is_ready(&rs->dl_status, now,
- MAX_ROUTERDESC_DOWNLOAD_FAILURES)) {
+ options->TestingDescriptorMaxDownloadTries)) {
++n_delayed; /* Not ready for retry. */
continue;
}
@@ -4957,7 +4913,7 @@ update_extrainfo_downloads(time_t now)
continue;
}
if (!download_status_is_ready(&sd->ei_dl_status, now,
- MAX_ROUTERDESC_DOWNLOAD_FAILURES)) {
+ options->TestingDescriptorMaxDownloadTries)) {
++n_delay;
continue;
}
diff --git a/src/or/routerlist.h b/src/or/routerlist.h
index ce0f0f2e3..0162297ca 100644
--- a/src/or/routerlist.h
+++ b/src/or/routerlist.h
@@ -11,6 +11,8 @@
#ifndef TOR_ROUTERLIST_H
#define TOR_ROUTERLIST_H
+#include "testsupport.h"
+
int get_n_authorities(dirinfo_type_t type);
int trusted_dirs_reload_certs(void);
@@ -206,9 +208,10 @@ typedef union u64_dbl_t {
double dbl;
} u64_dbl_t;
-int choose_array_element_by_weight(const u64_dbl_t *entries, int n_entries);
-void scale_array_elements_to_u64(u64_dbl_t *entries, int n_entries,
- uint64_t *total_out);
+STATIC int choose_array_element_by_weight(const u64_dbl_t *entries,
+ int n_entries);
+STATIC void scale_array_elements_to_u64(u64_dbl_t *entries, int n_entries,
+ uint64_t *total_out);
#endif
#endif
diff --git a/src/or/transports.c b/src/or/transports.c
index b5a00c90e..cfec70340 100644
--- a/src/or/transports.c
+++ b/src/or/transports.c
@@ -95,6 +95,7 @@
#include "util.h"
#include "router.h"
#include "statefile.h"
+#include "entrynodes.h"
static process_environment_t *
create_managed_proxy_environment(const managed_proxy_t *mp);
@@ -775,7 +776,7 @@ handle_methods_done(const managed_proxy_t *mp)
/** Handle a configuration protocol <b>line</b> received from a
* managed proxy <b>mp</b>. */
-void
+STATIC void
handle_proxy_line(const char *line, managed_proxy_t *mp)
{
log_info(LD_GENERAL, "Got a line from managed proxy '%s': (%s)",
@@ -876,7 +877,7 @@ handle_proxy_line(const char *line, managed_proxy_t *mp)
}
/** Parses an ENV-ERROR <b>line</b> and warns the user accordingly. */
-void
+STATIC void
parse_env_error(const char *line)
{
/* (Length of the protocol string) plus (a space) and (the first char of
@@ -892,7 +893,7 @@ parse_env_error(const char *line)
/** Handles a VERSION <b>line</b>. Updates the configuration protocol
* version in <b>mp</b>. */
-int
+STATIC int
parse_version(const char *line, managed_proxy_t *mp)
{
if (strlen(line) < (strlen(PROTO_NEG_SUCCESS) + 2)) {
@@ -933,7 +934,7 @@ parse_method_error(const char *line, int is_server)
/** Parses an SMETHOD <b>line</b> and if well-formed it registers the
* new transport in <b>mp</b>. */
-int
+STATIC int
parse_smethod_line(const char *line, managed_proxy_t *mp)
{
int r;
@@ -1010,7 +1011,7 @@ parse_smethod_line(const char *line, managed_proxy_t *mp)
/** Parses a CMETHOD <b>line</b>, and if well-formed it registers
* the new transport in <b>mp</b>. */
-int
+STATIC int
parse_cmethod_line(const char *line, managed_proxy_t *mp)
{
int r;
@@ -1420,6 +1421,57 @@ pt_get_extra_info_descriptor_string(void)
return the_string;
}
+/** Stringify the SOCKS arguments in <b>socks_args</b> according to
+ * 180_pluggable_transport.txt. The string is allocated on the heap
+ * and it's the responsibility of the caller to free it after use. */
+char *
+pt_stringify_socks_args(const smartlist_t *socks_args)
+{
+ /* tmp place to store escaped socks arguments, so that we can
+ concatenate them up afterwards */
+ smartlist_t *sl_tmp = NULL;
+ char *escaped_string = NULL;
+ char *new_string = NULL;
+
+ tor_assert(socks_args);
+ tor_assert(smartlist_len(socks_args) > 0);
+
+ sl_tmp = smartlist_new();
+
+ SMARTLIST_FOREACH_BEGIN(socks_args, const char *, s) {
+ /* Escape ';' and '\'. */
+ escaped_string = tor_escape_str_for_socks_arg(s);
+ if (!escaped_string)
+ goto done;
+
+ smartlist_add(sl_tmp, escaped_string);
+ } SMARTLIST_FOREACH_END(s);
+
+ new_string = smartlist_join_strings(sl_tmp, ";", 0, NULL);
+
+ done:
+ SMARTLIST_FOREACH(sl_tmp, char *, s, tor_free(s));
+ smartlist_free(sl_tmp);
+
+ return new_string;
+}
+
+/** Return a string of the SOCKS arguments that we should pass to the
+ * pluggable transports proxy in <b>addr</b>:<b>port</b> according to
+ * 180_pluggable_transport.txt. The string is allocated on the heap
+ * and it's the responsibility of the caller to free it after use. */
+char *
+pt_get_socks_args_for_proxy_addrport(const tor_addr_t *addr, uint16_t port)
+{
+ const smartlist_t *socks_args = NULL;
+
+ socks_args = get_socks_args_by_bridge_addrport(addr, port);
+ if (!socks_args)
+ return NULL;
+
+ return pt_stringify_socks_args(socks_args);
+}
+
/** The tor config was read.
* Destroy all managed proxies that were marked by a previous call to
* prepare_proxy_list_for_config_read() and are not used by the new
diff --git a/src/or/transports.h b/src/or/transports.h
index 6ee82f455..cc3e018d6 100644
--- a/src/or/transports.h
+++ b/src/or/transports.h
@@ -55,6 +55,10 @@ void pt_prepare_proxy_list_for_config_read(void);
void sweep_proxy_list(void);
smartlist_t *get_transport_proxy_ports(void);
+char *pt_stringify_socks_args(const smartlist_t *socks_args);
+
+char *pt_get_socks_args_for_proxy_addrport(const tor_addr_t *addr,
+ uint16_t port);
#ifdef PT_PRIVATE
/** State of the managed proxy configuration protocol. */
@@ -100,12 +104,12 @@ typedef struct {
smartlist_t *transports;
} managed_proxy_t;
-int parse_cmethod_line(const char *line, managed_proxy_t *mp);
-int parse_smethod_line(const char *line, managed_proxy_t *mp);
+STATIC int parse_cmethod_line(const char *line, managed_proxy_t *mp);
+STATIC int parse_smethod_line(const char *line, managed_proxy_t *mp);
-int parse_version(const char *line, managed_proxy_t *mp);
-void parse_env_error(const char *line);
-void handle_proxy_line(const char *line, managed_proxy_t *mp);
+STATIC int parse_version(const char *line, managed_proxy_t *mp);
+STATIC void parse_env_error(const char *line);
+STATIC void handle_proxy_line(const char *line, managed_proxy_t *mp);
#endif
diff --git a/src/test/bench.c b/src/test/bench.c
index 5a8d21d17..ca01d3c3e 100644
--- a/src/test/bench.c
+++ b/src/test/bench.c
@@ -15,7 +15,6 @@ const char tor_git_revision[] = "";
#include "orconfig.h"
#define RELAY_PRIVATE
-#define CONFIG_PRIVATE
#include "or.h"
#include "onion_tap.h"
@@ -204,6 +203,7 @@ bench_onion_ntor(void)
for (i = 0; i < iters; ++i) {
onion_skin_ntor_create(nodeid, &keypair1.pubkey, &state, os);
ntor_handshake_state_free(state);
+ state = NULL;
}
end = perftime();
printf("Client-side, part 1: %f usec.\n", NANOCOUNT(start, end, iters)/1e3);
diff --git a/src/test/include.am b/src/test/include.am
index 112d1a79d..279369e74 100644
--- a/src/test/include.am
+++ b/src/test/include.am
@@ -1,11 +1,15 @@
TESTS+= src/test/test
-noinst_PROGRAMS+= src/test/test src/test/test-child src/test/bench
+noinst_PROGRAMS+= src/test/bench
+if UNITTESTS_ENABLED
+noinst_PROGRAMS+= src/test/test src/test/test-child
+endif
src_test_AM_CPPFLAGS = -DSHARE_DATADIR="\"$(datadir)\"" \
-DLOCALSTATEDIR="\"$(localstatedir)\"" \
-DBINDIR="\"$(bindir)\"" \
- -I"$(top_srcdir)/src/or" -I"$(top_srcdir)/src/ext"
+ -I"$(top_srcdir)/src/or" -I"$(top_srcdir)/src/ext" \
+ -DTOR_UNIT_TESTS
# -L flags need to go in LDFLAGS. -l flags need to go in LDADD.
# This seems to matter nowhere but on Windows, but I assure you that it
@@ -15,6 +19,7 @@ src_test_test_SOURCES = \
src/test/test.c \
src/test/test_addr.c \
src/test/test_cell_formats.c \
+ src/test/test_circuitlist.c \
src/test/test_containers.c \
src/test/test_crypto.c \
src/test/test_data.c \
@@ -27,6 +32,8 @@ src_test_test_SOURCES = \
src/test/test_config.c \
src/ext/tinytest.c
+src_test_test_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+
src_test_test_CPPFLAGS= $(src_test_AM_CPPFLAGS)
src_test_bench_SOURCES = \
@@ -36,9 +43,9 @@ src_test_bench_CPPFLAGS= $(src_test_AM_CPPFLAGS)
src_test_test_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \
@TOR_LDFLAGS_libevent@
-src_test_test_LDADD = src/or/libtor.a src/common/libor.a \
- src/common/libor-crypto.a $(LIBDONNA) \
- src/common/libor-event.a \
+src_test_test_LDADD = src/or/libtor-testing.a src/common/libor-testing.a \
+ src/common/libor-crypto-testing.a $(LIBDONNA) \
+ src/common/libor-event-testing.a \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
diff --git a/src/test/test-network.sh b/src/test/test-network.sh
new file mode 100755
index 000000000..9146ae3ce
--- /dev/null
+++ b/src/test/test-network.sh
@@ -0,0 +1,25 @@
+#! /bin/sh
+
+# NOTE: Requires Chutney in $CHUTNEY_PATH.
+
+TOR_DIR=$(pwd)/src/or
+NETWORK_FLAVOUR=basic
+CHUTNEY_NETWORK=networks/$NETWORK_FLAVOUR
+myname=$(basename $0)
+
+[ -d "$CHUTNEY_PATH" ] && [ -x "$CHUTNEY_PATH/chutney" ] || {
+ echo "$myname: missing 'chutney' in CHUTNEY_PATH ($CHUTNEY_PATH)"
+ exit 1
+}
+cd "$CHUTNEY_PATH"
+PATH=$TOR_DIR:$PATH # For picking up the right tor binary.
+./tools/bootstrap-network.sh $NETWORK_FLAVOUR || exit 2
+
+# Sleep some, waiting for the network to bootstrap.
+# TODO: Add chutney command 'bootstrap-status' and use that instead.
+BOOTSTRAP_TIME=18
+echo -n "$myname: sleeping for $BOOTSTRAP_TIME seconds"
+n=$BOOTSTRAP_TIME; while [ $n -gt 0 ]; do
+ sleep 1; n=$(expr $n - 1); echo -n .
+done; echo ""
+./chutney verify $CHUTNEY_NETWORK
diff --git a/src/test/test.c b/src/test/test.c
index 3ff39e629..d7d4c6c06 100644
--- a/src/test/test.c
+++ b/src/test/test.c
@@ -29,7 +29,6 @@ const char tor_git_revision[] = "";
/* These macros pull in declarations for some functions and structures that
* are typically file-private. */
#define BUFFERS_PRIVATE
-#define CONFIG_PRIVATE
#define GEOIP_PRIVATE
#define ROUTER_PRIVATE
#define CIRCUITSTATS_PRIVATE
@@ -840,43 +839,130 @@ test_onion_handshake(void)
crypto_dh_t *c_dh = NULL;
char c_buf[TAP_ONIONSKIN_CHALLENGE_LEN];
char c_keys[40];
-
/* server-side */
char s_buf[TAP_ONIONSKIN_REPLY_LEN];
char s_keys[40];
-
+ int i;
/* shared */
- crypto_pk_t *pk = NULL;
+ crypto_pk_t *pk = NULL, *pk2 = NULL;
pk = pk_generate(0);
+ pk2 = pk_generate(1);
/* client handshake 1. */
memset(c_buf, 0, TAP_ONIONSKIN_CHALLENGE_LEN);
test_assert(! onion_skin_TAP_create(pk, &c_dh, c_buf));
- /* server handshake */
- memset(s_buf, 0, TAP_ONIONSKIN_REPLY_LEN);
- memset(s_keys, 0, 40);
- test_assert(! onion_skin_TAP_server_handshake(c_buf, pk, NULL,
- s_buf, s_keys, 40));
+ for (i = 1; i <= 3; ++i) {
+ crypto_pk_t *k1, *k2;
+ if (i==1) {
+ /* server handshake: only one key known. */
+ k1 = pk; k2 = NULL;
+ } else if (i==2) {
+ /* server handshake: try the right key first. */
+ k1 = pk; k2 = pk2;
+ } else {
+ /* server handshake: try the right key second. */
+ k1 = pk2; k2 = pk;
+ }
- /* client handshake 2 */
- memset(c_keys, 0, 40);
- test_assert(! onion_skin_TAP_client_handshake(c_dh, s_buf, c_keys, 40));
+ memset(s_buf, 0, TAP_ONIONSKIN_REPLY_LEN);
+ memset(s_keys, 0, 40);
+ test_assert(! onion_skin_TAP_server_handshake(c_buf, k1, k2,
+ s_buf, s_keys, 40));
- if (memcmp(c_keys, s_keys, 40)) {
- puts("Aiiiie");
- exit(1);
+ /* client handshake 2 */
+ memset(c_keys, 0, 40);
+ test_assert(! onion_skin_TAP_client_handshake(c_dh, s_buf, c_keys, 40));
+
+ test_memeq(c_keys, s_keys, 40);
+ memset(s_buf, 0, 40);
+ test_memneq(c_keys, s_buf, 40);
}
- test_memeq(c_keys, s_keys, 40);
- memset(s_buf, 0, 40);
- test_memneq(c_keys, s_buf, 40);
+ done:
+ crypto_dh_free(c_dh);
+ crypto_pk_free(pk);
+ crypto_pk_free(pk2);
+}
+
+static void
+test_bad_onion_handshake(void *arg)
+{
+ char junk_buf[TAP_ONIONSKIN_CHALLENGE_LEN];
+ char junk_buf2[TAP_ONIONSKIN_CHALLENGE_LEN];
+ /* client-side */
+ crypto_dh_t *c_dh = NULL;
+ char c_buf[TAP_ONIONSKIN_CHALLENGE_LEN];
+ char c_keys[40];
+ /* server-side */
+ char s_buf[TAP_ONIONSKIN_REPLY_LEN];
+ char s_keys[40];
+ /* shared */
+ crypto_pk_t *pk = NULL, *pk2 = NULL;
+
+ (void)arg;
+
+ pk = pk_generate(0);
+ pk2 = pk_generate(1);
+
+ /* Server: Case 1: the encrypted data is degenerate. */
+ memset(junk_buf, 0, sizeof(junk_buf));
+ crypto_pk_public_hybrid_encrypt(pk, junk_buf2, TAP_ONIONSKIN_CHALLENGE_LEN,
+ junk_buf, DH_KEY_LEN, PK_PKCS1_OAEP_PADDING, 1);
+ tt_int_op(-1, ==,
+ onion_skin_TAP_server_handshake(junk_buf2, pk, NULL,
+ s_buf, s_keys, 40));
+
+ /* Server: Case 2: the encrypted data is not long enough. */
+ memset(junk_buf, 0, sizeof(junk_buf));
+ memset(junk_buf2, 0, sizeof(junk_buf2));
+ crypto_pk_public_encrypt(pk, junk_buf2, sizeof(junk_buf2),
+ junk_buf, 48, PK_PKCS1_OAEP_PADDING);
+ tt_int_op(-1, ==,
+ onion_skin_TAP_server_handshake(junk_buf2, pk, NULL,
+ s_buf, s_keys, 40));
+
+ /* client handshake 1: do it straight. */
+ memset(c_buf, 0, TAP_ONIONSKIN_CHALLENGE_LEN);
+ test_assert(! onion_skin_TAP_create(pk, &c_dh, c_buf));
+
+ /* Server: Case 3: we just don't have the right key. */
+ tt_int_op(-1, ==,
+ onion_skin_TAP_server_handshake(c_buf, pk2, NULL,
+ s_buf, s_keys, 40));
+
+ /* Server: Case 4: The RSA-encrypted portion is corrupt. */
+ c_buf[64] ^= 33;
+ tt_int_op(-1, ==,
+ onion_skin_TAP_server_handshake(c_buf, pk, NULL,
+ s_buf, s_keys, 40));
+ c_buf[64] ^= 33;
+
+ /* (Let the server procede) */
+ tt_int_op(0, ==,
+ onion_skin_TAP_server_handshake(c_buf, pk, NULL,
+ s_buf, s_keys, 40));
+
+ /* Client: Case 1: The server sent back junk. */
+ s_buf[64] ^= 33;
+ tt_int_op(-1, ==,
+ onion_skin_TAP_client_handshake(c_dh, s_buf, c_keys, 40));
+ s_buf[64] ^= 33;
+
+ /* Let the client finish; make sure it can. */
+ tt_int_op(0, ==,
+ onion_skin_TAP_client_handshake(c_dh, s_buf, c_keys, 40));
+ test_memeq(s_keys, c_keys, 40);
+
+ /* Client: Case 2: The server sent back a degenerate DH. */
+ memset(s_buf, 0, sizeof(s_buf));
+ tt_int_op(-1, ==,
+ onion_skin_TAP_client_handshake(c_dh, s_buf, c_keys, 40));
done:
- if (c_dh)
- crypto_dh_free(c_dh);
- if (pk)
- crypto_pk_free(pk);
+ crypto_dh_free(c_dh);
+ crypto_pk_free(pk);
+ crypto_pk_free(pk2);
}
#ifdef CURVE25519_ENABLED
@@ -2005,6 +2091,7 @@ static struct testcase_t test_array[] = {
ENT(buffers),
{ "buffer_copy", test_buffer_copy, 0, NULL, NULL },
ENT(onion_handshake),
+ { "bad_onion_handshake", test_bad_onion_handshake, 0, NULL, NULL },
#ifdef CURVE25519_ENABLED
{ "ntor_handshake", test_ntor_handshake, 0, NULL, NULL },
#endif
@@ -2045,6 +2132,7 @@ extern struct testcase_t config_tests[];
extern struct testcase_t introduce_tests[];
extern struct testcase_t replaycache_tests[];
extern struct testcase_t cell_format_tests[];
+extern struct testcase_t circuitlist_tests[];
static struct testgroup_t testgroups[] = {
{ "", test_array },
@@ -2060,6 +2148,7 @@ static struct testgroup_t testgroups[] = {
{ "config/", config_tests },
{ "replaycache/", replaycache_tests },
{ "introduce/", introduce_tests },
+ { "circuitlist/", circuitlist_tests },
END_OF_GROUPS
};
diff --git a/src/test/test_addr.c b/src/test/test_addr.c
index fec85a469..4bc602df8 100644
--- a/src/test/test_addr.c
+++ b/src/test/test_addr.c
@@ -44,6 +44,10 @@ test_addr_basic(void)
test_eq(u32, 0x7f000001u);
test_eq(u16, 0);
tor_free(cp);
+
+ test_assert(addr_port_lookup(LOG_WARN, "localhost:3", &cp, &u32, NULL));
+ tor_free(cp);
+
test_eq(0, addr_mask_get_bits(0x0u));
test_eq(32, addr_mask_get_bits(0xFFFFFFFFu));
test_eq(16, addr_mask_get_bits(0xFFFF0000u));
@@ -217,11 +221,12 @@ test_addr_ip6_helpers(void)
/* ==== Converting to and from sockaddr_t. */
sin = (struct sockaddr_in *)&sa_storage;
sin->sin_family = AF_INET;
- sin->sin_port = 9090;
+ sin->sin_port = htons(9090);
sin->sin_addr.s_addr = htonl(0x7f7f0102); /*127.127.1.2*/
- tor_addr_from_sockaddr(&t1, (struct sockaddr *)sin, NULL);
+ tor_addr_from_sockaddr(&t1, (struct sockaddr *)sin, &port1);
test_eq(tor_addr_family(&t1), AF_INET);
test_eq(tor_addr_to_ipv4h(&t1), 0x7f7f0102);
+ tt_int_op(port1, ==, 9090);
memset(&sa_storage, 0, sizeof(sa_storage));
test_eq(sizeof(struct sockaddr_in),
@@ -235,8 +240,9 @@ test_addr_ip6_helpers(void)
sin6->sin6_family = AF_INET6;
sin6->sin6_port = htons(7070);
sin6->sin6_addr.s6_addr[0] = 128;
- tor_addr_from_sockaddr(&t1, (struct sockaddr *)sin6, NULL);
+ tor_addr_from_sockaddr(&t1, (struct sockaddr *)sin6, &port1);
test_eq(tor_addr_family(&t1), AF_INET6);
+ tt_int_op(port1, ==, 7070);
p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 0);
test_streq(p1, "8000::");
@@ -464,6 +470,9 @@ test_addr_ip6_helpers(void)
test_eq(0, i);
i = tor_addr_parse_PTR_name(&t1, "Foobar.baz", AF_UNSPEC, 1);
test_eq(0, i);
+ i = tor_addr_parse_PTR_name(&t1, "9999999999999999999999999999.in-addr.arpa",
+ AF_UNSPEC, 1);
+ test_eq(-1, i);
i = tor_addr_parse_PTR_name(&t1, "1.0.168.192.in-addr.arpa",
AF_UNSPEC, 1);
test_eq(1, i);
@@ -844,6 +853,90 @@ test_virtaddrmap(void *data)
}
static void
+test_addr_localname(void *arg)
+{
+ (void)arg;
+ tt_assert(tor_addr_hostname_is_local("localhost"));
+ tt_assert(tor_addr_hostname_is_local("LOCALHOST"));
+ tt_assert(tor_addr_hostname_is_local("LocalHost"));
+ tt_assert(tor_addr_hostname_is_local("local"));
+ tt_assert(tor_addr_hostname_is_local("LOCAL"));
+ tt_assert(tor_addr_hostname_is_local("here.now.local"));
+ tt_assert(tor_addr_hostname_is_local("here.now.LOCAL"));
+
+ tt_assert(!tor_addr_hostname_is_local(" localhost"));
+ tt_assert(!tor_addr_hostname_is_local("www.torproject.org"));
+ done:
+ ;
+}
+
+static void
+test_addr_dup_ip(void *arg)
+{
+ char *v = NULL;
+ (void)arg;
+#define CHECK(ip, s) do { \
+ v = tor_dup_ip(ip); \
+ tt_str_op(v,==,(s)); \
+ tor_free(v); \
+ } while (0)
+
+ CHECK(0xffffffff, "255.255.255.255");
+ CHECK(0x00000000, "0.0.0.0");
+ CHECK(0x7f000001, "127.0.0.1");
+ CHECK(0x01020304, "1.2.3.4");
+
+#undef CHECK
+ done:
+ tor_free(v);
+}
+
+static void
+test_addr_sockaddr_to_str(void *arg)
+{
+ char *v = NULL;
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+ struct sockaddr_storage ss;
+#ifdef HAVE_SYS_UN_H
+ struct sockaddr_un sun;
+#endif
+#define CHECK(sa, s) do { \
+ v = tor_sockaddr_to_str((const struct sockaddr*) &(sa)); \
+ tt_str_op(v,==,(s)); \
+ tor_free(v); \
+ } while (0)
+ (void)arg;
+
+ memset(&ss,0,sizeof(ss));
+ ss.ss_family = AF_UNSPEC;
+ CHECK(ss, "unspec");
+
+ memset(&sin,0,sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = htonl(0x7f808001);
+ sin.sin_port = htons(1234);
+ CHECK(sin, "127.128.128.1:1234");
+
+#ifdef HAVE_SYS_UN_H
+ memset(&sun,0,sizeof(sun));
+ sun.sun_family = AF_UNIX;
+ strlcpy(sun.sun_path, "/here/is/a/path", sizeof(sun.sun_path));
+ CHECK(sun, "unix:/here/is/a/path");
+#endif
+
+ memset(&sin6,0,sizeof(sin6));
+ sin6.sin6_family = AF_INET6;
+ memcpy(sin6.sin6_addr.s6_addr, "\x20\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x1a\x2b\x3c\x4d\x5e\x00\x01", 16);
+ sin6.sin6_port = htons(1234);
+ CHECK(sin6, "[2000::1a:2b3c:4d5e:1]:1234");
+
+ done:
+ tor_free(v);
+}
+
+static void
test_addr_is_loopback(void *data)
{
static const struct loopback_item {
@@ -886,6 +979,9 @@ struct testcase_t addr_tests[] = {
ADDR_LEGACY(ip6_helpers),
ADDR_LEGACY(parse),
{ "virtaddr", test_virtaddrmap, 0, NULL, NULL },
+ { "localname", test_addr_localname, 0, NULL, NULL },
+ { "dup_ip", test_addr_dup_ip, 0, NULL, NULL },
+ { "sockaddr_to_str", test_addr_sockaddr_to_str, 0, NULL, NULL },
{ "is_loopback", test_addr_is_loopback, 0, NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_circuitlist.c b/src/test/test_circuitlist.c
new file mode 100644
index 000000000..720b40765
--- /dev/null
+++ b/src/test/test_circuitlist.c
@@ -0,0 +1,168 @@
+/* Copyright (c) 2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#define TOR_CHANNEL_INTERNAL_
+#define CIRCUITLIST_PRIVATE
+#include "or.h"
+#include "channel.h"
+#include "circuitlist.h"
+#include "test.h"
+
+static channel_t *
+new_fake_channel(void)
+{
+ channel_t *chan = tor_malloc_zero(sizeof(channel_t));
+ channel_init(chan);
+ return chan;
+}
+
+static struct {
+ int ncalls;
+ void *cmux;
+ void *circ;
+ cell_direction_t dir;
+} cam;
+
+static void
+circuitmux_attach_mock(circuitmux_t *cmux, circuit_t *circ,
+ cell_direction_t dir)
+{
+ ++cam.ncalls;
+ cam.cmux = cmux;
+ cam.circ = circ;
+ cam.dir = dir;
+}
+
+static struct {
+ int ncalls;
+ void *cmux;
+ void *circ;
+} cdm;
+
+static void
+circuitmux_detach_mock(circuitmux_t *cmux, circuit_t *circ)
+{
+ ++cdm.ncalls;
+ cdm.cmux = cmux;
+ cdm.circ = circ;
+}
+
+#define GOT_CMUX_ATTACH(mux_, circ_, dir_) do { \
+ tt_int_op(cam.ncalls, ==, 1); \
+ tt_ptr_op(cam.cmux, ==, (mux_)); \
+ tt_ptr_op(cam.circ, ==, (circ_)); \
+ tt_ptr_op(cam.dir, ==, (dir_)); \
+ memset(&cam, 0, sizeof(cam)); \
+ } while (0)
+
+#define GOT_CMUX_DETACH(mux_, circ_) do { \
+ tt_int_op(cdm.ncalls, ==, 1); \
+ tt_ptr_op(cdm.cmux, ==, (mux_)); \
+ tt_ptr_op(cdm.circ, ==, (circ_)); \
+ memset(&cdm, 0, sizeof(cdm)); \
+ } while (0)
+
+static void
+test_clist_maps(void *arg)
+{
+ channel_t *ch1 = new_fake_channel();
+ channel_t *ch2 = new_fake_channel();
+ channel_t *ch3 = new_fake_channel();
+ or_circuit_t *or_c1=NULL, *or_c2=NULL;
+
+ (void) arg;
+
+ MOCK(circuitmux_attach_circuit, circuitmux_attach_mock);
+ MOCK(circuitmux_detach_circuit, circuitmux_detach_mock);
+ memset(&cam, 0, sizeof(cam));
+ memset(&cdm, 0, sizeof(cdm));
+
+ ch1->cmux = (void*)0x1001;
+ ch2->cmux = (void*)0x1002;
+ ch3->cmux = (void*)0x1003;
+
+ or_c1 = or_circuit_new(100, ch2);
+ tt_assert(or_c1);
+ GOT_CMUX_ATTACH(ch2->cmux, or_c1, CELL_DIRECTION_IN);
+ tt_int_op(or_c1->p_circ_id, ==, 100);
+ tt_ptr_op(or_c1->p_chan, ==, ch2);
+
+ or_c2 = or_circuit_new(100, ch1);
+ tt_assert(or_c2);
+ GOT_CMUX_ATTACH(ch1->cmux, or_c2, CELL_DIRECTION_IN);
+ tt_int_op(or_c2->p_circ_id, ==, 100);
+ tt_ptr_op(or_c2->p_chan, ==, ch1);
+
+ circuit_set_n_circid_chan(TO_CIRCUIT(or_c1), 200, ch1);
+ GOT_CMUX_ATTACH(ch1->cmux, or_c1, CELL_DIRECTION_OUT);
+
+ circuit_set_n_circid_chan(TO_CIRCUIT(or_c2), 200, ch2);
+ GOT_CMUX_ATTACH(ch2->cmux, or_c2, CELL_DIRECTION_OUT);
+
+ tt_ptr_op(circuit_get_by_circid_channel(200, ch1), ==, TO_CIRCUIT(or_c1));
+ tt_ptr_op(circuit_get_by_circid_channel(200, ch2), ==, TO_CIRCUIT(or_c2));
+ tt_ptr_op(circuit_get_by_circid_channel(100, ch2), ==, TO_CIRCUIT(or_c1));
+ /* Try the same thing again, to test the "fast" path. */
+ tt_ptr_op(circuit_get_by_circid_channel(100, ch2), ==, TO_CIRCUIT(or_c1));
+ tt_assert(circuit_id_in_use_on_channel(100, ch2));
+ tt_assert(! circuit_id_in_use_on_channel(101, ch2));
+
+ /* Try changing the circuitid and channel of that circuit. */
+ circuit_set_p_circid_chan(or_c1, 500, ch3);
+ GOT_CMUX_DETACH(ch2->cmux, TO_CIRCUIT(or_c1));
+ GOT_CMUX_ATTACH(ch3->cmux, TO_CIRCUIT(or_c1), CELL_DIRECTION_IN);
+ tt_ptr_op(circuit_get_by_circid_channel(100, ch2), ==, NULL);
+ tt_assert(! circuit_id_in_use_on_channel(100, ch2));
+ tt_ptr_op(circuit_get_by_circid_channel(500, ch3), ==, TO_CIRCUIT(or_c1));
+
+ /* Now let's see about destroy handling. */
+ tt_assert(! circuit_id_in_use_on_channel(205, ch2));
+ tt_assert(circuit_id_in_use_on_channel(200, ch2));
+ channel_note_destroy_pending(ch2, 200);
+ channel_note_destroy_pending(ch2, 205);
+ channel_note_destroy_pending(ch1, 100);
+ tt_assert(circuit_id_in_use_on_channel(205, ch2))
+ tt_assert(circuit_id_in_use_on_channel(200, ch2));
+ tt_assert(circuit_id_in_use_on_channel(100, ch1));
+
+ tt_assert(TO_CIRCUIT(or_c2)->n_delete_pending != 0);
+ tt_ptr_op(circuit_get_by_circid_channel(200, ch2), ==, TO_CIRCUIT(or_c2));
+ tt_ptr_op(circuit_get_by_circid_channel(100, ch1), ==, TO_CIRCUIT(or_c2));
+
+ /* Okay, now free ch2 and make sure that the circuit ID is STILL not
+ * usable, because we haven't declared the destroy to be nonpending */
+ tt_int_op(cdm.ncalls, ==, 0);
+ circuit_free(TO_CIRCUIT(or_c2));
+ or_c2 = NULL; /* prevent free */
+ tt_int_op(cdm.ncalls, ==, 2);
+ memset(&cdm, 0, sizeof(cdm));
+ tt_assert(circuit_id_in_use_on_channel(200, ch2));
+ tt_assert(circuit_id_in_use_on_channel(100, ch1));
+ tt_ptr_op(circuit_get_by_circid_channel(200, ch2), ==, NULL);
+ tt_ptr_op(circuit_get_by_circid_channel(100, ch1), ==, NULL);
+
+ /* Now say that the destroy is nonpending */
+ channel_note_destroy_not_pending(ch2, 200);
+ tt_ptr_op(circuit_get_by_circid_channel(200, ch2), ==, NULL);
+ channel_note_destroy_not_pending(ch1, 100);
+ tt_ptr_op(circuit_get_by_circid_channel(100, ch1), ==, NULL);
+ tt_assert(! circuit_id_in_use_on_channel(200, ch2));
+ tt_assert(! circuit_id_in_use_on_channel(100, ch1));
+
+ done:
+ tor_free(ch1);
+ tor_free(ch2);
+ tor_free(ch3);
+ if (or_c1)
+ circuit_free(TO_CIRCUIT(or_c1));
+ if (or_c2)
+ circuit_free(TO_CIRCUIT(or_c2));
+ UNMOCK(circuitmux_attach_circuit);
+ UNMOCK(circuitmux_detach_circuit);
+}
+
+struct testcase_t circuitlist_tests[] = {
+ { "maps", test_clist_maps, TT_FORK, NULL, NULL },
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_config.c b/src/test/test_config.c
index e20fe7329..4e9e13e47 100644
--- a/src/test/test_config.c
+++ b/src/test/test_config.c
@@ -10,6 +10,8 @@
#include "confparse.h"
#include "connection_edge.h"
#include "test.h"
+#include "util.h"
+#include "address.h"
static void
test_config_addressmap(void *arg)
@@ -169,11 +171,281 @@ test_config_addressmap(void *arg)
;
}
+static int
+is_private_dir(const char* path)
+{
+ struct stat st;
+ int r = stat(path, &st);
+ if (r) {
+ return 0;
+ }
+#if !defined (_WIN32) || defined (WINCE)
+ if ((st.st_mode & (S_IFDIR | 0777)) != (S_IFDIR | 0700)) {
+ return 0;
+ }
+#endif
+ return 1;
+}
+
+static void
+test_config_check_or_create_data_subdir(void *arg)
+{
+ or_options_t *options = get_options_mutable();
+ char *datadir = options->DataDirectory = tor_strdup(get_fname("datadir-0"));
+ const char *subdir = "test_stats";
+ char *subpath = get_datadir_fname(subdir);
+ struct stat st;
+ int r;
+#if !defined (_WIN32) || defined (WINCE)
+ unsigned group_permission;
+#endif
+ (void)arg;
+
+#if defined (_WIN32) && !defined (WINCE)
+ tt_int_op(mkdir(options->DataDirectory), ==, 0);
+#else
+ tt_int_op(mkdir(options->DataDirectory, 0700), ==, 0);
+#endif
+
+ r = stat(subpath, &st);
+
+ // The subdirectory shouldn't exist yet,
+ // but should be created by the call to check_or_create_data_subdir.
+ test_assert(r && (errno == ENOENT));
+ test_assert(!check_or_create_data_subdir(subdir));
+ test_assert(is_private_dir(subpath));
+
+ // The check should return 0, if the directory already exists
+ // and is private to the user.
+ test_assert(!check_or_create_data_subdir(subdir));
+
+#if !defined (_WIN32) || defined (WINCE)
+ group_permission = st.st_mode | 0070;
+ r = chmod(subpath, group_permission);
+
+ if (r) {
+ test_fail_msg("Changing permissions for the subdirectory failed.");
+ }
+
+ // If the directory exists, but its mode is too permissive
+ // a call to check_or_create_data_subdir should reset the mode.
+ test_assert(!is_private_dir(subpath));
+ test_assert(!check_or_create_data_subdir(subdir));
+ test_assert(is_private_dir(subpath));
+#endif
+
+ done:
+ rmdir(subpath);
+ tor_free(datadir);
+ tor_free(subpath);
+}
+
+static void
+test_config_write_to_data_subdir(void *arg)
+{
+ or_options_t* options = get_options_mutable();
+ char *datadir = options->DataDirectory = tor_strdup(get_fname("datadir-1"));
+ const char* subdir = "test_stats";
+ const char* fname = "test_file";
+ const char* str =
+ "Lorem ipsum dolor sit amet, consetetur sadipscing\n"
+ "elitr, sed diam nonumy eirmod\n"
+ "tempor invidunt ut labore et dolore magna aliquyam\n"
+ "erat, sed diam voluptua.\n"
+ "At vero eos et accusam et justo duo dolores et ea\n"
+ "rebum. Stet clita kasd gubergren,\n"
+ "no sea takimata sanctus est Lorem ipsum dolor sit amet.\n"
+ "Lorem ipsum dolor sit amet,\n"
+ "consetetur sadipscing elitr, sed diam nonumy eirmod\n"
+ "tempor invidunt ut labore et dolore\n"
+ "magna aliquyam erat, sed diam voluptua. At vero eos et\n"
+ "accusam et justo duo dolores et\n"
+ "ea rebum. Stet clita kasd gubergren, no sea takimata\n"
+ "sanctus est Lorem ipsum dolor sit amet.";
+ char* filepath = get_datadir_fname2(subdir, fname);
+ (void)arg;
+
+#if defined (_WIN32) && !defined (WINCE)
+ tt_int_op(mkdir(options->DataDirectory), ==, 0);
+#else
+ tt_int_op(mkdir(options->DataDirectory, 0700), ==, 0);
+#endif
+
+ // Write attempt shoudl fail, if subdirectory doesn't exist.
+ test_assert(write_to_data_subdir(subdir, fname, str, NULL));
+ test_assert(! check_or_create_data_subdir(subdir));
+
+ // Content of file after write attempt should be
+ // equal to the original string.
+ test_assert(!write_to_data_subdir(subdir, fname, str, NULL));
+ test_streq(read_file_to_str(filepath, 0, NULL), str);
+
+ // A second write operation should overwrite the old content.
+ test_assert(!write_to_data_subdir(subdir, fname, str, NULL));
+ test_streq(read_file_to_str(filepath, 0, NULL), str);
+
+ done:
+ (void) unlink(filepath);
+ rmdir(options->DataDirectory);
+ tor_free(datadir);
+ tor_free(filepath);
+}
+
+/* Test helper function: Make sure that a bridge line gets parsed
+ * properly. Also make sure that the resulting bridge_line_t structure
+ * has its fields set correctly. */
+static void
+good_bridge_line_test(const char *string, const char *test_addrport,
+ const char *test_digest, const char *test_transport,
+ const smartlist_t *test_socks_args)
+{
+ char *tmp = NULL;
+ bridge_line_t *bridge_line = parse_bridge_line(string);
+ test_assert(bridge_line);
+
+ /* test addrport */
+ tmp = tor_strdup(fmt_addrport(&bridge_line->addr, bridge_line->port));
+ test_streq(test_addrport, tmp);
+ tor_free(tmp);
+
+ /* If we were asked to validate a digest, but we did not get a
+ digest after parsing, we failed. */
+ if (test_digest && tor_digest_is_zero(bridge_line->digest))
+ test_assert(0);
+
+ /* If we were not asked to validate a digest, and we got a digest
+ after parsing, we failed again. */
+ if (!test_digest && !tor_digest_is_zero(bridge_line->digest))
+ test_assert(0);
+
+ /* If we were asked to validate a digest, and we got a digest after
+ parsing, make sure it's correct. */
+ if (test_digest) {
+ tmp = tor_strdup(hex_str(bridge_line->digest, DIGEST_LEN));
+ tor_strlower(tmp);
+ test_streq(test_digest, tmp);
+ tor_free(tmp);
+ }
+
+ /* If we were asked to validate a transport name, make sure tha it
+ matches with the transport name that was parsed. */
+ if (test_transport && !bridge_line->transport_name)
+ test_assert(0);
+ if (!test_transport && bridge_line->transport_name)
+ test_assert(0);
+ if (test_transport)
+ test_streq(test_transport, bridge_line->transport_name);
+
+ /* Validate the SOCKS argument smartlist. */
+ if (test_socks_args && !bridge_line->socks_args)
+ test_assert(0);
+ if (!test_socks_args && bridge_line->socks_args)
+ test_assert(0);
+ if (test_socks_args)
+ test_assert(smartlist_strings_eq(test_socks_args,
+ bridge_line->socks_args));
+
+ done:
+ tor_free(tmp);
+ bridge_line_free(bridge_line);
+}
+
+/* Test helper function: Make sure that a bridge line is
+ * unparseable. */
+static void
+bad_bridge_line_test(const char *string)
+{
+ bridge_line_t *bridge_line = parse_bridge_line(string);
+ test_assert(!bridge_line);
+
+ done:
+ bridge_line_free(bridge_line);
+}
+
+static void
+test_config_parse_bridge_line(void *arg)
+{
+ (void) arg;
+ good_bridge_line_test("192.0.2.1:4123",
+ "192.0.2.1:4123", NULL, NULL, NULL);
+
+ good_bridge_line_test("192.0.2.1",
+ "192.0.2.1:443", NULL, NULL, NULL);
+
+ good_bridge_line_test("transport [::1]",
+ "[::1]:443", NULL, "transport", NULL);
+
+ good_bridge_line_test("transport 192.0.2.1:12 "
+ "4352e58420e68f5e40bf7c74faddccd9d1349413",
+ "192.0.2.1:12",
+ "4352e58420e68f5e40bf7c74faddccd9d1349413",
+ "transport", NULL);
+
+ {
+ smartlist_t *sl_tmp = smartlist_new();
+ smartlist_add_asprintf(sl_tmp, "twoandtwo=five");
+
+ good_bridge_line_test("transport 192.0.2.1:12 "
+ "4352e58420e68f5e40bf7c74faddccd9d1349413 twoandtwo=five",
+ "192.0.2.1:12", "4352e58420e68f5e40bf7c74faddccd9d1349413",
+ "transport", sl_tmp);
+
+ SMARTLIST_FOREACH(sl_tmp, char *, s, tor_free(s));
+ smartlist_free(sl_tmp);
+ }
+
+ {
+ smartlist_t *sl_tmp = smartlist_new();
+ smartlist_add_asprintf(sl_tmp, "twoandtwo=five");
+ smartlist_add_asprintf(sl_tmp, "z=z");
+
+ good_bridge_line_test("transport 192.0.2.1:12 twoandtwo=five z=z",
+ "192.0.2.1:12", NULL, "transport", sl_tmp);
+
+ SMARTLIST_FOREACH(sl_tmp, char *, s, tor_free(s));
+ smartlist_free(sl_tmp);
+ }
+
+ good_bridge_line_test("192.0.2.1:1231 "
+ "4352e58420e68f5e40bf7c74faddccd9d1349413",
+ "192.0.2.1:1231",
+ "4352e58420e68f5e40bf7c74faddccd9d1349413",
+ NULL, NULL);
+
+ /* Empty line */
+ bad_bridge_line_test("");
+ /* bad transport name */
+ bad_bridge_line_test("tr$n_sp0r7 190.20.2.2");
+ /* weird ip address */
+ bad_bridge_line_test("a.b.c.d");
+ /* invalid fpr */
+ bad_bridge_line_test("2.2.2.2:1231 4352e58420e68f5e40bf7c74faddccd9d1349");
+ /* no k=v in the end */
+ bad_bridge_line_test("obfs2 2.2.2.2:1231 "
+ "4352e58420e68f5e40bf7c74faddccd9d1349413 what");
+ /* no addrport */
+ bad_bridge_line_test("asdw");
+ /* huge k=v value that can't fit in SOCKS fields */
+ bad_bridge_line_test(
+ "obfs2 2.2.2.2:1231 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aa=b");
+}
+
#define CONFIG_TEST(name, flags) \
{ #name, test_config_ ## name, flags, NULL, NULL }
struct testcase_t config_tests[] = {
CONFIG_TEST(addressmap, 0),
+ CONFIG_TEST(parse_bridge_line, 0),
+ CONFIG_TEST(check_or_create_data_subdir, TT_FORK),
+ CONFIG_TEST(write_to_data_subdir, TT_FORK),
END_OF_TESTCASES
};
diff --git a/src/test/test_crypto.c b/src/test/test_crypto.c
index f92bfd673..9dc43b1d2 100644
--- a/src/test/test_crypto.c
+++ b/src/test/test_crypto.c
@@ -4,7 +4,6 @@
/* See LICENSE for licensing information */
#include "orconfig.h"
-#define CRYPTO_PRIVATE
#define CRYPTO_CURVE25519_PRIVATE
#include "or.h"
#include "test.h"
@@ -14,6 +13,10 @@
#include "crypto_curve25519.h"
#endif
+extern const char AUTHORITY_SIGNKEY_1[];
+extern const char AUTHORITY_SIGNKEY_1_DIGEST[];
+extern const char AUTHORITY_SIGNKEY_1_DIGEST256[];
+
/** Run unit tests for Diffie-Hellman functionality. */
static void
test_crypto_dh(void)
@@ -269,34 +272,6 @@ test_crypto_sha(void)
"96177A9CB410FF61F20015AD");
tt_int_op(i, ==, 0);
- /* Test HMAC-SHA-1 with test cases from RFC2202. */
-
- /* Case 1. */
- memset(key, 0x0b, 20);
- crypto_hmac_sha1(digest, key, 20, "Hi There", 8);
- test_streq(hex_str(digest, 20),
- "B617318655057264E28BC0B6FB378C8EF146BE00");
- /* Case 2. */
- crypto_hmac_sha1(digest, "Jefe", 4, "what do ya want for nothing?", 28);
- test_streq(hex_str(digest, 20),
- "EFFCDF6AE5EB2FA2D27416D5F184DF9C259A7C79");
-
- /* Case 4. */
- base16_decode(key, 25,
- "0102030405060708090a0b0c0d0e0f10111213141516171819", 50);
- memset(data, 0xcd, 50);
- crypto_hmac_sha1(digest, key, 25, data, 50);
- test_streq(hex_str(digest, 20),
- "4C9007F4026250C6BC8414F9BF50C86C2D7235DA");
-
- /* Case 5. */
- memset(key, 0xaa, 80);
- crypto_hmac_sha1(digest, key, 80,
- "Test Using Larger Than Block-Size Key - Hash Key First",
- 54);
- test_streq(hex_str(digest, 20),
- "AA4AE5E15272D00E95705637CE8A3B55ED402112");
-
/* Test HMAC-SHA256 with test cases from wikipedia and RFC 4231 */
/* Case empty (wikipedia) */
@@ -422,7 +397,7 @@ test_crypto_pk(void)
char *encoded = NULL;
char data1[1024], data2[1024], data3[1024];
size_t size;
- int i, j, p, len;
+ int i, len;
/* Public-key ciphers */
pk1 = pk_generate(0);
@@ -506,19 +481,16 @@ test_crypto_pk(void)
/* Try with hybrid encryption wrappers. */
crypto_rand(data1, 1024);
- for (i = 0; i < 2; ++i) {
- for (j = 85; j < 140; ++j) {
- memset(data2,0,1024);
- memset(data3,0,1024);
- p = (i==0)?PK_PKCS1_PADDING:PK_PKCS1_OAEP_PADDING;
- len = crypto_pk_public_hybrid_encrypt(pk1,data2,sizeof(data2),
- data1,j,p,0);
- test_assert(len>=0);
- len = crypto_pk_private_hybrid_decrypt(pk1,data3,sizeof(data3),
- data2,len,p,1);
- test_eq(len,j);
- test_memeq(data1,data3,j);
- }
+ for (i = 85; i < 140; ++i) {
+ memset(data2,0,1024);
+ memset(data3,0,1024);
+ len = crypto_pk_public_hybrid_encrypt(pk1,data2,sizeof(data2),
+ data1,i,PK_PKCS1_OAEP_PADDING,0);
+ test_assert(len>=0);
+ len = crypto_pk_private_hybrid_decrypt(pk1,data3,sizeof(data3),
+ data2,len,PK_PKCS1_OAEP_PADDING,1);
+ test_eq(len,i);
+ test_memeq(data1,data3,i);
}
/* Try copy_full */
@@ -536,6 +508,35 @@ test_crypto_pk(void)
tor_free(encoded);
}
+/** Sanity check for crypto pk digests */
+static void
+test_crypto_digests(void)
+{
+ crypto_pk_t *k = NULL;
+ ssize_t r;
+ digests_t pkey_digests;
+ char digest[DIGEST_LEN];
+
+ k = crypto_pk_new();
+ test_assert(k);
+ r = crypto_pk_read_private_key_from_string(k, AUTHORITY_SIGNKEY_1, -1);
+ test_assert(!r);
+
+ r = crypto_pk_get_digest(k, digest);
+ test_assert(r == 0);
+ test_memeq(hex_str(digest, DIGEST_LEN),
+ AUTHORITY_SIGNKEY_1_DIGEST, HEX_DIGEST_LEN);
+
+ r = crypto_pk_get_all_digests(k, &pkey_digests);
+
+ test_memeq(hex_str(pkey_digests.d[DIGEST_SHA1], DIGEST_LEN),
+ AUTHORITY_SIGNKEY_1_DIGEST, HEX_DIGEST_LEN);
+ test_memeq(hex_str(pkey_digests.d[DIGEST_SHA256], DIGEST256_LEN),
+ AUTHORITY_SIGNKEY_1_DIGEST256, HEX_DIGEST256_LEN);
+ done:
+ crypto_pk_free(k);
+}
+
/** Run unit tests for misc crypto formatting functionality (base64, base32,
* fingerprints, etc) */
static void
@@ -630,7 +631,7 @@ test_crypto_formats(void)
data1 = tor_strdup("ABCD1234ABCD56780000ABCD1234ABCD56780000");
test_eq(strlen(data1), 40);
data2 = tor_malloc(FINGERPRINT_LEN+1);
- add_spaces_to_fp(data2, FINGERPRINT_LEN+1, data1);
+ crypto_add_spaces_to_fp(data2, FINGERPRINT_LEN+1, data1);
test_streq(data2, "ABCD 1234 ABCD 5678 0000 ABCD 1234 ABCD 5678 0000");
tor_free(data1);
tor_free(data2);
@@ -1134,6 +1135,7 @@ struct testcase_t crypto_tests[] = {
{ "aes_EVP", test_crypto_aes, TT_FORK, &pass_data, (void*)"evp" },
CRYPTO_LEGACY(sha),
CRYPTO_LEGACY(pk),
+ CRYPTO_LEGACY(digests),
CRYPTO_LEGACY(dh),
CRYPTO_LEGACY(s2k),
{ "aes_iv_AES", test_crypto_aes_iv, TT_FORK, &pass_data, (void*)"aes" },
diff --git a/src/test/test_data.c b/src/test/test_data.c
index 5f0f7cba0..3c68b1294 100644
--- a/src/test/test_data.c
+++ b/src/test/test_data.c
@@ -63,6 +63,11 @@ const char AUTHORITY_SIGNKEY_1[] =
"Yx4lqK0ca5IkTp3HevwnlWaJgbaOTUspCVshzJBhDA==\n"
"-----END RSA PRIVATE KEY-----\n";
+const char AUTHORITY_SIGNKEY_1_DIGEST[] =
+ "CBF56A83368A5150F1A9AAADAFB4D77F8C4170E2";
+const char AUTHORITY_SIGNKEY_1_DIGEST256[] =
+ "AF7C5468DBE3BA54A052726038D7F15F3C4CA511B1952645B3D96D83A8DFB51C";
+
/** Second of 3 example authority certificates for unit testing. */
const char AUTHORITY_CERT_2[] =
"dir-key-certificate-version 3\n"
diff --git a/src/test/test_dir.c b/src/test/test_dir.c
index 56ac3b34c..6c2915d09 100644
--- a/src/test/test_dir.c
+++ b/src/test/test_dir.c
@@ -2317,9 +2317,9 @@ test_dir_v2_dir(void *arg)
/* Make a directory so there's somewhere to store the thing */
#ifdef _WIN32
- mkdir(get_fname("cached-status"));
+ tt_int_op(mkdir(get_fname("cached-status")), ==, 0);
#else
- mkdir(get_fname("cached-status"), 0700);
+ tt_int_op(mkdir(get_fname("cached-status"), 0700), ==, 0);
#endif
v2 = generate_v2_networkstatus_opinion();
diff --git a/src/test/test_pt.c b/src/test/test_pt.c
index 80707f437..16daa2836 100644
--- a/src/test/test_pt.c
+++ b/src/test/test_pt.c
@@ -22,64 +22,85 @@ static void
test_pt_parsing(void)
{
char line[200];
+ transport_t *transport = NULL;
+ tor_addr_t test_addr;
managed_proxy_t *mp = tor_malloc(sizeof(managed_proxy_t));
mp->conf_state = PT_PROTO_INFANT;
mp->transports = smartlist_new();
/* incomplete cmethod */
- strcpy(line,"CMETHOD trebuchet");
+ strlcpy(line,"CMETHOD trebuchet",sizeof(line));
test_assert(parse_cmethod_line(line, mp) < 0);
reset_mp(mp);
/* wrong proxy type */
- strcpy(line,"CMETHOD trebuchet dog 127.0.0.1:1999");
+ strlcpy(line,"CMETHOD trebuchet dog 127.0.0.1:1999",sizeof(line));
test_assert(parse_cmethod_line(line, mp) < 0);
reset_mp(mp);
/* wrong addrport */
- strcpy(line,"CMETHOD trebuchet socks4 abcd");
+ strlcpy(line,"CMETHOD trebuchet socks4 abcd",sizeof(line));
test_assert(parse_cmethod_line(line, mp) < 0);
reset_mp(mp);
/* correct line */
- strcpy(line,"CMETHOD trebuchet socks5 127.0.0.1:1999");
+ strlcpy(line,"CMETHOD trebuchet socks5 127.0.0.1:1999",sizeof(line));
test_assert(parse_cmethod_line(line, mp) == 0);
- test_assert(smartlist_len(mp->transports));
+ test_assert(smartlist_len(mp->transports) == 1);
+ transport = smartlist_get(mp->transports, 0);
+ /* test registered address of transport */
+ tor_addr_parse(&test_addr, "127.0.0.1");
+ test_assert(tor_addr_eq(&test_addr, &transport->addr));
+ /* test registered port of transport */
+ test_assert(transport->port == 1999);
+ /* test registered SOCKS version of transport */
+ test_assert(transport->socks_version == PROXY_SOCKS5);
+ /* test registered name of transport */
+ test_streq(transport->name, "trebuchet");
reset_mp(mp);
/* incomplete smethod */
- strcpy(line,"SMETHOD trebuchet");
+ strlcpy(line,"SMETHOD trebuchet",sizeof(line));
test_assert(parse_smethod_line(line, mp) < 0);
reset_mp(mp);
/* wrong addr type */
- strcpy(line,"SMETHOD trebuchet abcd");
+ strlcpy(line,"SMETHOD trebuchet abcd",sizeof(line));
test_assert(parse_smethod_line(line, mp) < 0);
reset_mp(mp);
/* cowwect */
- strcpy(line,"SMETHOD trebuchy 127.0.0.1:1999");
+ strlcpy(line,"SMETHOD trebuchy 127.0.0.2:2999",sizeof(line));
test_assert(parse_smethod_line(line, mp) == 0);
+ test_assert(smartlist_len(mp->transports) == 1);
+ transport = smartlist_get(mp->transports, 0);
+ /* test registered address of transport */
+ tor_addr_parse(&test_addr, "127.0.0.2");
+ test_assert(tor_addr_eq(&test_addr, &transport->addr));
+ /* test registered port of transport */
+ test_assert(transport->port == 2999);
+ /* test registered name of transport */
+ test_streq(transport->name, "trebuchy");
reset_mp(mp);
/* unsupported version */
- strcpy(line,"VERSION 666");
+ strlcpy(line,"VERSION 666",sizeof(line));
test_assert(parse_version(line, mp) < 0);
/* incomplete VERSION */
- strcpy(line,"VERSION ");
+ strlcpy(line,"VERSION ",sizeof(line));
test_assert(parse_version(line, mp) < 0);
/* correct VERSION */
- strcpy(line,"VERSION 1");
+ strlcpy(line,"VERSION 1",sizeof(line));
test_assert(parse_version(line, mp) == 0);
done:
@@ -99,32 +120,32 @@ test_pt_protocol(void)
/* various wrong protocol runs: */
- strcpy(line,"VERSION 1");
+ strlcpy(line,"VERSION 1",sizeof(line));
handle_proxy_line(line, mp);
test_assert(mp->conf_state == PT_PROTO_ACCEPTING_METHODS);
- strcpy(line,"VERSION 1");
+ strlcpy(line,"VERSION 1",sizeof(line));
handle_proxy_line(line, mp);
test_assert(mp->conf_state == PT_PROTO_BROKEN);
reset_mp(mp);
- strcpy(line,"CMETHOD trebuchet socks5 127.0.0.1:1999");
+ strlcpy(line,"CMETHOD trebuchet socks5 127.0.0.1:1999",sizeof(line));
handle_proxy_line(line, mp);
test_assert(mp->conf_state == PT_PROTO_BROKEN);
reset_mp(mp);
/* correct protocol run: */
- strcpy(line,"VERSION 1");
+ strlcpy(line,"VERSION 1",sizeof(line));
handle_proxy_line(line, mp);
test_assert(mp->conf_state == PT_PROTO_ACCEPTING_METHODS);
- strcpy(line,"CMETHOD trebuchet socks5 127.0.0.1:1999");
+ strlcpy(line,"CMETHOD trebuchet socks5 127.0.0.1:1999",sizeof(line));
handle_proxy_line(line, mp);
test_assert(mp->conf_state == PT_PROTO_ACCEPTING_METHODS);
- strcpy(line,"CMETHODS DONE");
+ strlcpy(line,"CMETHODS DONE",sizeof(line));
handle_proxy_line(line, mp);
test_assert(mp->conf_state == PT_PROTO_CONFIGURED);
diff --git a/src/test/test_replay.c b/src/test/test_replay.c
index de841ad59..200bf4dd3 100644
--- a/src/test/test_replay.c
+++ b/src/test/test_replay.c
@@ -32,6 +32,40 @@ test_replaycache_alloc(void)
}
static void
+test_replaycache_badalloc(void)
+{
+ replaycache_t *r = NULL;
+
+ /* Negative horizon should fail */
+ r = replaycache_new(-600, 300);
+ test_assert(r == NULL);
+ /* Negative interval should get adjusted to zero */
+ r = replaycache_new(600, -300);
+ test_assert(r != NULL);
+ test_eq(r->scrub_interval, 0);
+ replaycache_free(r);
+ /* Negative horizon and negative interval should still fail */
+ r = replaycache_new(-600, -300);
+ test_assert(r == NULL);
+
+ done:
+ if (r) replaycache_free(r);
+
+ return;
+}
+
+static void
+test_replaycache_free_null(void)
+{
+ replaycache_free(NULL);
+ /* Assert that we're here without horrible death */
+ test_assert(1);
+
+ done:
+ return;
+}
+
+static void
test_replaycache_miss(void)
{
replaycache_t *r = NULL;
@@ -45,6 +79,12 @@ test_replaycache_miss(void)
(int)strlen(test_buffer), NULL);
test_eq(result, 0);
+ /* poke the bad-parameter error case too */
+ result =
+ replaycache_add_and_test_internal(1200, NULL, test_buffer,
+ (int)strlen(test_buffer), NULL);
+ test_eq(result, 0);
+
done:
if (r) replaycache_free(r);
@@ -163,16 +203,146 @@ test_replaycache_noexpire(void)
return;
}
+static void
+test_replaycache_scrub(void)
+{
+ replaycache_t *r = NULL;
+ int result;
+
+ r = replaycache_new(600, 300);
+ test_assert(r != NULL);
+
+ /* Set up like in test_replaycache_hit() */
+ result =
+ replaycache_add_and_test_internal(100, r, test_buffer,
+ (int)strlen(test_buffer), NULL);
+ test_eq(result, 0);
+
+ result =
+ replaycache_add_and_test_internal(200, r, test_buffer,
+ (int)strlen(test_buffer), NULL);
+ test_eq(result, 1);
+
+ /*
+ * Poke a few replaycache_scrub_if_needed_internal() error cases that
+ * can't happen through replaycache_add_and_test_internal()
+ */
+
+ /* Null cache */
+ replaycache_scrub_if_needed_internal(300, NULL);
+ /* Assert we're still here */
+ test_assert(1);
+
+ /* Make sure we hit the aging-out case too */
+ replaycache_scrub_if_needed_internal(1500, r);
+ /* Assert that we aged it */
+ test_eq(digestmap_size(r->digests_seen), 0);
+
+ done:
+ if (r) replaycache_free(r);
+
+ return;
+}
+
+static void
+test_replaycache_future(void)
+{
+ replaycache_t *r = NULL;
+ int result;
+ time_t elapsed = 0;
+
+ r = replaycache_new(600, 300);
+ test_assert(r != NULL);
+
+ /* Set up like in test_replaycache_hit() */
+ result =
+ replaycache_add_and_test_internal(100, r, test_buffer,
+ (int)strlen(test_buffer), &elapsed);
+ test_eq(result, 0);
+ /* elapsed should still be 0, since it wasn't written */
+ test_eq(elapsed, 0);
+
+ result =
+ replaycache_add_and_test_internal(200, r, test_buffer,
+ (int)strlen(test_buffer), &elapsed);
+ test_eq(result, 1);
+ /* elapsed should be the time since the last hit */
+ test_eq(elapsed, 100);
+
+ /*
+ * Now let's turn the clock back to get coverage on the cache entry from the
+ * future not-supposed-to-happen case.
+ */
+ result =
+ replaycache_add_and_test_internal(150, r, test_buffer,
+ (int)strlen(test_buffer), &elapsed);
+ /* We should still get a hit */
+ test_eq(result, 1);
+ /* ...but it shouldn't let us see a negative elapsed time */
+ test_eq(elapsed, 0);
+
+ done:
+ if (r) replaycache_free(r);
+
+ return;
+}
+
+static void
+test_replaycache_realtime(void)
+{
+ replaycache_t *r = NULL;
+ /*
+ * Negative so we fail if replaycache_add_test_and_elapsed() doesn't
+ * write to elapsed.
+ */
+ time_t elapsed = -1;
+ int result;
+
+ /* Test the realtime as well as *_internal() entry points */
+ r = replaycache_new(600, 300);
+ test_assert(r != NULL);
+
+ /* This should miss */
+ result =
+ replaycache_add_and_test(r, test_buffer, (int)strlen(test_buffer));
+ test_eq(result, 0);
+
+ /* This should hit */
+ result =
+ replaycache_add_and_test(r, test_buffer, (int)strlen(test_buffer));
+ test_eq(result, 1);
+
+ /* This should hit and return a small elapsed time */
+ result =
+ replaycache_add_test_and_elapsed(r, test_buffer,
+ (int)strlen(test_buffer), &elapsed);
+ test_eq(result, 1);
+ test_assert(elapsed >= 0);
+ test_assert(elapsed <= 5);
+
+ /* Scrub it to exercise that entry point too */
+ replaycache_scrub_if_needed(r);
+
+ done:
+ if (r) replaycache_free(r);
+ return;
+}
+
#define REPLAYCACHE_LEGACY(name) \
{ #name, legacy_test_helper, 0, &legacy_setup, test_replaycache_ ## name }
struct testcase_t replaycache_tests[] = {
REPLAYCACHE_LEGACY(alloc),
+ REPLAYCACHE_LEGACY(badalloc),
+ REPLAYCACHE_LEGACY(free_null),
REPLAYCACHE_LEGACY(miss),
REPLAYCACHE_LEGACY(hit),
REPLAYCACHE_LEGACY(age),
REPLAYCACHE_LEGACY(elapsed),
REPLAYCACHE_LEGACY(noexpire),
+ REPLAYCACHE_LEGACY(scrub),
+ REPLAYCACHE_LEGACY(future),
+ REPLAYCACHE_LEGACY(realtime),
END_OF_TESTCASES
};
diff --git a/src/test/test_util.c b/src/test/test_util.c
index 6e1ee713d..2cc25e986 100644
--- a/src/test/test_util.c
+++ b/src/test/test_util.c
@@ -796,6 +796,64 @@ test_util_expand_filename(void)
}
#endif
+/** Test tor_escape_str_for_socks_arg(). */
+static void
+test_util_escape_string_socks(void)
+{
+ char *escaped_string = NULL;
+
+ /** Simple backslash escape. */
+ escaped_string = tor_escape_str_for_socks_arg("This is a backslash: \\");
+ test_assert(escaped_string);
+ test_streq(escaped_string, "This is a backslash: \\\\");
+ tor_free(escaped_string);
+
+ /** Simple semicolon escape. */
+ escaped_string = tor_escape_str_for_socks_arg("First rule: Do not use ;");
+ test_assert(escaped_string);
+ test_streq(escaped_string, "First rule: Do not use \\;");
+ tor_free(escaped_string);
+
+ /** Empty string. */
+ escaped_string = tor_escape_str_for_socks_arg("");
+ test_assert(escaped_string);
+ test_streq(escaped_string, "");
+ tor_free(escaped_string);
+
+ /** Escape all characters. */
+ escaped_string = tor_escape_str_for_socks_arg(";\\;\\");
+ test_assert(escaped_string);
+ test_streq(escaped_string, "\\;\\\\\\;\\\\");
+ tor_free(escaped_string);
+
+ escaped_string = tor_escape_str_for_socks_arg(";");
+ test_assert(escaped_string);
+ test_streq(escaped_string, "\\;");
+ tor_free(escaped_string);
+
+ done:
+ tor_free(escaped_string);
+}
+
+static void
+test_util_string_is_key_value(void *ptr)
+{
+ (void)ptr;
+ test_assert(string_is_key_value(LOG_WARN, "key=value"));
+ test_assert(string_is_key_value(LOG_WARN, "k=v"));
+ test_assert(string_is_key_value(LOG_WARN, "key="));
+ test_assert(string_is_key_value(LOG_WARN, "x="));
+ test_assert(string_is_key_value(LOG_WARN, "xx="));
+ test_assert(!string_is_key_value(LOG_WARN, "=value"));
+ test_assert(!string_is_key_value(LOG_WARN, "=x"));
+ test_assert(!string_is_key_value(LOG_WARN, "="));
+
+ /* ??? */
+ /* test_assert(!string_is_key_value(LOG_WARN, "===")); */
+ done:
+ ;
+}
+
/** Test basic string functionality. */
static void
test_util_strmisc(void)
@@ -2223,6 +2281,7 @@ test_util_load_win_lib(void *ptr)
}
#endif
+#ifndef _WIN32
static void
clear_hex_errno(char *hex_errno)
{
@@ -2266,6 +2325,7 @@ test_util_exit_status(void *ptr)
done:
;
}
+#endif
#ifndef _WIN32
/** Check that fgets waits until a full line, and not return a partial line, on
@@ -2567,14 +2627,14 @@ test_util_spawn_background_partial_read(void *ptr)
}
/**
- * Test for format_hex_number_for_helper_exit_status()
+ * Test for format_hex_number_sigsafe()
*/
static void
test_util_format_hex_number(void *ptr)
{
int i, len;
- char buf[HEX_ERRNO_SIZE + 1];
+ char buf[33];
const struct {
const char *str;
unsigned int x;
@@ -2583,6 +2643,8 @@ test_util_format_hex_number(void *ptr)
{"1", 1},
{"273A", 0x273a},
{"FFFF", 0xffff},
+ {"7FFFFFFF", 0x7fffffff},
+ {"FFFFFFFF", 0xffffffff},
#if UINT_MAX >= 0xffffffff
{"31BC421D", 0x31bc421d},
{"FFFFFFFF", 0xffffffff},
@@ -2593,19 +2655,23 @@ test_util_format_hex_number(void *ptr)
(void)ptr;
for (i = 0; test_data[i].str != NULL; ++i) {
- len = format_hex_number_for_helper_exit_status(test_data[i].x,
- buf, HEX_ERRNO_SIZE);
+ len = format_hex_number_sigsafe(test_data[i].x, buf, sizeof(buf));
test_neq(len, 0);
- buf[len] = '\0';
+ test_eq(len, strlen(buf));
test_streq(buf, test_data[i].str);
}
+ test_eq(4, format_hex_number_sigsafe(0xffff, buf, 5));
+ test_streq(buf, "FFFF");
+ test_eq(0, format_hex_number_sigsafe(0xffff, buf, 4));
+ test_eq(0, format_hex_number_sigsafe(0, buf, 1));
+
done:
return;
}
/**
- * Test that we can properly format q Windows command line
+ * Test that we can properly format a Windows command line
*/
static void
test_util_join_win_cmdline(void *ptr)
@@ -2816,7 +2882,7 @@ test_util_eat_whitespace(void *ptr)
(void)ptr;
/* Try one leading ws */
- strcpy(str, "fuubaar");
+ strlcpy(str, "fuubaar", sizeof(str));
for (i = 0; i < sizeof(ws); ++i) {
str[0] = ws[i];
test_eq_ptr(str + 1, eat_whitespace(str));
@@ -2831,14 +2897,14 @@ test_util_eat_whitespace(void *ptr)
test_eq_ptr(str, eat_whitespace_eos_no_nl(str, str + strlen(str)));
/* Empty string */
- strcpy(str, "");
+ strlcpy(str, "", sizeof(str));
test_eq_ptr(str, eat_whitespace(str));
test_eq_ptr(str, eat_whitespace_eos(str, str));
test_eq_ptr(str, eat_whitespace_no_nl(str));
test_eq_ptr(str, eat_whitespace_eos_no_nl(str, str));
/* Only ws */
- strcpy(str, " \t\r\n");
+ strlcpy(str, " \t\r\n", sizeof(str));
test_eq_ptr(str + strlen(str), eat_whitespace(str));
test_eq_ptr(str + strlen(str), eat_whitespace_eos(str, str + strlen(str)));
test_eq_ptr(str + strlen(str) - 1,
@@ -2846,7 +2912,7 @@ test_util_eat_whitespace(void *ptr)
test_eq_ptr(str + strlen(str) - 1,
eat_whitespace_eos_no_nl(str, str + strlen(str)));
- strcpy(str, " \t\r ");
+ strlcpy(str, " \t\r ", sizeof(str));
test_eq_ptr(str + strlen(str), eat_whitespace(str));
test_eq_ptr(str + strlen(str),
eat_whitespace_eos(str, str + strlen(str)));
@@ -2855,7 +2921,7 @@ test_util_eat_whitespace(void *ptr)
eat_whitespace_eos_no_nl(str, str + strlen(str)));
/* Multiple ws */
- strcpy(str, "fuubaar");
+ strlcpy(str, "fuubaar", sizeof(str));
for (i = 0; i < sizeof(ws); ++i)
str[i] = ws[i];
test_eq_ptr(str + sizeof(ws), eat_whitespace(str));
@@ -2865,28 +2931,28 @@ test_util_eat_whitespace(void *ptr)
eat_whitespace_eos_no_nl(str, str + strlen(str)));
/* Eat comment */
- strcpy(str, "# Comment \n No Comment");
+ strlcpy(str, "# Comment \n No Comment", sizeof(str));
test_streq("No Comment", eat_whitespace(str));
test_streq("No Comment", eat_whitespace_eos(str, str + strlen(str)));
test_eq_ptr(str, eat_whitespace_no_nl(str));
test_eq_ptr(str, eat_whitespace_eos_no_nl(str, str + strlen(str)));
/* Eat comment & ws mix */
- strcpy(str, " # \t Comment \n\t\nNo Comment");
+ strlcpy(str, " # \t Comment \n\t\nNo Comment", sizeof(str));
test_streq("No Comment", eat_whitespace(str));
test_streq("No Comment", eat_whitespace_eos(str, str + strlen(str)));
test_eq_ptr(str + 1, eat_whitespace_no_nl(str));
test_eq_ptr(str + 1, eat_whitespace_eos_no_nl(str, str + strlen(str)));
/* Eat entire comment */
- strcpy(str, "#Comment");
+ strlcpy(str, "#Comment", sizeof(str));
test_eq_ptr(str + strlen(str), eat_whitespace(str));
test_eq_ptr(str + strlen(str), eat_whitespace_eos(str, str + strlen(str)));
test_eq_ptr(str, eat_whitespace_no_nl(str));
test_eq_ptr(str, eat_whitespace_eos_no_nl(str, str + strlen(str)));
/* Blank line, then comment */
- strcpy(str, " \t\n # Comment");
+ strlcpy(str, " \t\n # Comment", sizeof(str));
test_eq_ptr(str + strlen(str), eat_whitespace(str));
test_eq_ptr(str + strlen(str), eat_whitespace_eos(str, str + strlen(str)));
test_eq_ptr(str + 2, eat_whitespace_no_nl(str));
@@ -3211,6 +3277,42 @@ test_util_mathlog(void *arg)
;
}
+static void
+test_util_round_to_next_multiple_of(void *arg)
+{
+ (void)arg;
+
+ test_assert(round_uint64_to_next_multiple_of(0,1) == 0);
+ test_assert(round_uint64_to_next_multiple_of(0,7) == 0);
+
+ test_assert(round_uint64_to_next_multiple_of(99,1) == 99);
+ test_assert(round_uint64_to_next_multiple_of(99,7) == 105);
+ test_assert(round_uint64_to_next_multiple_of(99,9) == 99);
+
+ done:
+ ;
+}
+
+static void
+test_util_strclear(void *arg)
+{
+ static const char *vals[] = { "", "a", "abcdef", "abcdefgh", NULL };
+ int i;
+ char *v = NULL;
+ (void)arg;
+
+ for (i = 0; vals[i]; ++i) {
+ size_t n;
+ v = tor_strdup(vals[i]);
+ n = strlen(v);
+ tor_strclear(v);
+ tt_assert(tor_mem_is_zero(v, n+1));
+ tor_free(v);
+ }
+ done:
+ tor_free(v);
+}
+
#define UTIL_LEGACY(name) \
{ #name, legacy_test_helper, 0, &legacy_setup, test_util_ ## name }
@@ -3227,6 +3329,8 @@ struct testcase_t util_tests[] = {
#ifndef _WIN32
UTIL_LEGACY(expand_filename),
#endif
+ UTIL_LEGACY(escape_string_socks),
+ UTIL_LEGACY(string_is_key_value),
UTIL_LEGACY(strmisc),
UTIL_LEGACY(pow2),
UTIL_LEGACY(gzip),
@@ -3240,6 +3344,8 @@ struct testcase_t util_tests[] = {
UTIL_LEGACY(path_is_relative),
UTIL_LEGACY(strtok),
UTIL_LEGACY(di_ops),
+ UTIL_TEST(round_to_next_multiple_of, 0),
+ UTIL_TEST(strclear, 0),
UTIL_TEST(find_str_at_start_of_line, 0),
UTIL_TEST(string_is_C_identifier, 0),
UTIL_TEST(asprintf, 0),
@@ -3248,8 +3354,8 @@ struct testcase_t util_tests[] = {
#ifdef _WIN32
UTIL_TEST(load_win_lib, 0),
#endif
- UTIL_TEST(exit_status, 0),
#ifndef _WIN32
+ UTIL_TEST(exit_status, 0),
UTIL_TEST(fgets_eagain, TT_SKIP),
#endif
UTIL_TEST(spawn_background_ok, 0),
diff --git a/src/tools/tor-checkkey.c b/src/tools/tor-checkkey.c
index a3860ca4b..d50f12ed2 100644
--- a/src/tools/tor-checkkey.c
+++ b/src/tools/tor-checkkey.c
@@ -1,8 +1,6 @@
/* Copyright (c) 2008-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-#define CRYPTO_PRIVATE
-
#include "orconfig.h"
#include <stdio.h>
diff --git a/src/tools/tor-fw-helper/tor-fw-helper.c b/src/tools/tor-fw-helper/tor-fw-helper.c
index bb6e70aaa..84cc21e34 100644
--- a/src/tools/tor-fw-helper/tor-fw-helper.c
+++ b/src/tools/tor-fw-helper/tor-fw-helper.c
@@ -496,6 +496,6 @@ main(int argc, char **argv)
smartlist_free(tor_fw_options.ports_to_forward);
}
- exit(r);
+ exit(0);
}
diff --git a/src/tools/tor-gencert.c b/src/tools/tor-gencert.c
index 3809b22d4..25beb2aae 100644
--- a/src/tools/tor-gencert.c
+++ b/src/tools/tor-gencert.c
@@ -27,8 +27,6 @@
#include <assert.h>
#endif
-#define CRYPTO_PRIVATE
-
#include "compat.h"
#include "../common/util.h"
#include "../common/torlog.h"
diff --git a/src/win32/orconfig.h b/src/win32/orconfig.h
index f5d5cf446..43f68c3b0 100644
--- a/src/win32/orconfig.h
+++ b/src/win32/orconfig.h
@@ -241,7 +241,7 @@
#define USING_TWOS_COMPLEMENT
/* Version number of package */
-#define VERSION "0.2.4.10-alpha-dev"
+#define VERSION "0.2.5.0-alpha-dev"