aboutsummaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
Diffstat (limited to 'src/test')
-rw-r--r--src/test/Makefile.nmake7
-rw-r--r--src/test/bench.c28
-rwxr-xr-xsrc/test/bt_test.py42
-rw-r--r--src/test/include.am69
-rwxr-xr-x[-rw-r--r--]src/test/ntor_ref.py72
-rw-r--r--src/test/slownacl_curve25519.py117
-rwxr-xr-xsrc/test/test-network.sh47
-rw-r--r--src/test/test.c1316
-rw-r--r--src/test/test.h127
-rw-r--r--src/test/test_addr.c194
-rw-r--r--src/test/test_bt_cl.c109
-rw-r--r--src/test/test_buffers.c732
-rw-r--r--src/test/test_cell_formats.c385
-rw-r--r--src/test/test_cell_queue.c158
-rw-r--r--src/test/test_circuitlist.c342
-rw-r--r--src/test/test_circuitmux.c88
-rwxr-xr-xsrc/test/test_cmdline_args.py292
-rw-r--r--src/test/test_config.c427
-rw-r--r--src/test/test_containers.c59
-rw-r--r--src/test/test_controller_events.c307
-rw-r--r--src/test/test_crypto.c244
-rw-r--r--src/test/test_data.c185
-rw-r--r--src/test/test_dir.c208
-rw-r--r--src/test/test_extorport.c607
-rw-r--r--src/test/test_hs.c129
-rw-r--r--src/test/test_logging.c135
-rw-r--r--src/test/test_microdesc.c108
-rw-r--r--src/test/test_nodelist.c71
-rw-r--r--src/test/test_oom.c372
-rw-r--r--src/test/test_options.c170
-rw-r--r--src/test/test_policy.c437
-rw-r--r--src/test/test_pt.c358
-rw-r--r--src/test/test_relaycell.c249
-rw-r--r--src/test/test_replay.c192
-rw-r--r--src/test/test_routerkeys.c85
-rw-r--r--src/test/test_socks.c393
-rw-r--r--src/test/test_status.c1114
-rw-r--r--src/test/test_util.c551
38 files changed, 9111 insertions, 1415 deletions
diff --git a/src/test/Makefile.nmake b/src/test/Makefile.nmake
index 562c8df8b..822431f3b 100644
--- a/src/test/Makefile.nmake
+++ b/src/test/Makefile.nmake
@@ -12,9 +12,10 @@ LIBS = ..\..\..\build-alpha\lib\libevent.lib \
crypt32.lib gdi32.lib user32.lib
TEST_OBJECTS = test.obj test_addr.obj test_containers.obj \
- test_crypto.obj test_data.obj test_dir.obj test_microdesc.obj \
- test_pt.obj test_util.obj test_config.obj test_cell_formats.obj \
- test_replay.obj test_introduce.obj tinytest.obj
+ test_controller_events.ogj test_crypto.obj test_data.obj test_dir.obj \
+ test_microdesc.obj test_pt.obj test_util.obj test_config.obj \
+ test_cell_formats.obj test_replay.obj test_introduce.obj tinytest.obj \
+ test_hs.obj
tinytest.obj: ..\ext\tinytest.c
$(CC) $(CFLAGS) /D snprintf=_snprintf /c ..\ext\tinytest.c
diff --git a/src/test/bench.c b/src/test/bench.c
index 706b8bc7f..f6c33626f 100644
--- a/src/test/bench.c
+++ b/src/test/bench.c
@@ -14,9 +14,6 @@ const char tor_git_revision[] = "";
#include "orconfig.h"
-#define RELAY_PRIVATE
-#define CONFIG_PRIVATE
-
#include "or.h"
#include "onion_tap.h"
#include "relay.h"
@@ -204,6 +201,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);
@@ -340,6 +338,28 @@ bench_dmap(void)
}
static void
+bench_siphash(void)
+{
+ char buf[128];
+ int lens[] = { 7, 8, 15, 16, 20, 32, 111, 128, -1 };
+ int i, j;
+ uint64_t start, end;
+ const int N = 300000;
+ crypto_rand(buf, sizeof(buf));
+
+ for (i = 0; lens[i] > 0; ++i) {
+ reset_perftime();
+ start = perftime();
+ for (j = 0; j < N; ++j) {
+ siphash24g(buf, lens[i]);
+ }
+ end = perftime();
+ printf("siphash24g(%d): %.2f ns per call\n",
+ lens[i], NANOCOUNT(start,end,N));
+ }
+}
+
+static void
bench_cell_ops(void)
{
const int iters = 1<<16;
@@ -489,6 +509,7 @@ typedef struct benchmark_t {
static struct benchmark_t benchmarks[] = {
ENT(dmap),
+ ENT(siphash),
ENT(aes),
ENT(onion_TAP),
#ifdef CURVE25519_ENABLED
@@ -546,6 +567,7 @@ main(int argc, const char **argv)
reset_perftime();
crypto_seed_rng(1);
+ crypto_init_siphash_key();
options = options_new();
init_logging();
options->command = CMD_RUN_UNITTESTS;
diff --git a/src/test/bt_test.py b/src/test/bt_test.py
new file mode 100755
index 000000000..8290509fa
--- /dev/null
+++ b/src/test/bt_test.py
@@ -0,0 +1,42 @@
+# Copyright 2013, The Tor Project, Inc
+# See LICENSE for licensing information
+
+"""
+bt_test.py
+
+This file tests the output from test-bt-cl to make sure it's as expected.
+
+Example usage:
+
+$ ./src/test/test-bt-cl crash | ./src/test/bt_test.py
+OK
+$ ./src/test/test-bt-cl assert | ./src/test/bt_test.py
+OK
+
+"""
+
+import sys
+
+
+def matches(lines, funcs):
+ if len(lines) < len(funcs):
+ return False
+ try:
+ for l, f in zip(lines, funcs):
+ l.index(f)
+ except ValueError:
+ return False
+ else:
+ return True
+
+FUNCNAMES = "crash oh_what a_tangled_web we_weave main".split()
+
+LINES = sys.stdin.readlines()
+
+for I in range(len(LINES)):
+ if matches(LINES[I:], FUNCNAMES):
+ print("OK")
+ break
+else:
+ print("BAD")
+
diff --git a/src/test/include.am b/src/test/include.am
index 112d1a79d..fba439a61 100644
--- a/src/test/include.am
+++ b/src/test/include.am
@@ -1,11 +1,15 @@
-TESTS+= src/test/test
+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
@@ -14,31 +18,47 @@ src_test_AM_CPPFLAGS = -DSHARE_DATADIR="\"$(datadir)\"" \
src_test_test_SOURCES = \
src/test/test.c \
src/test/test_addr.c \
+ src/test/test_buffers.c \
src/test/test_cell_formats.c \
+ src/test/test_circuitlist.c \
+ src/test/test_circuitmux.c \
src/test/test_containers.c \
+ src/test/test_controller_events.c \
src/test/test_crypto.c \
+ src/test/test_cell_queue.c \
src/test/test_data.c \
src/test/test_dir.c \
+ src/test/test_extorport.c \
src/test/test_introduce.c \
+ src/test/test_logging.c \
src/test/test_microdesc.c \
+ src/test/test_oom.c \
+ src/test/test_options.c \
src/test/test_pt.c \
+ src/test/test_relaycell.c \
src/test/test_replay.c \
+ src/test/test_routerkeys.c \
+ src/test/test_socks.c \
src/test/test_util.c \
src/test/test_config.c \
+ src/test/test_hs.c \
+ src/test/test_nodelist.c \
+ src/test/test_policy.c \
+ src/test/test_status.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 = \
src/test/bench.c
-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@
@@ -63,6 +83,39 @@ src_test_test_ntor_cl_LDADD = src/or/libtor.a src/common/libor.a \
@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
src_test_test_ntor_cl_AM_CPPFLAGS = \
-I"$(top_srcdir)/src/or"
+NTOR_TEST_DEPS=src/test/test-ntor-cl
+else
+NTOR_TEST_DEPS=
+endif
+if COVERAGE_ENABLED
+CMDLINE_TEST_TOR = ./src/or/tor-cov
+else
+CMDLINE_TEST_TOR = ./src/or/tor
+endif
+
+noinst_PROGRAMS += src/test/test-bt-cl
+src_test_test_bt_cl_SOURCES = src/test/test_bt_cl.c
+src_test_test_bt_cl_LDADD = src/common/libor-testing.a \
+ @TOR_LIB_MATH@ \
+ @TOR_LIB_WS32@ @TOR_LIB_GDI@
+src_test_test_bt_cl_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+src_test_test_bt_cl_CPPFLAGS= $(src_test_AM_CPPFLAGS)
+
+
+check-local: $(NTOR_TEST_DEPS) $(CMDLINE_TEST_TOR)
+if USEPYTHON
+ $(PYTHON) $(top_srcdir)/src/test/test_cmdline_args.py $(CMDLINE_TEST_TOR) "${top_srcdir}"
+if CURVE25519_ENABLED
+ $(PYTHON) $(top_srcdir)/src/test/ntor_ref.py test-tor
+ $(PYTHON) $(top_srcdir)/src/test/ntor_ref.py self-test
+endif
+ ./src/test/test-bt-cl assert | $(PYTHON) $(top_srcdir)/src/test/bt_test.py
+ ./src/test/test-bt-cl crash | $(PYTHON) $(top_srcdir)/src/test/bt_test.py
endif
+EXTRA_DIST += \
+ src/test/bt_test.py \
+ src/test/ntor_ref.py \
+ src/test/slownacl_curve25519.py \
+ src/test/test_cmdline_args.py
diff --git a/src/test/ntor_ref.py b/src/test/ntor_ref.py
index ade468da7..7d6e43e71 100644..100755
--- a/src/test/ntor_ref.py
+++ b/src/test/ntor_ref.py
@@ -1,3 +1,4 @@
+#!/usr/bin/python
# Copyright 2012-2013, The Tor Project, Inc
# See LICENSE for licensing information
@@ -27,17 +28,25 @@ commands:
"""
import binascii
-import curve25519
+try:
+ import curve25519
+ curve25519mod = curve25519.keys
+except ImportError:
+ curve25519 = None
+ import slownacl_curve25519
+ curve25519mod = slownacl_curve25519
+
import hashlib
import hmac
import subprocess
+import sys
# **********************************************************************
# Helpers and constants
def HMAC(key,msg):
"Return the HMAC-SHA256 of 'msg' using the key 'key'."
- H = hmac.new(key, "", hashlib.sha256)
+ H = hmac.new(key, b"", hashlib.sha256)
H.update(msg)
return H.digest()
@@ -59,31 +68,38 @@ G_LENGTH = 32
H_LENGTH = 32
PROTOID = b"ntor-curve25519-sha256-1"
-M_EXPAND = PROTOID + ":key_expand"
-T_MAC = PROTOID + ":mac"
-T_KEY = PROTOID + ":key_extract"
-T_VERIFY = PROTOID + ":verify"
+M_EXPAND = PROTOID + b":key_expand"
+T_MAC = PROTOID + b":mac"
+T_KEY = PROTOID + b":key_extract"
+T_VERIFY = PROTOID + b":verify"
def H_mac(msg): return H(msg, tweak=T_MAC)
def H_verify(msg): return H(msg, tweak=T_VERIFY)
-class PrivateKey(curve25519.keys.Private):
- """As curve25519.keys.Private, but doesn't regenerate its public key
+class PrivateKey(curve25519mod.Private):
+ """As curve25519mod.Private, but doesn't regenerate its public key
every time you ask for it.
"""
def __init__(self):
- curve25519.keys.Private.__init__(self)
+ curve25519mod.Private.__init__(self)
self._memo_public = None
def get_public(self):
if self._memo_public is None:
- self._memo_public = curve25519.keys.Private.get_public(self)
+ self._memo_public = curve25519mod.Private.get_public(self)
return self._memo_public
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-def kdf_rfc5869(key, salt, info, n):
+if sys.version < '3':
+ def int2byte(i):
+ return chr(i)
+else:
+ def int2byte(i):
+ return bytes([i])
+
+def kdf_rfc5869(key, salt, info, n):
prk = HMAC(key=salt, msg=key)
@@ -91,7 +107,7 @@ def kdf_rfc5869(key, salt, info, n):
last = b""
i = 1
while len(out) < n:
- m = last + info + chr(i)
+ m = last + info + int2byte(i)
last = h = HMAC(key=prk, msg=m)
out += h
i = i + 1
@@ -177,7 +193,7 @@ def server(seckey_b, my_node_id, message, keyBytes=72):
badness = (keyid(seckey_b.get_public()) !=
message[NODE_ID_LENGTH:NODE_ID_LENGTH+H_LENGTH])
- pubkey_X = curve25519.keys.Public(message[NODE_ID_LENGTH+H_LENGTH:])
+ pubkey_X = curve25519mod.Public(message[NODE_ID_LENGTH+H_LENGTH:])
seckey_y = PrivateKey()
pubkey_Y = seckey_y.get_public()
pubkey_B = seckey_b.get_public()
@@ -200,7 +216,7 @@ def server(seckey_b, my_node_id, message, keyBytes=72):
pubkey_Y.serialize() +
pubkey_X.serialize() +
PROTOID +
- "Server")
+ b"Server")
msg = pubkey_Y.serialize() + H_mac(auth_input)
@@ -240,7 +256,7 @@ def client_part2(seckey_x, msg, node_id, pubkey_B, keyBytes=72):
"""
assert len(msg) == G_LENGTH + H_LENGTH
- pubkey_Y = curve25519.keys.Public(msg[:G_LENGTH])
+ pubkey_Y = curve25519mod.Public(msg[:G_LENGTH])
their_auth = msg[G_LENGTH:]
pubkey_X = seckey_x.get_public()
@@ -262,7 +278,7 @@ def client_part2(seckey_x, msg, node_id, pubkey_B, keyBytes=72):
pubkey_B.serialize() +
pubkey_Y.serialize() +
pubkey_X.serialize() + PROTOID +
- "Server")
+ b"Server")
my_auth = H_mac(auth_input)
@@ -276,7 +292,7 @@ def client_part2(seckey_x, msg, node_id, pubkey_B, keyBytes=72):
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-def demo(node_id="iToldYouAboutStairs.", server_key=PrivateKey()):
+def demo(node_id=b"iToldYouAboutStairs.", server_key=PrivateKey()):
"""
Try to handshake with ourself.
"""
@@ -286,6 +302,7 @@ def demo(node_id="iToldYouAboutStairs.", server_key=PrivateKey()):
assert len(skeys) == 72
assert len(ckeys) == 72
assert skeys == ckeys
+ print("OK")
# ======================================================================
def timing():
@@ -295,7 +312,7 @@ def timing():
import timeit
t = timeit.Timer(stmt="ntor_ref.demo(N,SK)",
setup="import ntor_ref,curve25519;N='ABCD'*5;SK=ntor_ref.PrivateKey()")
- print t.timeit(number=1000)
+ print(t.timeit(number=1000))
# ======================================================================
@@ -306,7 +323,7 @@ def kdf_vectors():
import binascii
def kdf_vec(inp):
k = kdf(inp, T_KEY, M_EXPAND, 100)
- print repr(inp), "\n\""+ binascii.b2a_hex(k)+ "\""
+ print(repr(inp), "\n\""+ binascii.b2a_hex(k)+ "\"")
kdf_vec("")
kdf_vec("Tor")
kdf_vec("AN ALARMING ITEM TO FIND ON YOUR CREDIT-RATING STATEMENT")
@@ -319,13 +336,13 @@ def test_tor():
Call the test-ntor-cl command-line program to make sure we can
interoperate with Tor's ntor program
"""
- enhex=binascii.b2a_hex
+ enhex=lambda s: binascii.b2a_hex(s)
dehex=lambda s: binascii.a2b_hex(s.strip())
- PROG = "./src/test/test-ntor-cl"
+ PROG = b"./src/test/test-ntor-cl"
def tor_client1(node_id, pubkey_B):
" returns (msg, state) "
- p = subprocess.Popen([PROG, "client1", enhex(node_id),
+ p = subprocess.Popen([PROG, b"client1", enhex(node_id),
enhex(pubkey_B.serialize())],
stdout=subprocess.PIPE)
return map(dehex, p.stdout.readlines())
@@ -343,7 +360,7 @@ def test_tor():
return map(dehex, p.stdout.readlines())
- node_id = "thisisatornodeid$#%^"
+ node_id = b"thisisatornodeid$#%^"
seckey_b = PrivateKey()
pubkey_B = seckey_b.get_public()
@@ -368,13 +385,14 @@ def test_tor():
assert c_keys == s_keys
assert len(c_keys) == 90
- print "We just interoperated."
+ print("OK")
# ======================================================================
if __name__ == '__main__':
- import sys
- if sys.argv[1] == 'gen_kdf_vectors':
+ if len(sys.argv) < 2:
+ print(__doc__)
+ elif sys.argv[1] == 'gen_kdf_vectors':
kdf_vectors()
elif sys.argv[1] == 'timing':
timing()
@@ -384,4 +402,4 @@ if __name__ == '__main__':
test_tor()
else:
- print __doc__
+ print(__doc__)
diff --git a/src/test/slownacl_curve25519.py b/src/test/slownacl_curve25519.py
new file mode 100644
index 000000000..4dabab61b
--- /dev/null
+++ b/src/test/slownacl_curve25519.py
@@ -0,0 +1,117 @@
+# This is the curve25519 implementation from Matthew Dempsky's "Slownacl"
+# library. It is in the public domain.
+#
+# It isn't constant-time. Don't use it except for testing.
+#
+# Nick got the slownacl source from:
+# https://github.com/mdempsky/dnscurve/tree/master/slownacl
+
+__all__ = ['smult_curve25519_base', 'smult_curve25519']
+
+import sys
+
+P = 2 ** 255 - 19
+A = 486662
+
+def expmod(b, e, m):
+ if e == 0: return 1
+ t = expmod(b, e // 2, m) ** 2 % m
+ if e & 1: t = (t * b) % m
+ return t
+
+def inv(x):
+ return expmod(x, P - 2, P)
+
+# Addition and doubling formulas taken from Appendix D of "Curve25519:
+# new Diffie-Hellman speed records".
+
+def add(n,m,d):
+ (xn,zn), (xm,zm), (xd,zd) = n, m, d
+ x = 4 * (xm * xn - zm * zn) ** 2 * zd
+ z = 4 * (xm * zn - zm * xn) ** 2 * xd
+ return (x % P, z % P)
+
+def double(n):
+ (xn,zn) = n
+ x = (xn ** 2 - zn ** 2) ** 2
+ z = 4 * xn * zn * (xn ** 2 + A * xn * zn + zn ** 2)
+ return (x % P, z % P)
+
+def curve25519(n, base):
+ one = (base,1)
+ two = double(one)
+ # f(m) evaluates to a tuple containing the mth multiple and the
+ # (m+1)th multiple of base.
+ def f(m):
+ if m == 1: return (one, two)
+ (pm, pm1) = f(m // 2)
+ if (m & 1):
+ return (add(pm, pm1, one), double(pm1))
+ return (double(pm), add(pm, pm1, one))
+ ((x,z), _) = f(n)
+ return (x * inv(z)) % P
+
+if sys.version < '3':
+ def b2i(c):
+ return ord(c)
+ def i2b(i):
+ return chr(i)
+ def ba2bs(ba):
+ return "".join(ba)
+else:
+ def b2i(c):
+ return c
+ def i2b(i):
+ return i
+ def ba2bs(ba):
+ return bytes(ba)
+
+def unpack(s):
+ if len(s) != 32: raise ValueError('Invalid Curve25519 argument')
+ return sum(b2i(s[i]) << (8 * i) for i in range(32))
+
+def pack(n):
+ return ba2bs([i2b((n >> (8 * i)) & 255) for i in range(32)])
+
+def clamp(n):
+ n &= ~7
+ n &= ~(128 << 8 * 31)
+ n |= 64 << 8 * 31
+ return n
+
+def smult_curve25519(n, p):
+ n = clamp(unpack(n))
+ p = unpack(p)
+ return pack(curve25519(n, p))
+
+def smult_curve25519_base(n):
+ n = clamp(unpack(n))
+ return pack(curve25519(n, 9))
+
+
+#
+# This part I'm adding in for compatibility with the curve25519 python
+# module. -Nick
+#
+import os
+
+class Private:
+ def __init__(self, secret=None, seed=None):
+ self.private = pack(clamp(unpack(os.urandom(32))))
+
+ def get_public(self):
+ return Public(smult_curve25519_base(self.private))
+
+ def get_shared_key(self, public, hashfn):
+ return hashfn(smult_curve25519(self.private, public.public))
+
+ def serialize(self):
+ return self.private
+
+class Public:
+ def __init__(self, public):
+ self.public = public
+
+ def serialize(self):
+ return self.public
+
diff --git a/src/test/test-network.sh b/src/test/test-network.sh
new file mode 100755
index 000000000..7b5986416
--- /dev/null
+++ b/src/test/test-network.sh
@@ -0,0 +1,47 @@
+#! /bin/sh
+
+until [ -z $1 ]
+do
+ case $1 in
+ --chutney-path)
+ export CHUTNEY_PATH="$2"
+ shift
+ ;;
+ --tor-path)
+ export TOR_DIR="$2"
+ shift
+ ;;
+ --flavo?r|--network-flavo?r)
+ export NETWORK_FLAVOUR="$2"
+ shift
+ ;;
+ *)
+ echo "Sorry, I don't know what to do with '$1'."
+ exit 2
+ ;;
+ esac
+ shift
+done
+
+TOR_DIR="${TOR_DIR:-$PWD}"
+NETWORK_FLAVOUR=${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"
+# For picking up the right tor binaries.
+PATH="$TOR_DIR/src/or:$TOR_DIR/src/tools:$PATH"
+./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 c2911d842..8bce9c91f 100644
--- a/src/test/test.c
+++ b/src/test/test.c
@@ -28,11 +28,11 @@ 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
+#define CIRCUITLIST_PRIVATE
+#define STATEFILE_PRIVATE
/*
* Linux doesn't provide lround in math.h by default, but mac os does...
@@ -52,16 +52,20 @@ double fabs(double x);
#include "rendcommon.h"
#include "test.h"
#include "torgzip.h"
+#ifdef ENABLE_MEMPOOLS
#include "mempool.h"
+#endif
#include "memarea.h"
#include "onion.h"
-#include "onion_tap.h"
#include "onion_ntor.h"
+#include "onion_tap.h"
#include "policies.h"
#include "rephist.h"
#include "routerparse.h"
+#include "statefile.h"
#ifdef CURVE25519_ENABLED
#include "crypto_curve25519.h"
+#include "onion_ntor.h"
#endif
#ifdef USE_DMALLOC
@@ -218,667 +222,138 @@ free_pregenerated_keys(void)
}
}
-typedef struct socks_test_data_t {
- socks_request_t *req;
- buf_t *buf;
-} socks_test_data_t;
-
-static void *
-socks_test_setup(const struct testcase_t *testcase)
-{
- socks_test_data_t *data = tor_malloc(sizeof(socks_test_data_t));
- (void)testcase;
- data->buf = buf_new_with_capacity(256);
- data->req = socks_request_new();
- config_register_addressmaps(get_options());
- return data;
-}
-static int
-socks_test_cleanup(const struct testcase_t *testcase, void *ptr)
-{
- socks_test_data_t *data = ptr;
- (void)testcase;
- buf_free(data->buf);
- socks_request_free(data->req);
- tor_free(data);
- return 1;
-}
-
-const struct testcase_setup_t socks_setup = {
- socks_test_setup, socks_test_cleanup
-};
-
-#define SOCKS_TEST_INIT() \
- socks_test_data_t *testdata = ptr; \
- buf_t *buf = testdata->buf; \
- socks_request_t *socks = testdata->req;
-#define ADD_DATA(buf, s) \
- write_to_buf(s, sizeof(s)-1, buf)
-
-static void
-socks_request_clear(socks_request_t *socks)
-{
- tor_free(socks->username);
- tor_free(socks->password);
- memset(socks, 0, sizeof(socks_request_t));
-}
-
-/** Perform unsupported SOCKS 4 commands */
-static void
-test_socks_4_unsupported_commands(void *ptr)
-{
- SOCKS_TEST_INIT();
-
- /* SOCKS 4 Send BIND [02] to IP address 2.2.2.2:4369 */
- ADD_DATA(buf, "\x04\x02\x11\x11\x02\x02\x02\x02\x00");
- test_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
- get_options()->SafeSocks) == -1);
- test_eq(4, socks->socks_version);
- test_eq(0, socks->replylen); /* XXX: shouldn't tor reply? */
-
- done:
- ;
-}
-
-/** Perform supported SOCKS 4 commands */
-static void
-test_socks_4_supported_commands(void *ptr)
-{
- SOCKS_TEST_INIT();
-
- test_eq(0, buf_datalen(buf));
-
- /* SOCKS 4 Send CONNECT [01] to IP address 2.2.2.2:4370 */
- ADD_DATA(buf, "\x04\x01\x11\x12\x02\x02\x02\x03\x00");
- test_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
- get_options()->SafeSocks) == 1);
- test_eq(4, socks->socks_version);
- test_eq(0, socks->replylen); /* XXX: shouldn't tor reply? */
- test_eq(SOCKS_COMMAND_CONNECT, socks->command);
- test_streq("2.2.2.3", socks->address);
- test_eq(4370, socks->port);
- test_assert(socks->got_auth == 0);
- test_assert(! socks->username);
-
- test_eq(0, buf_datalen(buf));
- socks_request_clear(socks);
-
- /* SOCKS 4 Send CONNECT [01] to IP address 2.2.2.2:4369 with userid*/
- ADD_DATA(buf, "\x04\x01\x11\x12\x02\x02\x02\x04me\x00");
- test_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
- get_options()->SafeSocks) == 1);
- test_eq(4, socks->socks_version);
- test_eq(0, socks->replylen); /* XXX: shouldn't tor reply? */
- test_eq(SOCKS_COMMAND_CONNECT, socks->command);
- test_streq("2.2.2.4", socks->address);
- test_eq(4370, socks->port);
- test_assert(socks->got_auth == 1);
- test_assert(socks->username);
- test_eq(2, socks->usernamelen);
- test_memeq("me", socks->username, 2);
-
- test_eq(0, buf_datalen(buf));
- socks_request_clear(socks);
-
- /* SOCKS 4a Send RESOLVE [F0] request for torproject.org */
- ADD_DATA(buf, "\x04\xF0\x01\x01\x00\x00\x00\x02me\x00torproject.org\x00");
- test_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
- get_options()->SafeSocks) == 1);
- test_eq(4, socks->socks_version);
- test_eq(0, socks->replylen); /* XXX: shouldn't tor reply? */
- test_streq("torproject.org", socks->address);
-
- test_eq(0, buf_datalen(buf));
-
- done:
- ;
-}
-
-/** Perform unsupported SOCKS 5 commands */
-static void
-test_socks_5_unsupported_commands(void *ptr)
-{
- SOCKS_TEST_INIT();
-
- /* SOCKS 5 Send unsupported BIND [02] command */
- ADD_DATA(buf, "\x05\x02\x00\x01");
-
- test_eq(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
- get_options()->SafeSocks), 0);
- test_eq(0, buf_datalen(buf));
- test_eq(5, socks->socks_version);
- test_eq(2, socks->replylen);
- test_eq(5, socks->reply[0]);
- test_eq(0, socks->reply[1]);
- ADD_DATA(buf, "\x05\x02\x00\x01\x02\x02\x02\x01\x01\x01");
- test_eq(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
- get_options()->SafeSocks), -1);
- /* XXX: shouldn't tor reply 'command not supported' [07]? */
-
- buf_clear(buf);
- socks_request_clear(socks);
-
- /* SOCKS 5 Send unsupported UDP_ASSOCIATE [03] command */
- ADD_DATA(buf, "\x05\x03\x00\x01\x02");
- test_eq(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
- get_options()->SafeSocks), 0);
- test_eq(5, socks->socks_version);
- test_eq(2, socks->replylen);
- test_eq(5, socks->reply[0]);
- test_eq(2, socks->reply[1]);
- ADD_DATA(buf, "\x05\x03\x00\x01\x02\x02\x02\x01\x01\x01");
- test_eq(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
- get_options()->SafeSocks), -1);
- /* XXX: shouldn't tor reply 'command not supported' [07]? */
-
- done:
- ;
-}
-
-/** Perform supported SOCKS 5 commands */
-static void
-test_socks_5_supported_commands(void *ptr)
-{
- SOCKS_TEST_INIT();
-
- /* SOCKS 5 Send CONNECT [01] to IP address 2.2.2.2:4369 */
- ADD_DATA(buf, "\x05\x01\x00");
- test_eq(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
- get_options()->SafeSocks), 0);
- test_eq(5, socks->socks_version);
- test_eq(2, socks->replylen);
- test_eq(5, socks->reply[0]);
- test_eq(0, socks->reply[1]);
-
- ADD_DATA(buf, "\x05\x01\x00\x01\x02\x02\x02\x02\x11\x11");
- test_eq(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
- get_options()->SafeSocks), 1);
- test_streq("2.2.2.2", socks->address);
- test_eq(4369, socks->port);
-
- test_eq(0, buf_datalen(buf));
- socks_request_clear(socks);
-
- /* SOCKS 5 Send CONNECT [01] to FQDN torproject.org:4369 */
- ADD_DATA(buf, "\x05\x01\x00");
- ADD_DATA(buf, "\x05\x01\x00\x03\x0Etorproject.org\x11\x11");
- test_eq(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
- get_options()->SafeSocks), 1);
-
- test_eq(5, socks->socks_version);
- test_eq(2, socks->replylen);
- test_eq(5, socks->reply[0]);
- test_eq(0, socks->reply[1]);
- test_streq("torproject.org", socks->address);
- test_eq(4369, socks->port);
-
- test_eq(0, buf_datalen(buf));
- socks_request_clear(socks);
-
- /* SOCKS 5 Send RESOLVE [F0] request for torproject.org:4369 */
- ADD_DATA(buf, "\x05\x01\x00");
- ADD_DATA(buf, "\x05\xF0\x00\x03\x0Etorproject.org\x01\x02");
- test_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
- get_options()->SafeSocks) == 1);
- test_eq(5, socks->socks_version);
- test_eq(2, socks->replylen);
- test_eq(5, socks->reply[0]);
- test_eq(0, socks->reply[1]);
- test_streq("torproject.org", socks->address);
-
- test_eq(0, buf_datalen(buf));
- socks_request_clear(socks);
-
- /* SOCKS 5 Send RESOLVE_PTR [F1] for IP address 2.2.2.5 */
- ADD_DATA(buf, "\x05\x01\x00");
- ADD_DATA(buf, "\x05\xF1\x00\x01\x02\x02\x02\x05\x01\x03");
- test_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
- get_options()->SafeSocks) == 1);
- test_eq(5, socks->socks_version);
- test_eq(2, socks->replylen);
- test_eq(5, socks->reply[0]);
- test_eq(0, socks->reply[1]);
- test_streq("2.2.2.5", socks->address);
-
- test_eq(0, buf_datalen(buf));
-
- done:
- ;
-}
-
-/** Perform SOCKS 5 authentication */
-static void
-test_socks_5_no_authenticate(void *ptr)
-{
- SOCKS_TEST_INIT();
-
- /*SOCKS 5 No Authentication */
- ADD_DATA(buf,"\x05\x01\x00");
- test_assert(!fetch_from_buf_socks(buf, socks,
- get_options()->TestSocks,
- get_options()->SafeSocks));
- test_eq(2, socks->replylen);
- test_eq(5, socks->reply[0]);
- test_eq(SOCKS_NO_AUTH, socks->reply[1]);
-
- test_eq(0, buf_datalen(buf));
-
- /*SOCKS 5 Send username/password anyway - pretend to be broken */
- ADD_DATA(buf,"\x01\x02\x01\x01\x02\x01\x01");
- test_assert(!fetch_from_buf_socks(buf, socks,
- get_options()->TestSocks,
- get_options()->SafeSocks));
- test_eq(5, socks->socks_version);
- test_eq(2, socks->replylen);
- test_eq(1, socks->reply[0]);
- test_eq(0, socks->reply[1]);
-
- test_eq(2, socks->usernamelen);
- test_eq(2, socks->passwordlen);
-
- test_memeq("\x01\x01", socks->username, 2);
- test_memeq("\x01\x01", socks->password, 2);
-
- done:
- ;
-}
-
-/** Perform SOCKS 5 authentication */
-static void
-test_socks_5_authenticate(void *ptr)
-{
- SOCKS_TEST_INIT();
-
- /* SOCKS 5 Negotiate username/password authentication */
- ADD_DATA(buf, "\x05\x01\x02");
-
- test_assert(!fetch_from_buf_socks(buf, socks,
- get_options()->TestSocks,
- get_options()->SafeSocks));
- test_eq(2, socks->replylen);
- test_eq(5, socks->reply[0]);
- test_eq(SOCKS_USER_PASS, socks->reply[1]);
- test_eq(5, socks->socks_version);
-
- test_eq(0, buf_datalen(buf));
-
- /* SOCKS 5 Send username/password */
- ADD_DATA(buf, "\x01\x02me\x08mypasswd");
- test_assert(!fetch_from_buf_socks(buf, socks,
- get_options()->TestSocks,
- get_options()->SafeSocks));
- test_eq(5, socks->socks_version);
- test_eq(2, socks->replylen);
- test_eq(1, socks->reply[0]);
- test_eq(0, socks->reply[1]);
-
- test_eq(2, socks->usernamelen);
- test_eq(8, socks->passwordlen);
-
- test_memeq("me", socks->username, 2);
- test_memeq("mypasswd", socks->password, 8);
-
- done:
- ;
-}
-
-/** Perform SOCKS 5 authentication and send data all in one go */
-static void
-test_socks_5_authenticate_with_data(void *ptr)
-{
- SOCKS_TEST_INIT();
-
- /* SOCKS 5 Negotiate username/password authentication */
- ADD_DATA(buf, "\x05\x01\x02");
-
- test_assert(!fetch_from_buf_socks(buf, socks,
- get_options()->TestSocks,
- get_options()->SafeSocks));
- test_eq(2, socks->replylen);
- test_eq(5, socks->reply[0]);
- test_eq(SOCKS_USER_PASS, socks->reply[1]);
- test_eq(5, socks->socks_version);
-
- test_eq(0, buf_datalen(buf));
-
- /* SOCKS 5 Send username/password */
- /* SOCKS 5 Send CONNECT [01] to IP address 2.2.2.2:4369 */
- ADD_DATA(buf, "\x01\x02me\x03you\x05\x01\x00\x01\x02\x02\x02\x02\x11\x11");
- test_assert(fetch_from_buf_socks(buf, socks,
- get_options()->TestSocks,
- get_options()->SafeSocks) == 1);
- test_eq(5, socks->socks_version);
- test_eq(2, socks->replylen);
- test_eq(1, socks->reply[0]);
- test_eq(0, socks->reply[1]);
-
- test_streq("2.2.2.2", socks->address);
- test_eq(4369, socks->port);
-
- test_eq(2, socks->usernamelen);
- test_eq(3, socks->passwordlen);
- test_memeq("me", socks->username, 2);
- test_memeq("you", socks->password, 3);
-
- done:
- ;
-}
-
-/** Perform SOCKS 5 authentication before method negotiated */
-static void
-test_socks_5_auth_before_negotiation(void *ptr)
-{
- SOCKS_TEST_INIT();
-
- /* SOCKS 5 Send username/password */
- ADD_DATA(buf, "\x01\x02me\x02me");
- test_assert(fetch_from_buf_socks(buf, socks,
- get_options()->TestSocks,
- get_options()->SafeSocks) == -1);
- test_eq(0, socks->socks_version);
- test_eq(0, socks->replylen);
- test_eq(0, socks->reply[0]);
- test_eq(0, socks->reply[1]);
-
- done:
- ;
-}
-
+/** Run unit tests for the onion handshake code. */
static void
-test_buffer_copy(void *arg)
+test_onion_handshake(void)
{
- generic_buffer_t *buf=NULL, *buf2=NULL;
- const char *s;
- size_t len;
- char b[256];
+ /* 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];
int i;
- (void)arg;
-
- buf = generic_buffer_new();
- tt_assert(buf);
-
- /* Copy an empty buffer. */
- tt_int_op(0, ==, generic_buffer_set_to_copy(&buf2, buf));
- tt_assert(buf2);
- tt_int_op(0, ==, generic_buffer_len(buf2));
-
- /* Now try with a short buffer. */
- s = "And now comes an act of enormous enormance!";
- len = strlen(s);
- generic_buffer_add(buf, s, len);
- tt_int_op(len, ==, generic_buffer_len(buf));
- /* Add junk to buf2 so we can test replacing.*/
- generic_buffer_add(buf2, "BLARG", 5);
- tt_int_op(0, ==, generic_buffer_set_to_copy(&buf2, buf));
- tt_int_op(len, ==, generic_buffer_len(buf2));
- generic_buffer_get(buf2, b, len);
- test_mem_op(b, ==, s, len);
- /* Now free buf2 and retry so we can test allocating */
- generic_buffer_free(buf2);
- buf2 = NULL;
- tt_int_op(0, ==, generic_buffer_set_to_copy(&buf2, buf));
- tt_int_op(len, ==, generic_buffer_len(buf2));
- generic_buffer_get(buf2, b, len);
- test_mem_op(b, ==, s, len);
- /* Clear buf for next test */
- generic_buffer_get(buf, b, len);
- tt_int_op(generic_buffer_len(buf),==,0);
-
- /* Okay, now let's try a bigger buffer. */
- s = "Quis autem vel eum iure reprehenderit qui in ea voluptate velit "
- "esse quam nihil molestiae consequatur, vel illum qui dolorem eum "
- "fugiat quo voluptas nulla pariatur?";
- len = strlen(s);
- for (i = 0; i < 256; ++i) {
- b[0]=i;
- generic_buffer_add(buf, b, 1);
- generic_buffer_add(buf, s, len);
- }
- tt_int_op(0, ==, generic_buffer_set_to_copy(&buf2, buf));
- tt_int_op(generic_buffer_len(buf2), ==, generic_buffer_len(buf));
- for (i = 0; i < 256; ++i) {
- generic_buffer_get(buf2, b, len+1);
- tt_int_op((unsigned char)b[0],==,i);
- test_mem_op(b+1, ==, s, len);
- }
-
- done:
- if (buf)
- generic_buffer_free(buf);
- if (buf2)
- generic_buffer_free(buf2);
-}
-
-/** Run unit tests for buffers.c */
-static void
-test_buffers(void)
-{
- char str[256];
- char str2[256];
-
- buf_t *buf = NULL, *buf2 = NULL;
- const char *cp;
+ /* shared */
+ crypto_pk_t *pk = NULL, *pk2 = NULL;
- int j;
- size_t r;
+ pk = pk_generate(0);
+ pk2 = pk_generate(1);
- /****
- * buf_new
- ****/
- if (!(buf = buf_new()))
- test_fail();
+ /* client handshake 1. */
+ memset(c_buf, 0, TAP_ONIONSKIN_CHALLENGE_LEN);
+ test_assert(! onion_skin_TAP_create(pk, &c_dh, c_buf));
- //test_eq(buf_capacity(buf), 4096);
- test_eq(buf_datalen(buf), 0);
+ 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;
+ }
- /****
- * General pointer frobbing
- */
- for (j=0;j<256;++j) {
- str[j] = (char)j;
- }
- write_to_buf(str, 256, buf);
- write_to_buf(str, 256, buf);
- test_eq(buf_datalen(buf), 512);
- fetch_from_buf(str2, 200, buf);
- test_memeq(str, str2, 200);
- test_eq(buf_datalen(buf), 312);
- memset(str2, 0, sizeof(str2));
-
- fetch_from_buf(str2, 256, buf);
- test_memeq(str+200, str2, 56);
- test_memeq(str, str2+56, 200);
- test_eq(buf_datalen(buf), 56);
- memset(str2, 0, sizeof(str2));
- /* Okay, now we should be 512 bytes into the 4096-byte buffer. If we add
- * another 3584 bytes, we hit the end. */
- for (j=0;j<15;++j) {
- write_to_buf(str, 256, buf);
- }
- assert_buf_ok(buf);
- test_eq(buf_datalen(buf), 3896);
- fetch_from_buf(str2, 56, buf);
- test_eq(buf_datalen(buf), 3840);
- test_memeq(str+200, str2, 56);
- for (j=0;j<15;++j) {
- memset(str2, 0, sizeof(str2));
- fetch_from_buf(str2, 256, buf);
- test_memeq(str, str2, 256);
- }
- test_eq(buf_datalen(buf), 0);
- buf_free(buf);
- buf = NULL;
-
- /* Okay, now make sure growing can work. */
- buf = buf_new_with_capacity(16);
- //test_eq(buf_capacity(buf), 16);
- write_to_buf(str+1, 255, buf);
- //test_eq(buf_capacity(buf), 256);
- fetch_from_buf(str2, 254, buf);
- test_memeq(str+1, str2, 254);
- //test_eq(buf_capacity(buf), 256);
- assert_buf_ok(buf);
- write_to_buf(str, 32, buf);
- //test_eq(buf_capacity(buf), 256);
- assert_buf_ok(buf);
- write_to_buf(str, 256, buf);
- assert_buf_ok(buf);
- //test_eq(buf_capacity(buf), 512);
- test_eq(buf_datalen(buf), 33+256);
- fetch_from_buf(str2, 33, buf);
- test_eq(*str2, str[255]);
-
- test_memeq(str2+1, str, 32);
- //test_eq(buf_capacity(buf), 512);
- test_eq(buf_datalen(buf), 256);
- fetch_from_buf(str2, 256, buf);
- test_memeq(str, str2, 256);
-
- /* now try shrinking: case 1. */
- buf_free(buf);
- buf = buf_new_with_capacity(33668);
- for (j=0;j<67;++j) {
- write_to_buf(str,255, buf);
- }
- //test_eq(buf_capacity(buf), 33668);
- test_eq(buf_datalen(buf), 17085);
- for (j=0; j < 40; ++j) {
- fetch_from_buf(str2, 255,buf);
- test_memeq(str2, str, 255);
- }
+ 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));
- /* now try shrinking: case 2. */
- buf_free(buf);
- buf = buf_new_with_capacity(33668);
- for (j=0;j<67;++j) {
- write_to_buf(str,255, buf);
- }
- for (j=0; j < 20; ++j) {
- fetch_from_buf(str2, 255,buf);
- test_memeq(str2, str, 255);
- }
- for (j=0;j<80;++j) {
- write_to_buf(str,255, buf);
- }
- //test_eq(buf_capacity(buf),33668);
- for (j=0; j < 120; ++j) {
- fetch_from_buf(str2, 255,buf);
- test_memeq(str2, str, 255);
- }
+ /* client handshake 2 */
+ memset(c_keys, 0, 40);
+ test_assert(! onion_skin_TAP_client_handshake(c_dh, s_buf, c_keys, 40));
- /* Move from buf to buf. */
- buf_free(buf);
- buf = buf_new_with_capacity(4096);
- buf2 = buf_new_with_capacity(4096);
- for (j=0;j<100;++j)
- write_to_buf(str, 255, buf);
- test_eq(buf_datalen(buf), 25500);
- for (j=0;j<100;++j) {
- r = 10;
- move_buf_to_buf(buf2, buf, &r);
- test_eq(r, 0);
- }
- test_eq(buf_datalen(buf), 24500);
- test_eq(buf_datalen(buf2), 1000);
- for (j=0;j<3;++j) {
- fetch_from_buf(str2, 255, buf2);
- test_memeq(str2, str, 255);
- }
- r = 8192; /*big move*/
- move_buf_to_buf(buf2, buf, &r);
- test_eq(r, 0);
- r = 30000; /* incomplete move */
- move_buf_to_buf(buf2, buf, &r);
- test_eq(r, 13692);
- for (j=0;j<97;++j) {
- fetch_from_buf(str2, 255, buf2);
- test_memeq(str2, str, 255);
+ test_memeq(c_keys, s_keys, 40);
+ memset(s_buf, 0, 40);
+ test_memneq(c_keys, s_buf, 40);
}
- buf_free(buf);
- buf_free(buf2);
- buf = buf2 = NULL;
-
- buf = buf_new_with_capacity(5);
- cp = "Testing. This is a moderately long Testing string.";
- for (j = 0; cp[j]; j++)
- write_to_buf(cp+j, 1, buf);
- test_eq(0, buf_find_string_offset(buf, "Testing", 7));
- test_eq(1, buf_find_string_offset(buf, "esting", 6));
- test_eq(1, buf_find_string_offset(buf, "est", 3));
- test_eq(39, buf_find_string_offset(buf, "ing str", 7));
- test_eq(35, buf_find_string_offset(buf, "Testing str", 11));
- test_eq(32, buf_find_string_offset(buf, "ng ", 3));
- test_eq(43, buf_find_string_offset(buf, "string.", 7));
- test_eq(-1, buf_find_string_offset(buf, "shrdlu", 6));
- test_eq(-1, buf_find_string_offset(buf, "Testing thing", 13));
- test_eq(-1, buf_find_string_offset(buf, "ngx", 3));
- buf_free(buf);
- buf = NULL;
-
- /* Try adding a string too long for any freelist. */
- {
- char *cp = tor_malloc_zero(65536);
- buf = buf_new();
- write_to_buf(cp, 65536, buf);
- tor_free(cp);
-
- tt_int_op(buf_datalen(buf), ==, 65536);
- buf_free(buf);
- buf = NULL;
- }
-
done:
- if (buf)
- buf_free(buf);
- if (buf2)
- buf_free(buf2);
+ crypto_dh_free(c_dh);
+ crypto_pk_free(pk);
+ crypto_pk_free(pk2);
}
-/** Run unit tests for the onion handshake code. */
static void
-test_onion_handshake(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;
+ crypto_pk_t *pk = NULL, *pk2 = NULL;
+
+ (void)arg;
pk = pk_generate(0);
+ pk2 = pk_generate(1);
- /* client handshake 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 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,
+ /* 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));
- /* client handshake 2 */
- memset(c_keys, 0, 40);
- test_assert(! onion_skin_TAP_client_handshake(c_dh, s_buf, c_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;
- if (memcmp(c_keys, s_keys, 40)) {
- puts("Aiiiie");
- exit(1);
- }
- test_memeq(c_keys, s_keys, 40);
- memset(s_buf, 0, 40);
- test_memneq(c_keys, s_buf, 40);
+ /* (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
@@ -945,9 +420,10 @@ test_onion_queues(void)
or_circuit_t *circ1 = or_circuit_new(0, NULL);
or_circuit_t *circ2 = or_circuit_new(0, NULL);
- create_cell_t *onionskin = NULL;
+ create_cell_t *onionskin = NULL, *create2_ptr;
create_cell_t *create1 = tor_malloc_zero(sizeof(create_cell_t));
create_cell_t *create2 = tor_malloc_zero(sizeof(create_cell_t));
+ create2_ptr = create2; /* remember, but do not free */
create_cell_init(create1, CELL_CREATE, ONION_HANDSHAKE_TYPE_TAP,
TAP_ONIONSKIN_CHALLENGE_LEN, buf1);
@@ -956,26 +432,29 @@ test_onion_queues(void)
test_eq(0, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
test_eq(0, onion_pending_add(circ1, create1));
+ create1 = NULL;
test_eq(1, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
test_eq(0, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
test_eq(0, onion_pending_add(circ2, create2));
+ create2 = NULL;
test_eq(1, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
test_eq_ptr(circ2, onion_next_task(&onionskin));
test_eq(1, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
test_eq(0, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
+ tt_ptr_op(onionskin, ==, create2_ptr);
clear_pending_onions();
test_eq(0, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
test_eq(0, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
done:
- ;
-// circuit_free(circ1);
-// circuit_free(circ2);
- /* and free create1 and create2 */
- /* XXX leaks everything here */
+ circuit_free(TO_CIRCUIT(circ1));
+ circuit_free(TO_CIRCUIT(circ2));
+ tor_free(create1);
+ tor_free(create2);
+ tor_free(onionskin);
}
static void
@@ -994,14 +473,14 @@ test_circuit_timeout(void)
circuit_build_times_t estimate;
circuit_build_times_t final;
double timeout1, timeout2;
- or_state_t state;
+ or_state_t *state=NULL;
int i, runs;
double close_ms;
circuit_build_times_init(&initial);
circuit_build_times_init(&estimate);
circuit_build_times_init(&final);
- memset(&state, 0, sizeof(or_state_t));
+ state = or_state_new();
circuitbuild_running_unit_tests();
#define timeout0 (build_time_t)(30*1000.0)
@@ -1033,8 +512,9 @@ test_circuit_timeout(void)
test_assert(estimate.total_build_times <= CBT_NCIRCUITS_TO_OBSERVE);
- circuit_build_times_update_state(&estimate, &state);
- test_assert(circuit_build_times_parse_state(&final, &state) == 0);
+ circuit_build_times_update_state(&estimate, state);
+ circuit_build_times_free_timeouts(&final);
+ test_assert(circuit_build_times_parse_state(&final, state) == 0);
circuit_build_times_update_alpha(&final);
timeout2 = circuit_build_times_calculate_timeout(&final,
@@ -1123,336 +603,10 @@ test_circuit_timeout(void)
}
done:
- return;
-}
-
-/* Helper: assert that short_policy parses and writes back out as itself,
- or as <b>expected</b> if that's provided. */
-static void
-test_short_policy_parse(const char *input,
- const char *expected)
-{
- short_policy_t *short_policy = NULL;
- char *out = NULL;
-
- if (expected == NULL)
- expected = input;
-
- short_policy = parse_short_policy(input);
- tt_assert(short_policy);
- out = write_short_policy(short_policy);
- tt_str_op(out, ==, expected);
-
- done:
- tor_free(out);
- short_policy_free(short_policy);
-}
-
-/** Helper: Parse the exit policy string in <b>policy_str</b>, and make sure
- * that policies_summarize() produces the string <b>expected_summary</b> from
- * it. */
-static void
-test_policy_summary_helper(const char *policy_str,
- const char *expected_summary)
-{
- config_line_t line;
- smartlist_t *policy = smartlist_new();
- char *summary = NULL;
- char *summary_after = NULL;
- int r;
- short_policy_t *short_policy = NULL;
-
- line.key = (char*)"foo";
- line.value = (char *)policy_str;
- line.next = NULL;
-
- r = policies_parse_exit_policy(&line, &policy, 1, 0, NULL, 1);
- test_eq(r, 0);
- summary = policy_summarize(policy, AF_INET);
-
- test_assert(summary != NULL);
- test_streq(summary, expected_summary);
-
- short_policy = parse_short_policy(summary);
- tt_assert(short_policy);
- summary_after = write_short_policy(short_policy);
- test_streq(summary, summary_after);
-
- done:
- tor_free(summary_after);
- tor_free(summary);
- if (policy)
- addr_policy_list_free(policy);
- short_policy_free(short_policy);
-}
-
-/** Run unit tests for generating summary lines of exit policies */
-static void
-test_policies(void)
-{
- int i;
- smartlist_t *policy = NULL, *policy2 = NULL, *policy3 = NULL,
- *policy4 = NULL, *policy5 = NULL, *policy6 = NULL,
- *policy7 = NULL;
- addr_policy_t *p;
- tor_addr_t tar;
- config_line_t line;
- smartlist_t *sm = NULL;
- char *policy_str = NULL;
-
- policy = smartlist_new();
-
- p = router_parse_addr_policy_item_from_string("reject 192.168.0.0/16:*",-1);
- test_assert(p != NULL);
- test_eq(ADDR_POLICY_REJECT, p->policy_type);
- tor_addr_from_ipv4h(&tar, 0xc0a80000u);
- test_eq(0, tor_addr_compare(&p->addr, &tar, CMP_EXACT));
- test_eq(16, p->maskbits);
- test_eq(1, p->prt_min);
- test_eq(65535, p->prt_max);
-
- smartlist_add(policy, p);
-
- tor_addr_from_ipv4h(&tar, 0x01020304u);
- test_assert(ADDR_POLICY_ACCEPTED ==
- compare_tor_addr_to_addr_policy(&tar, 2, policy));
- tor_addr_make_unspec(&tar);
- test_assert(ADDR_POLICY_PROBABLY_ACCEPTED ==
- compare_tor_addr_to_addr_policy(&tar, 2, policy));
- tor_addr_from_ipv4h(&tar, 0xc0a80102);
- test_assert(ADDR_POLICY_REJECTED ==
- compare_tor_addr_to_addr_policy(&tar, 2, policy));
-
- test_assert(0 == policies_parse_exit_policy(NULL, &policy2, 1, 1, NULL, 1));
- test_assert(policy2);
-
- policy3 = smartlist_new();
- p = router_parse_addr_policy_item_from_string("reject *:*",-1);
- test_assert(p != NULL);
- smartlist_add(policy3, p);
- p = router_parse_addr_policy_item_from_string("accept *:*",-1);
- test_assert(p != NULL);
- smartlist_add(policy3, p);
-
- policy4 = smartlist_new();
- p = router_parse_addr_policy_item_from_string("accept *:443",-1);
- test_assert(p != NULL);
- smartlist_add(policy4, p);
- p = router_parse_addr_policy_item_from_string("accept *:443",-1);
- test_assert(p != NULL);
- smartlist_add(policy4, p);
-
- policy5 = smartlist_new();
- p = router_parse_addr_policy_item_from_string("reject 0.0.0.0/8:*",-1);
- test_assert(p != NULL);
- smartlist_add(policy5, p);
- p = router_parse_addr_policy_item_from_string("reject 169.254.0.0/16:*",-1);
- test_assert(p != NULL);
- smartlist_add(policy5, p);
- p = router_parse_addr_policy_item_from_string("reject 127.0.0.0/8:*",-1);
- test_assert(p != NULL);
- smartlist_add(policy5, p);
- p = router_parse_addr_policy_item_from_string("reject 192.168.0.0/16:*",-1);
- test_assert(p != NULL);
- smartlist_add(policy5, p);
- p = router_parse_addr_policy_item_from_string("reject 10.0.0.0/8:*",-1);
- test_assert(p != NULL);
- smartlist_add(policy5, p);
- p = router_parse_addr_policy_item_from_string("reject 172.16.0.0/12:*",-1);
- test_assert(p != NULL);
- smartlist_add(policy5, p);
- p = router_parse_addr_policy_item_from_string("reject 80.190.250.90:*",-1);
- test_assert(p != NULL);
- smartlist_add(policy5, p);
- p = router_parse_addr_policy_item_from_string("reject *:1-65534",-1);
- test_assert(p != NULL);
- smartlist_add(policy5, p);
- p = router_parse_addr_policy_item_from_string("reject *:65535",-1);
- test_assert(p != NULL);
- smartlist_add(policy5, p);
- p = router_parse_addr_policy_item_from_string("accept *:1-65535",-1);
- test_assert(p != NULL);
- smartlist_add(policy5, p);
-
- policy6 = smartlist_new();
- p = router_parse_addr_policy_item_from_string("accept 43.3.0.0/9:*",-1);
- test_assert(p != NULL);
- smartlist_add(policy6, p);
-
- policy7 = smartlist_new();
- p = router_parse_addr_policy_item_from_string("accept 0.0.0.0/8:*",-1);
- test_assert(p != NULL);
- smartlist_add(policy7, p);
-
- test_assert(!exit_policy_is_general_exit(policy));
- test_assert(exit_policy_is_general_exit(policy2));
- test_assert(!exit_policy_is_general_exit(NULL));
- test_assert(!exit_policy_is_general_exit(policy3));
- test_assert(!exit_policy_is_general_exit(policy4));
- test_assert(!exit_policy_is_general_exit(policy5));
- test_assert(!exit_policy_is_general_exit(policy6));
- test_assert(!exit_policy_is_general_exit(policy7));
-
- test_assert(cmp_addr_policies(policy, policy2));
- test_assert(cmp_addr_policies(policy, NULL));
- test_assert(!cmp_addr_policies(policy2, policy2));
- test_assert(!cmp_addr_policies(NULL, NULL));
-
- test_assert(!policy_is_reject_star(policy2, AF_INET));
- test_assert(policy_is_reject_star(policy, AF_INET));
- test_assert(policy_is_reject_star(NULL, AF_INET));
-
- addr_policy_list_free(policy);
- policy = NULL;
-
- /* make sure compacting logic works. */
- policy = NULL;
- line.key = (char*)"foo";
- line.value = (char*)"accept *:80,reject private:*,reject *:*";
- line.next = NULL;
- test_assert(0 == policies_parse_exit_policy(&line, &policy, 1, 0, NULL, 1));
- test_assert(policy);
- //test_streq(policy->string, "accept *:80");
- //test_streq(policy->next->string, "reject *:*");
- test_eq(smartlist_len(policy), 4);
-
- /* test policy summaries */
- /* check if we properly ignore private IP addresses */
- test_policy_summary_helper("reject 192.168.0.0/16:*,"
- "reject 0.0.0.0/8:*,"
- "reject 10.0.0.0/8:*,"
- "accept *:10-30,"
- "accept *:90,"
- "reject *:*",
- "accept 10-30,90");
- /* check all accept policies, and proper counting of rejects */
- test_policy_summary_helper("reject 11.0.0.0/9:80,"
- "reject 12.0.0.0/9:80,"
- "reject 13.0.0.0/9:80,"
- "reject 14.0.0.0/9:80,"
- "accept *:*", "accept 1-65535");
- test_policy_summary_helper("reject 11.0.0.0/9:80,"
- "reject 12.0.0.0/9:80,"
- "reject 13.0.0.0/9:80,"
- "reject 14.0.0.0/9:80,"
- "reject 15.0.0.0:81,"
- "accept *:*", "accept 1-65535");
- test_policy_summary_helper("reject 11.0.0.0/9:80,"
- "reject 12.0.0.0/9:80,"
- "reject 13.0.0.0/9:80,"
- "reject 14.0.0.0/9:80,"
- "reject 15.0.0.0:80,"
- "accept *:*",
- "reject 80");
- /* no exits */
- test_policy_summary_helper("accept 11.0.0.0/9:80,"
- "reject *:*",
- "reject 1-65535");
- /* port merging */
- test_policy_summary_helper("accept *:80,"
- "accept *:81,"
- "accept *:100-110,"
- "accept *:111,"
- "reject *:*",
- "accept 80-81,100-111");
- /* border ports */
- test_policy_summary_helper("accept *:1,"
- "accept *:3,"
- "accept *:65535,"
- "reject *:*",
- "accept 1,3,65535");
- /* holes */
- test_policy_summary_helper("accept *:1,"
- "accept *:3,"
- "accept *:5,"
- "accept *:7,"
- "reject *:*",
- "accept 1,3,5,7");
- test_policy_summary_helper("reject *:1,"
- "reject *:3,"
- "reject *:5,"
- "reject *:7,"
- "accept *:*",
- "reject 1,3,5,7");
-
- /* Short policies with unrecognized formats should get accepted. */
- test_short_policy_parse("accept fred,2,3-5", "accept 2,3-5");
- test_short_policy_parse("accept 2,fred,3", "accept 2,3");
- test_short_policy_parse("accept 2,fred,3,bob", "accept 2,3");
- test_short_policy_parse("accept 2,-3,500-600", "accept 2,500-600");
- /* Short policies with nil entries are accepted too. */
- test_short_policy_parse("accept 1,,3", "accept 1,3");
- test_short_policy_parse("accept 100-200,,", "accept 100-200");
- test_short_policy_parse("reject ,1-10,,,,30-40", "reject 1-10,30-40");
-
- /* Try parsing various broken short policies */
- tt_ptr_op(NULL, ==, parse_short_policy("accept 200-199"));
- tt_ptr_op(NULL, ==, parse_short_policy(""));
- tt_ptr_op(NULL, ==, parse_short_policy("rejekt 1,2,3"));
- tt_ptr_op(NULL, ==, parse_short_policy("reject "));
- tt_ptr_op(NULL, ==, parse_short_policy("reject"));
- tt_ptr_op(NULL, ==, parse_short_policy("rej"));
- tt_ptr_op(NULL, ==, parse_short_policy("accept 2,3,100000"));
- tt_ptr_op(NULL, ==, parse_short_policy("accept 2,3x,4"));
- tt_ptr_op(NULL, ==, parse_short_policy("accept 2,3x,4"));
- tt_ptr_op(NULL, ==, parse_short_policy("accept 2-"));
- tt_ptr_op(NULL, ==, parse_short_policy("accept 2-x"));
- tt_ptr_op(NULL, ==, parse_short_policy("accept 1-,3"));
- tt_ptr_op(NULL, ==, parse_short_policy("accept 1-,3"));
- /* Test a too-long policy. */
- {
- int i;
- char *policy = NULL;
- smartlist_t *chunks = smartlist_new();
- smartlist_add(chunks, tor_strdup("accept "));
- for (i=1; i<10000; ++i)
- smartlist_add_asprintf(chunks, "%d,", i);
- smartlist_add(chunks, tor_strdup("20000"));
- policy = smartlist_join_strings(chunks, "", 0, NULL);
- SMARTLIST_FOREACH(chunks, char *, ch, tor_free(ch));
- smartlist_free(chunks);
- tt_ptr_op(NULL, ==, parse_short_policy(policy));/* shouldn't be accepted */
- tor_free(policy); /* could leak. */
- }
-
- /* truncation ports */
- sm = smartlist_new();
- for (i=1; i<2000; i+=2) {
- char buf[POLICY_BUF_LEN];
- tor_snprintf(buf, sizeof(buf), "reject *:%d", i);
- smartlist_add(sm, tor_strdup(buf));
- }
- smartlist_add(sm, tor_strdup("accept *:*"));
- policy_str = smartlist_join_strings(sm, ",", 0, NULL);
- test_policy_summary_helper( policy_str,
- "accept 2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,"
- "46,48,50,52,54,56,58,60,62,64,66,68,70,72,74,76,78,80,82,84,86,88,90,"
- "92,94,96,98,100,102,104,106,108,110,112,114,116,118,120,122,124,126,128,"
- "130,132,134,136,138,140,142,144,146,148,150,152,154,156,158,160,162,164,"
- "166,168,170,172,174,176,178,180,182,184,186,188,190,192,194,196,198,200,"
- "202,204,206,208,210,212,214,216,218,220,222,224,226,228,230,232,234,236,"
- "238,240,242,244,246,248,250,252,254,256,258,260,262,264,266,268,270,272,"
- "274,276,278,280,282,284,286,288,290,292,294,296,298,300,302,304,306,308,"
- "310,312,314,316,318,320,322,324,326,328,330,332,334,336,338,340,342,344,"
- "346,348,350,352,354,356,358,360,362,364,366,368,370,372,374,376,378,380,"
- "382,384,386,388,390,392,394,396,398,400,402,404,406,408,410,412,414,416,"
- "418,420,422,424,426,428,430,432,434,436,438,440,442,444,446,448,450,452,"
- "454,456,458,460,462,464,466,468,470,472,474,476,478,480,482,484,486,488,"
- "490,492,494,496,498,500,502,504,506,508,510,512,514,516,518,520,522");
-
- done:
- addr_policy_list_free(policy);
- addr_policy_list_free(policy2);
- addr_policy_list_free(policy3);
- addr_policy_list_free(policy4);
- addr_policy_list_free(policy5);
- addr_policy_list_free(policy6);
- addr_policy_list_free(policy7);
- tor_free(policy_str);
- if (sm) {
- SMARTLIST_FOREACH(sm, char *, s, tor_free(s));
- smartlist_free(sm);
- }
+ circuit_build_times_free_timeouts(&initial);
+ circuit_build_times_free_timeouts(&estimate);
+ circuit_build_times_free_timeouts(&final);
+ or_state_free(state);
}
/** Test encoding and parsing of rendezvous service descriptors. */
@@ -1579,6 +733,34 @@ test_rend_fns(void)
tor_free(intro_points_encrypted);
}
+ /* Record odd numbered fake-IPs using ipv6, even numbered fake-IPs
+ * using ipv4. Since our fake geoip database is the same between
+ * ipv4 and ipv6, we should get the same result no matter which
+ * address family we pick for each IP. */
+#define SET_TEST_ADDRESS(i) do { \
+ if ((i) & 1) { \
+ SET_TEST_IPV6(i); \
+ tor_addr_from_in6(&addr, &in6); \
+ } else { \
+ tor_addr_from_ipv4h(&addr, (uint32_t) i); \
+ } \
+ } while (0)
+
+ /* Make sure that country ID actually works. */
+#define SET_TEST_IPV6(i) \
+ do { \
+ set_uint32(in6.s6_addr + 12, htonl((uint32_t) (i))); \
+ } while (0)
+#define CHECK_COUNTRY(country, val) do { \
+ /* test ipv4 country lookup */ \
+ test_streq(country, \
+ geoip_get_country_name(geoip_get_country_by_ipv4(val))); \
+ /* test ipv6 country lookup */ \
+ SET_TEST_IPV6(val); \
+ test_streq(country, \
+ geoip_get_country_name(geoip_get_country_by_ipv6(&in6))); \
+ } while (0)
+
/** Run unit tests for GeoIP code. */
static void
test_geoip(void)
@@ -1589,7 +771,8 @@ test_geoip(void)
const char *bridge_stats_1 =
"bridge-stats-end 2010-08-12 13:27:30 (86400 s)\n"
"bridge-ips zz=24,xy=8\n"
- "bridge-ip-versions v4=16,v6=16\n",
+ "bridge-ip-versions v4=16,v6=16\n"
+ "bridge-ip-transports <OR>=24\n",
*dirreq_stats_1 =
"dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n"
"dirreq-v3-ips ab=8\n"
@@ -1653,21 +836,6 @@ test_geoip(void)
test_eq(4, geoip_get_n_countries());
memset(&in6, 0, sizeof(in6));
- /* Make sure that country ID actually works. */
-#define SET_TEST_IPV6(i) \
- do { \
- set_uint32(in6.s6_addr + 12, htonl((uint32_t) (i))); \
- } while (0)
-#define CHECK_COUNTRY(country, val) do { \
- /* test ipv4 country lookup */ \
- test_streq(country, \
- geoip_get_country_name(geoip_get_country_by_ipv4(val))); \
- /* test ipv6 country lookup */ \
- SET_TEST_IPV6(val); \
- test_streq(country, \
- geoip_get_country_name(geoip_get_country_by_ipv6(&in6))); \
- } while (0)
-
CHECK_COUNTRY("??", 3);
CHECK_COUNTRY("ab", 32);
CHECK_COUNTRY("??", 5);
@@ -1680,40 +848,25 @@ test_geoip(void)
SET_TEST_IPV6(3);
test_eq(0, geoip_get_country_by_ipv6(&in6));
-#undef CHECK_COUNTRY
-
- /* Record odd numbered fake-IPs using ipv6, even numbered fake-IPs
- * using ipv4. Since our fake geoip database is the same between
- * ipv4 and ipv6, we should get the same result no matter which
- * address family we pick for each IP. */
-#define SET_TEST_ADDRESS(i) do { \
- if ((i) & 1) { \
- SET_TEST_IPV6(i); \
- tor_addr_from_in6(&addr, &in6); \
- } else { \
- tor_addr_from_ipv4h(&addr, (uint32_t) i); \
- } \
- } while (0)
-
get_options_mutable()->BridgeRelay = 1;
get_options_mutable()->BridgeRecordUsageByCountry = 1;
/* Put 9 observations in AB... */
for (i=32; i < 40; ++i) {
SET_TEST_ADDRESS(i);
- geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now-7200);
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL, now-7200);
}
SET_TEST_ADDRESS(225);
- geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now-7200);
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL, now-7200);
/* and 3 observations in XY, several times. */
for (j=0; j < 10; ++j)
for (i=52; i < 55; ++i) {
SET_TEST_ADDRESS(i);
- geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now-3600);
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL, now-3600);
}
/* and 17 observations in ZZ... */
for (i=110; i < 127; ++i) {
SET_TEST_ADDRESS(i);
- geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now);
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL, now);
}
geoip_get_client_history(GEOIP_CLIENT_CONNECT, &s, &v);
test_assert(s);
@@ -1762,7 +915,7 @@ test_geoip(void)
/* Start testing dirreq statistics by making sure that we don't collect
* dirreq stats without initializing them. */
SET_TEST_ADDRESS(100);
- geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, now);
+ geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, NULL, now);
s = geoip_format_dirreq_stats(now + 86400);
test_assert(!s);
@@ -1770,7 +923,7 @@ test_geoip(void)
* dirreq-stats history string. */
geoip_dirreq_stats_init(now);
SET_TEST_ADDRESS(100);
- geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, now);
+ geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, NULL, now);
s = geoip_format_dirreq_stats(now + 86400);
test_streq(dirreq_stats_1, s);
tor_free(s);
@@ -1779,7 +932,7 @@ test_geoip(void)
* don't generate a history string. */
geoip_dirreq_stats_term();
SET_TEST_ADDRESS(101);
- geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, now);
+ geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, NULL, now);
s = geoip_format_dirreq_stats(now + 86400);
test_assert(!s);
@@ -1787,7 +940,7 @@ test_geoip(void)
* that we get an all empty history string. */
geoip_dirreq_stats_init(now);
SET_TEST_ADDRESS(100);
- geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, now);
+ geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, NULL, now);
geoip_reset_dirreq_stats(now);
s = geoip_format_dirreq_stats(now + 86400);
test_streq(dirreq_stats_2, s);
@@ -1804,6 +957,7 @@ test_geoip(void)
geoip_start_dirreq((uint64_t) 1, 1024, DIRREQ_TUNNELED);
s = geoip_format_dirreq_stats(now + 86400);
test_streq(dirreq_stats_4, s);
+ tor_free(s);
/* Stop collecting directory request statistics and start gathering
* entry stats. */
@@ -1814,7 +968,7 @@ test_geoip(void)
/* Start testing entry statistics by making sure that we don't collect
* anything without initializing entry stats. */
SET_TEST_ADDRESS(100);
- geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now);
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL, now);
s = geoip_format_entry_stats(now + 86400);
test_assert(!s);
@@ -1822,7 +976,7 @@ test_geoip(void)
* entry-stats history string. */
geoip_entry_stats_init(now);
SET_TEST_ADDRESS(100);
- geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now);
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL, now);
s = geoip_format_entry_stats(now + 86400);
test_streq(entry_stats_1, s);
tor_free(s);
@@ -1831,7 +985,7 @@ test_geoip(void)
* don't generate a history string. */
geoip_entry_stats_term();
SET_TEST_ADDRESS(101);
- geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now);
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL, now);
s = geoip_format_entry_stats(now + 86400);
test_assert(!s);
@@ -1839,15 +993,12 @@ test_geoip(void)
* that we get an all empty history string. */
geoip_entry_stats_init(now);
SET_TEST_ADDRESS(100);
- geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now);
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL, now);
geoip_reset_entry_stats(now);
s = geoip_format_entry_stats(now + 86400);
test_streq(entry_stats_2, s);
tor_free(s);
-#undef SET_TEST_ADDRESS
-#undef SET_TEST_IPV6
-
/* Stop collecting entry statistics. */
geoip_entry_stats_term();
get_options_mutable()->EntryStatistics = 0;
@@ -1857,6 +1008,81 @@ test_geoip(void)
tor_free(v);
}
+static void
+test_geoip_with_pt(void)
+{
+ time_t now = 1281533250; /* 2010-08-11 13:27:30 UTC */
+ char *s = NULL;
+ int i;
+ tor_addr_t addr;
+ struct in6_addr in6;
+
+ get_options_mutable()->BridgeRelay = 1;
+ get_options_mutable()->BridgeRecordUsageByCountry = 1;
+
+ memset(&in6, 0, sizeof(in6));
+
+ /* No clients seen yet. */
+ s = geoip_get_transport_history();
+ tor_assert(!s);
+
+ /* 4 connections without a pluggable transport */
+ for (i=0; i < 4; ++i) {
+ SET_TEST_ADDRESS(i);
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL, now-7200);
+ }
+
+ /* 9 connections with "alpha" */
+ for (i=4; i < 13; ++i) {
+ SET_TEST_ADDRESS(i);
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, "alpha", now-7200);
+ }
+
+ /* one connection with "beta" */
+ SET_TEST_ADDRESS(13);
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, "beta", now-7200);
+
+ /* 14 connections with "charlie" */
+ for (i=14; i < 28; ++i) {
+ SET_TEST_ADDRESS(i);
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, "charlie", now-7200);
+ }
+
+ /* 131 connections with "ddr" */
+ for (i=28; i < 159; ++i) {
+ SET_TEST_ADDRESS(i);
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, "ddr", now-7200);
+ }
+
+ /* 8 connections with "entropy" */
+ for (i=159; i < 167; ++i) {
+ SET_TEST_ADDRESS(i);
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, "entropy", now-7200);
+ }
+
+ /* 2 connections from the same IP with two different transports. */
+ SET_TEST_ADDRESS(++i);
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, "fire", now-7200);
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, "google", now-7200);
+
+ /* Test the transport history string. */
+ s = geoip_get_transport_history();
+ tor_assert(s);
+ test_streq(s, "<OR>=8,alpha=16,beta=8,charlie=16,ddr=136,"
+ "entropy=8,fire=8,google=8");
+
+ /* Stop collecting entry statistics. */
+ geoip_entry_stats_term();
+ get_options_mutable()->EntryStatistics = 0;
+
+ done:
+ tor_free(s);
+}
+
+#undef SET_TEST_ADDRESS
+#undef SET_TEST_IPV6
+#undef CHECK_COUNTRY
+
/** Run unit tests for stats code. */
static void
test_stats(void)
@@ -2047,40 +1273,23 @@ const struct testcase_setup_t legacy_setup = {
{ #name, legacy_test_helper, TT_FORK, &legacy_setup, test_ ## name }
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 },
ENT(onion_queues),
#ifdef CURVE25519_ENABLED
{ "ntor_handshake", test_ntor_handshake, 0, NULL, NULL },
#endif
ENT(circuit_timeout),
- ENT(policies),
ENT(rend_fns),
ENT(geoip),
+ FORK(geoip_with_pt),
FORK(stats),
END_OF_TESTCASES
};
-#define SOCKSENT(name) \
- { #name, test_socks_##name, TT_FORK, &socks_setup, NULL }
-
-static struct testcase_t socks_tests[] = {
- SOCKSENT(4_unsupported_commands),
- SOCKSENT(4_supported_commands),
-
- SOCKSENT(5_unsupported_commands),
- SOCKSENT(5_supported_commands),
- SOCKSENT(5_no_authenticate),
- SOCKSENT(5_auth_before_negotiation),
- SOCKSENT(5_authenticate),
- SOCKSENT(5_authenticate_with_data),
-
- END_OF_TESTCASES
-};
-
extern struct testcase_t addr_tests[];
+extern struct testcase_t buffer_tests[];
extern struct testcase_t crypto_tests[];
extern struct testcase_t container_tests[];
extern struct testcase_t util_tests[];
@@ -2090,22 +1299,52 @@ extern struct testcase_t pt_tests[];
extern struct testcase_t config_tests[];
extern struct testcase_t introduce_tests[];
extern struct testcase_t replaycache_tests[];
+extern struct testcase_t relaycell_tests[];
extern struct testcase_t cell_format_tests[];
+extern struct testcase_t circuitlist_tests[];
+extern struct testcase_t circuitmux_tests[];
+extern struct testcase_t cell_queue_tests[];
+extern struct testcase_t options_tests[];
+extern struct testcase_t socks_tests[];
+extern struct testcase_t extorport_tests[];
+extern struct testcase_t controller_event_tests[];
+extern struct testcase_t logging_tests[];
+extern struct testcase_t hs_tests[];
+extern struct testcase_t nodelist_tests[];
+extern struct testcase_t routerkeys_tests[];
+extern struct testcase_t oom_tests[];
+extern struct testcase_t policy_tests[];
+extern struct testcase_t status_tests[];
static struct testgroup_t testgroups[] = {
{ "", test_array },
+ { "buffer/", buffer_tests },
{ "socks/", socks_tests },
{ "addr/", addr_tests },
{ "crypto/", crypto_tests },
{ "container/", container_tests },
{ "util/", util_tests },
+ { "util/logging/", logging_tests },
{ "cellfmt/", cell_format_tests },
+ { "cellqueue/", cell_queue_tests },
{ "dir/", dir_tests },
{ "dir/md/", microdesc_tests },
{ "pt/", pt_tests },
{ "config/", config_tests },
{ "replaycache/", replaycache_tests },
+ { "relaycell/", relaycell_tests },
{ "introduce/", introduce_tests },
+ { "circuitlist/", circuitlist_tests },
+ { "circuitmux/", circuitmux_tests },
+ { "options/", options_tests },
+ { "extorport/", extorport_tests },
+ { "control/", controller_event_tests },
+ { "hs/", hs_tests },
+ { "nodelist/", nodelist_tests },
+ { "routerkeys/", routerkeys_tests },
+ { "oom/", oom_tests },
+ { "policy/" , policy_tests },
+ { "status/" , status_tests },
END_OF_GROUPS
};
@@ -2118,6 +1357,7 @@ main(int c, const char **v)
char *errmsg = NULL;
int i, i_out;
int loglevel = LOG_ERR;
+ int accel_crypto = 0;
#ifdef USE_DMALLOC
{
@@ -2140,6 +1380,8 @@ main(int c, const char **v)
loglevel = LOG_INFO;
} else if (!strcmp(v[i], "--debug")) {
loglevel = LOG_DEBUG;
+ } else if (!strcmp(v[i], "--accel")) {
+ accel_crypto = 1;
} else {
v[i_out++] = v[i];
}
@@ -2154,7 +1396,7 @@ main(int c, const char **v)
}
options->command = CMD_RUN_UNITTESTS;
- if (crypto_global_init(0, NULL, NULL)) {
+ if (crypto_global_init(accel_crypto, NULL, NULL)) {
printf("Can't initialize crypto subsystem; exiting.\n");
return 1;
}
diff --git a/src/test/test.h b/src/test/test.h
index a89b558e5..861ce5ac3 100644
--- a/src/test/test.h
+++ b/src/test/test.h
@@ -36,17 +36,7 @@
#define test_strneq(expr1, expr2) tt_str_op((expr1), !=, (expr2))
#define test_mem_op(expr1, op, expr2, len) \
- tt_assert_test_fmt_type(expr1,expr2,#expr1" "#op" "#expr2, \
- const char *, \
- (memcmp(val1_, val2_, len) op 0), \
- char *, "%s", \
- { size_t printlen = (len)*2+1; \
- print_ = tor_malloc(printlen); \
- base16_encode(print_, printlen, value_, \
- (len)); }, \
- { tor_free(print_); }, \
- TT_EXIT_TEST_FUNCTION \
- );
+ tt_mem_op((expr1), op, (expr2), (len))
#define test_memeq(expr1, expr2, len) test_mem_op((expr1), ==, (expr2), len)
#define test_memneq(expr1, expr2, len) test_mem_op((expr1), !=, (expr2), len)
@@ -69,11 +59,126 @@
tt_assert_test_type(a,b,#a" "#op" "#b,double,(val1_ op val2_),"%f", \
TT_EXIT_TEST_FUNCTION)
+#ifdef _MSC_VER
+#define U64_PRINTF_TYPE uint64_t
+#define U64_PRINTF_TYPE int64_t
+#else
+#define U64_PRINTF_TYPE unsigned long long
+#define I64_PRINTF_TYPE long long
+#endif
+
+#define tt_size_op(a,op,b) \
+ tt_assert_test_fmt_type(a,b,#a" "#op" "#b,size_t,(val1_ op val2_), \
+ U64_PRINTF_TYPE, U64_FORMAT, \
+ {print_ = (U64_PRINTF_TYPE) value_;}, {}, TT_EXIT_TEST_FUNCTION)
+
+#define tt_u64_op(a,op,b) \
+ tt_assert_test_fmt_type(a,b,#a" "#op" "#b,uint64_t,(val1_ op val2_), \
+ U64_PRINTF_TYPE, U64_FORMAT, \
+ {print_ = (U64_PRINTF_TYPE) value_;}, {}, TT_EXIT_TEST_FUNCTION)
+
+#define tt_i64_op(a,op,b) \
+ tt_assert_test_fmt_type(a,b,#a" "#op" "#b,int64_t,(val1_ op val2_), \
+ I64_PRINTF_TYPE, I64_FORMAT, \
+ {print_ = (I64_PRINTF_TYPE) value_;}, {}, TT_EXIT_TEST_FUNCTION)
+
const char *get_fname(const char *name);
crypto_pk_t *pk_generate(int idx);
void legacy_test_helper(void *data);
extern const struct testcase_setup_t legacy_setup;
+#define US2_CONCAT_2__(a, b) a ## __ ## b
+#define US_CONCAT_2__(a, b) a ## _ ## b
+#define US_CONCAT_3__(a, b, c) a ## _ ## b ## _ ## c
+#define US_CONCAT_2_(a, b) US_CONCAT_2__(a, b)
+#define US_CONCAT_3_(a, b, c) US_CONCAT_3__(a, b, c)
+
+/*
+ * These macros are helpful for streamlining the authorship of several test
+ * cases that use mocks.
+ *
+ * The pattern is as follows.
+ * * Declare a top level namespace:
+ * #define NS_MODULE foo
+ *
+ * * For each test case you want to write, create a new submodule in the
+ * namespace. All mocks and other information should belong to a single
+ * submodule to avoid interference with other test cases.
+ * You can simply name the submodule after the function in the module you
+ * are testing:
+ * #define NS_SUBMODULE some_function
+ * or, if you're wanting to write several tests against the same function,
+ * ie., you are testing an aspect of that function, you can use:
+ * #define NS_SUBMODULE ASPECT(some_function, behavior)
+ *
+ * * Declare all the mocks you will use. The NS_DECL macro serves to declare
+ * the mock in the current namespace (defined by NS_MODULE and NS_SUBMODULE).
+ * It behaves like MOCK_DECL:
+ * NS_DECL(int, dependent_function, (void *));
+ * Here, dependent_function must be declared and implemented with the
+ * MOCK_DECL and MOCK_IMPL macros. The NS_DECL macro also defines an integer
+ * global for use for tracking how many times a mock was called, and can be
+ * accessed by CALLED(mock_name). For example, you might put
+ * CALLED(dependent_function)++;
+ * in your mock body.
+ *
+ * * Define a function called NS(main) that will contain the body of the
+ * test case. The NS macro can be used to reference a name in the current
+ * namespace.
+ *
+ * * In NS(main), indicate that a mock function in the current namespace,
+ * declared with NS_DECL is to override that in the global namespace,
+ * with the NS_MOCK macro:
+ * NS_MOCK(dependent_function)
+ * Unmock with:
+ * NS_UNMOCK(dependent_function)
+ *
+ * * Define the mocks with the NS macro, eg.,
+ * int
+ * NS(dependent_function)(void *)
+ * {
+ * CALLED(dependent_function)++;
+ * }
+ *
+ * * In the struct testcase_t array, you can use the TEST_CASE and
+ * TEST_CASE_ASPECT macros to define the cases without having to do so
+ * explicitly nor without having to reset NS_SUBMODULE, eg.,
+ * struct testcase_t foo_tests[] = {
+ * TEST_CASE_ASPECT(some_function, behavior),
+ * ...
+ * END_OF_TESTCASES
+ * which will define a test case named "some_function__behavior".
+ */
+
+#define NAME_TEST_(name) #name
+#define NAME_TEST(name) NAME_TEST_(name)
+#define ASPECT(test_module, test_name) US2_CONCAT_2__(test_module, test_name)
+#define TEST_CASE(function) \
+ { \
+ NAME_TEST(function), \
+ NS_FULL(NS_MODULE, function, test_main), \
+ TT_FORK, \
+ NULL, \
+ NULL, \
+ }
+#define TEST_CASE_ASPECT(function, aspect) \
+ { \
+ NAME_TEST(ASPECT(function, aspect)), \
+ NS_FULL(NS_MODULE, ASPECT(function, aspect), test_main), \
+ TT_FORK, \
+ NULL, \
+ NULL, \
+ }
+
+#define NS(name) US_CONCAT_3_(NS_MODULE, NS_SUBMODULE, name)
+#define NS_FULL(module, submodule, name) US_CONCAT_3_(module, submodule, name)
+
+#define CALLED(mock_name) US_CONCAT_2_(NS(mock_name), called)
+#define NS_DECL(retval, mock_fn, args) \
+ static retval NS(mock_fn) args; int CALLED(mock_fn) = 0
+#define NS_MOCK(name) MOCK(name, NS(name))
+#define NS_UNMOCK(name) UNMOCK(name)
+
#endif
diff --git a/src/test/test_addr.c b/src/test/test_addr.c
index fec85a469..50011e606 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));
@@ -69,7 +73,7 @@ test_addr_basic(void)
}
done:
- ;
+ tor_free(cp);
}
#define test_op_ip6_(a,op,b,e1,e2) \
@@ -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::");
@@ -340,6 +346,9 @@ test_addr_ip6_helpers(void)
test_pton6_bad("a:::b:c");
test_pton6_bad(":::a:b:c");
test_pton6_bad("a:b:c:::");
+ test_pton6_bad("1.2.3.4");
+ test_pton6_bad(":1.2.3.4");
+ test_pton6_bad(".2.3.4");
/* test internal checking */
test_external_ip("fbff:ffff::2:7", 0);
@@ -396,7 +405,6 @@ test_addr_ip6_helpers(void)
test_internal_ip("::ffff:169.254.0.0", 0);
test_internal_ip("::ffff:169.254.255.255", 0);
test_external_ip("::ffff:169.255.0.0", 0);
- test_assert(is_internal_IP(0x7f000001, 0));
/* tor_addr_compare(tor_addr_t x2) */
test_addr_compare("ffff::", ==, "ffff::0");
@@ -464,6 +472,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);
@@ -735,42 +746,89 @@ test_addr_parse(void)
/* Correct call. */
r= tor_addr_port_parse(LOG_DEBUG,
"192.0.2.1:1234",
- &addr, &port);
+ &addr, &port, -1);
test_assert(r == 0);
tor_addr_to_str(buf, &addr, sizeof(buf), 0);
test_streq(buf, "192.0.2.1");
test_eq(port, 1234);
+ r= tor_addr_port_parse(LOG_DEBUG,
+ "[::1]:1234",
+ &addr, &port, -1);
+ test_assert(r == 0);
+ tor_addr_to_str(buf, &addr, sizeof(buf), 0);
+ test_streq(buf, "::1");
+ test_eq(port, 1234);
+
/* Domain name. */
r= tor_addr_port_parse(LOG_DEBUG,
"torproject.org:1234",
- &addr, &port);
+ &addr, &port, -1);
test_assert(r == -1);
/* Only IP. */
r= tor_addr_port_parse(LOG_DEBUG,
"192.0.2.2",
- &addr, &port);
+ &addr, &port, -1);
+ test_assert(r == -1);
+
+ r= tor_addr_port_parse(LOG_DEBUG,
+ "192.0.2.2",
+ &addr, &port, 200);
+ test_assert(r == 0);
+ tt_int_op(port,==,200);
+
+ r= tor_addr_port_parse(LOG_DEBUG,
+ "[::1]",
+ &addr, &port, -1);
test_assert(r == -1);
+ r= tor_addr_port_parse(LOG_DEBUG,
+ "[::1]",
+ &addr, &port, 400);
+ test_assert(r == 0);
+ tt_int_op(port,==,400);
+
/* Bad port. */
r= tor_addr_port_parse(LOG_DEBUG,
"192.0.2.2:66666",
- &addr, &port);
+ &addr, &port, -1);
+ test_assert(r == -1);
+ r= tor_addr_port_parse(LOG_DEBUG,
+ "192.0.2.2:66666",
+ &addr, &port, 200);
test_assert(r == -1);
/* Only domain name */
r= tor_addr_port_parse(LOG_DEBUG,
"torproject.org",
- &addr, &port);
+ &addr, &port, -1);
+ test_assert(r == -1);
+ r= tor_addr_port_parse(LOG_DEBUG,
+ "torproject.org",
+ &addr, &port, 200);
test_assert(r == -1);
/* Bad IP address */
r= tor_addr_port_parse(LOG_DEBUG,
"192.0.2:1234",
- &addr, &port);
+ &addr, &port, -1);
test_assert(r == -1);
+ /* Make sure that the default port has lower priority than the real
+ one */
+ r= tor_addr_port_parse(LOG_DEBUG,
+ "192.0.2.2:1337",
+ &addr, &port, 200);
+ test_assert(r == 0);
+ tt_int_op(port,==,1337);
+
+ r= tor_addr_port_parse(LOG_DEBUG,
+ "[::1]:1369",
+ &addr, &port, 200);
+ test_assert(r == 0);
+ tt_int_op(port,==,1369);
+
done:
;
}
@@ -844,6 +902,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 s_un;
+#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(&s_un,0,sizeof(s_un));
+ s_un.sun_family = AF_UNIX;
+ strlcpy(s_un.sun_path, "/here/is/a/path", sizeof(s_un.sun_path));
+ CHECK(s_un, "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 {
@@ -878,6 +1020,32 @@ test_addr_is_loopback(void *data)
;
}
+static void
+test_addr_make_null(void *data)
+{
+ tor_addr_t *addr = tor_malloc(sizeof(*addr));
+ tor_addr_t *zeros = tor_malloc_zero(sizeof(*addr));
+ char buf[TOR_ADDR_BUF_LEN];
+ (void) data;
+ /* Ensure that before tor_addr_make_null, addr != 0's */
+ memset(addr, 1, sizeof(*addr));
+ tt_int_op(memcmp(addr, zeros, sizeof(*addr)), !=, 0);
+ /* Test with AF == AF_INET */
+ zeros->family = AF_INET;
+ tor_addr_make_null(addr, AF_INET);
+ tt_int_op(memcmp(addr, zeros, sizeof(*addr)), ==, 0);
+ tt_str_op(tor_addr_to_str(buf, addr, sizeof(buf), 0), ==, "0.0.0.0");
+ /* Test with AF == AF_INET6 */
+ memset(addr, 1, sizeof(*addr));
+ zeros->family = AF_INET6;
+ tor_addr_make_null(addr, AF_INET6);
+ tt_int_op(memcmp(addr, zeros, sizeof(*addr)), ==, 0);
+ tt_str_op(tor_addr_to_str(buf, addr, sizeof(buf), 0), ==, "::");
+ done:
+ tor_free(addr);
+ tor_free(zeros);
+}
+
#define ADDR_LEGACY(name) \
{ #name, legacy_test_helper, 0, &legacy_setup, test_addr_ ## name }
@@ -886,7 +1054,11 @@ 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 },
+ { "make_null", test_addr_make_null, 0, NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_bt_cl.c b/src/test/test_bt_cl.c
new file mode 100644
index 000000000..45ae82fb8
--- /dev/null
+++ b/src/test/test_bt_cl.c
@@ -0,0 +1,109 @@
+/* Copyright (c) 2012-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "or.h"
+#include "util.h"
+#include "backtrace.h"
+#include "torlog.h"
+
+/* -1: no crash.
+ * 0: crash with a segmentation fault.
+ * 1x: crash with an assertion failure. */
+static int crashtype = 0;
+
+#ifdef __GNUC__
+#define NOINLINE __attribute__((noinline))
+#define NORETURN __attribute__((noreturn))
+#endif
+
+int crash(int x) NOINLINE;
+int oh_what(int x) NOINLINE;
+int a_tangled_web(int x) NOINLINE;
+int we_weave(int x) NOINLINE;
+static void abort_handler(int s) NORETURN;
+
+int
+crash(int x)
+{
+ if (crashtype == 0) {
+ *(volatile int *)0 = 0;
+ } else if (crashtype == 1) {
+ tor_assert(1 == 0);
+ } else if (crashtype == -1) {
+ ;
+ }
+
+ crashtype *= x;
+ return crashtype;
+}
+
+int
+oh_what(int x)
+{
+ /* We call crash() twice here, so that the compiler won't try to do a
+ * tail-call optimization. Only the first call will actually happen, but
+ * telling the compiler to maybe do the second call will prevent it from
+ * replacing the first call with a jump. */
+ return crash(x) + crash(x*2);
+}
+
+int
+a_tangled_web(int x)
+{
+ return oh_what(x) * 99 + oh_what(x);
+}
+
+int
+we_weave(int x)
+{
+ return a_tangled_web(x) + a_tangled_web(x+1);
+}
+
+static void
+abort_handler(int s)
+{
+ (void)s;
+ exit(0);
+}
+
+int
+main(int argc, char **argv)
+{
+ log_severity_list_t severity;
+
+ if (argc < 2) {
+ puts("I take an argument. It should be \"assert\" or \"crash\" or "
+ "\"none\"");
+ return 1;
+ }
+ if (!strcmp(argv[1], "assert")) {
+ crashtype = 1;
+ } else if (!strcmp(argv[1], "crash")) {
+ crashtype = 0;
+ } else if (!strcmp(argv[1], "none")) {
+ crashtype = -1;
+ } else {
+ puts("Argument should be \"assert\" or \"crash\" or \"none\"");
+ return 1;
+ }
+
+ init_logging();
+ set_log_severity_config(LOG_WARN, LOG_ERR, &severity);
+ add_stream_log(&severity, "stdout", STDOUT_FILENO);
+ tor_log_update_sigsafe_err_fds();
+
+ configure_backtrace_handler(NULL);
+
+ signal(SIGABRT, abort_handler);
+
+ printf("%d\n", we_weave(2));
+
+ clean_up_backtrace_handler();
+
+ return 0;
+}
+
diff --git a/src/test/test_buffers.c b/src/test/test_buffers.c
new file mode 100644
index 000000000..61ac5bc36
--- /dev/null
+++ b/src/test/test_buffers.c
@@ -0,0 +1,732 @@
+/* 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 */
+
+#define BUFFERS_PRIVATE
+#include "or.h"
+#include "buffers.h"
+#include "ext_orport.h"
+#include "test.h"
+
+/** Run unit tests for buffers.c */
+static void
+test_buffers_basic(void *arg)
+{
+ char str[256];
+ char str2[256];
+
+ buf_t *buf = NULL, *buf2 = NULL;
+ const char *cp;
+
+ int j;
+ size_t r;
+ (void) arg;
+
+ /****
+ * buf_new
+ ****/
+ if (!(buf = buf_new()))
+ test_fail();
+
+ //test_eq(buf_capacity(buf), 4096);
+ test_eq(buf_datalen(buf), 0);
+
+ /****
+ * General pointer frobbing
+ */
+ for (j=0;j<256;++j) {
+ str[j] = (char)j;
+ }
+ write_to_buf(str, 256, buf);
+ write_to_buf(str, 256, buf);
+ test_eq(buf_datalen(buf), 512);
+ fetch_from_buf(str2, 200, buf);
+ test_memeq(str, str2, 200);
+ test_eq(buf_datalen(buf), 312);
+ memset(str2, 0, sizeof(str2));
+
+ fetch_from_buf(str2, 256, buf);
+ test_memeq(str+200, str2, 56);
+ test_memeq(str, str2+56, 200);
+ test_eq(buf_datalen(buf), 56);
+ memset(str2, 0, sizeof(str2));
+ /* Okay, now we should be 512 bytes into the 4096-byte buffer. If we add
+ * another 3584 bytes, we hit the end. */
+ for (j=0;j<15;++j) {
+ write_to_buf(str, 256, buf);
+ }
+ assert_buf_ok(buf);
+ test_eq(buf_datalen(buf), 3896);
+ fetch_from_buf(str2, 56, buf);
+ test_eq(buf_datalen(buf), 3840);
+ test_memeq(str+200, str2, 56);
+ for (j=0;j<15;++j) {
+ memset(str2, 0, sizeof(str2));
+ fetch_from_buf(str2, 256, buf);
+ test_memeq(str, str2, 256);
+ }
+ test_eq(buf_datalen(buf), 0);
+ buf_free(buf);
+ buf = NULL;
+
+ /* Okay, now make sure growing can work. */
+ buf = buf_new_with_capacity(16);
+ //test_eq(buf_capacity(buf), 16);
+ write_to_buf(str+1, 255, buf);
+ //test_eq(buf_capacity(buf), 256);
+ fetch_from_buf(str2, 254, buf);
+ test_memeq(str+1, str2, 254);
+ //test_eq(buf_capacity(buf), 256);
+ assert_buf_ok(buf);
+ write_to_buf(str, 32, buf);
+ //test_eq(buf_capacity(buf), 256);
+ assert_buf_ok(buf);
+ write_to_buf(str, 256, buf);
+ assert_buf_ok(buf);
+ //test_eq(buf_capacity(buf), 512);
+ test_eq(buf_datalen(buf), 33+256);
+ fetch_from_buf(str2, 33, buf);
+ test_eq(*str2, str[255]);
+
+ test_memeq(str2+1, str, 32);
+ //test_eq(buf_capacity(buf), 512);
+ test_eq(buf_datalen(buf), 256);
+ fetch_from_buf(str2, 256, buf);
+ test_memeq(str, str2, 256);
+
+ /* now try shrinking: case 1. */
+ buf_free(buf);
+ buf = buf_new_with_capacity(33668);
+ for (j=0;j<67;++j) {
+ write_to_buf(str,255, buf);
+ }
+ //test_eq(buf_capacity(buf), 33668);
+ test_eq(buf_datalen(buf), 17085);
+ for (j=0; j < 40; ++j) {
+ fetch_from_buf(str2, 255,buf);
+ test_memeq(str2, str, 255);
+ }
+
+ /* now try shrinking: case 2. */
+ buf_free(buf);
+ buf = buf_new_with_capacity(33668);
+ for (j=0;j<67;++j) {
+ write_to_buf(str,255, buf);
+ }
+ for (j=0; j < 20; ++j) {
+ fetch_from_buf(str2, 255,buf);
+ test_memeq(str2, str, 255);
+ }
+ for (j=0;j<80;++j) {
+ write_to_buf(str,255, buf);
+ }
+ //test_eq(buf_capacity(buf),33668);
+ for (j=0; j < 120; ++j) {
+ fetch_from_buf(str2, 255,buf);
+ test_memeq(str2, str, 255);
+ }
+
+ /* Move from buf to buf. */
+ buf_free(buf);
+ buf = buf_new_with_capacity(4096);
+ buf2 = buf_new_with_capacity(4096);
+ for (j=0;j<100;++j)
+ write_to_buf(str, 255, buf);
+ test_eq(buf_datalen(buf), 25500);
+ for (j=0;j<100;++j) {
+ r = 10;
+ move_buf_to_buf(buf2, buf, &r);
+ test_eq(r, 0);
+ }
+ test_eq(buf_datalen(buf), 24500);
+ test_eq(buf_datalen(buf2), 1000);
+ for (j=0;j<3;++j) {
+ fetch_from_buf(str2, 255, buf2);
+ test_memeq(str2, str, 255);
+ }
+ r = 8192; /*big move*/
+ move_buf_to_buf(buf2, buf, &r);
+ test_eq(r, 0);
+ r = 30000; /* incomplete move */
+ move_buf_to_buf(buf2, buf, &r);
+ test_eq(r, 13692);
+ for (j=0;j<97;++j) {
+ fetch_from_buf(str2, 255, buf2);
+ test_memeq(str2, str, 255);
+ }
+ buf_free(buf);
+ buf_free(buf2);
+ buf = buf2 = NULL;
+
+ buf = buf_new_with_capacity(5);
+ cp = "Testing. This is a moderately long Testing string.";
+ for (j = 0; cp[j]; j++)
+ write_to_buf(cp+j, 1, buf);
+ test_eq(0, buf_find_string_offset(buf, "Testing", 7));
+ test_eq(1, buf_find_string_offset(buf, "esting", 6));
+ test_eq(1, buf_find_string_offset(buf, "est", 3));
+ test_eq(39, buf_find_string_offset(buf, "ing str", 7));
+ test_eq(35, buf_find_string_offset(buf, "Testing str", 11));
+ test_eq(32, buf_find_string_offset(buf, "ng ", 3));
+ test_eq(43, buf_find_string_offset(buf, "string.", 7));
+ test_eq(-1, buf_find_string_offset(buf, "shrdlu", 6));
+ test_eq(-1, buf_find_string_offset(buf, "Testing thing", 13));
+ test_eq(-1, buf_find_string_offset(buf, "ngx", 3));
+ buf_free(buf);
+ buf = NULL;
+
+ /* Try adding a string too long for any freelist. */
+ {
+ char *cp = tor_malloc_zero(65536);
+ buf = buf_new();
+ write_to_buf(cp, 65536, buf);
+ tor_free(cp);
+
+ tt_int_op(buf_datalen(buf), ==, 65536);
+ buf_free(buf);
+ buf = NULL;
+ }
+
+ done:
+ if (buf)
+ buf_free(buf);
+ if (buf2)
+ buf_free(buf2);
+ buf_shrink_freelists(1);
+}
+
+static void
+test_buffer_pullup(void *arg)
+{
+ buf_t *buf;
+ char *stuff, *tmp;
+ const char *cp;
+ size_t sz;
+ (void)arg;
+ stuff = tor_malloc(16384);
+ tmp = tor_malloc(16384);
+
+ /* Note: this test doesn't check the nulterminate argument to buf_pullup,
+ since nothing actually uses it. We should remove it some time. */
+
+ buf = buf_new_with_capacity(3000); /* rounds up to next power of 2. */
+
+ tt_assert(buf);
+ tt_int_op(buf_get_default_chunk_size(buf), ==, 4096);
+
+ tt_int_op(buf_get_total_allocation(), ==, 0);
+
+ /* There are a bunch of cases for pullup. One is the trivial case. Let's
+ mess around with an empty buffer. */
+ buf_pullup(buf, 16, 1);
+ buf_get_first_chunk_data(buf, &cp, &sz);
+ tt_ptr_op(cp, ==, NULL);
+ tt_uint_op(sz, ==, 0);
+
+ /* Let's make sure nothing got allocated */
+ tt_int_op(buf_get_total_allocation(), ==, 0);
+
+ /* Case 1: everything puts into the first chunk with some moving. */
+
+ /* Let's add some data. */
+ crypto_rand(stuff, 16384);
+ write_to_buf(stuff, 3000, buf);
+ write_to_buf(stuff+3000, 3000, buf);
+ buf_get_first_chunk_data(buf, &cp, &sz);
+ tt_ptr_op(cp, !=, NULL);
+ tt_int_op(sz, <=, 4096);
+
+ /* Make room for 3000 bytes in the first chunk, so that the pullup-move code
+ * can get tested. */
+ tt_int_op(fetch_from_buf(tmp, 3000, buf), ==, 3000);
+ test_memeq(tmp, stuff, 3000);
+ buf_pullup(buf, 2048, 0);
+ assert_buf_ok(buf);
+ buf_get_first_chunk_data(buf, &cp, &sz);
+ tt_ptr_op(cp, !=, NULL);
+ tt_int_op(sz, >=, 2048);
+ test_memeq(cp, stuff+3000, 2048);
+ tt_int_op(3000, ==, buf_datalen(buf));
+ tt_int_op(fetch_from_buf(tmp, 3000, buf), ==, 0);
+ test_memeq(tmp, stuff+3000, 2048);
+
+ buf_free(buf);
+
+ /* Now try the large-chunk case. */
+ buf = buf_new_with_capacity(3000); /* rounds up to next power of 2. */
+ write_to_buf(stuff, 4000, buf);
+ write_to_buf(stuff+4000, 4000, buf);
+ write_to_buf(stuff+8000, 4000, buf);
+ write_to_buf(stuff+12000, 4000, buf);
+ tt_int_op(buf_datalen(buf), ==, 16000);
+ buf_get_first_chunk_data(buf, &cp, &sz);
+ tt_ptr_op(cp, !=, NULL);
+ tt_int_op(sz, <=, 4096);
+
+ buf_pullup(buf, 12500, 0);
+ assert_buf_ok(buf);
+ buf_get_first_chunk_data(buf, &cp, &sz);
+ tt_ptr_op(cp, !=, NULL);
+ tt_int_op(sz, >=, 12500);
+ test_memeq(cp, stuff, 12500);
+ tt_int_op(buf_datalen(buf), ==, 16000);
+
+ fetch_from_buf(tmp, 12400, buf);
+ test_memeq(tmp, stuff, 12400);
+ tt_int_op(buf_datalen(buf), ==, 3600);
+ fetch_from_buf(tmp, 3500, buf);
+ test_memeq(tmp, stuff+12400, 3500);
+ fetch_from_buf(tmp, 100, buf);
+ test_memeq(tmp, stuff+15900, 10);
+
+ buf_free(buf);
+
+ /* Make sure that the pull-up-whole-buffer case works */
+ buf = buf_new_with_capacity(3000); /* rounds up to next power of 2. */
+ write_to_buf(stuff, 4000, buf);
+ write_to_buf(stuff+4000, 4000, buf);
+ fetch_from_buf(tmp, 100, buf); /* dump 100 bytes from first chunk */
+ buf_pullup(buf, 16000, 0); /* Way too much. */
+ assert_buf_ok(buf);
+ buf_get_first_chunk_data(buf, &cp, &sz);
+ tt_ptr_op(cp, !=, NULL);
+ tt_int_op(sz, ==, 7900);
+ test_memeq(cp, stuff+100, 7900);
+
+ buf_free(buf);
+ buf = NULL;
+
+ buf_shrink_freelists(1);
+
+ tt_int_op(buf_get_total_allocation(), ==, 0);
+ done:
+ buf_free(buf);
+ buf_shrink_freelists(1);
+ tor_free(stuff);
+ tor_free(tmp);
+}
+
+static void
+test_buffer_copy(void *arg)
+{
+ generic_buffer_t *buf=NULL, *buf2=NULL;
+ const char *s;
+ size_t len;
+ char b[256];
+ int i;
+ (void)arg;
+
+ buf = generic_buffer_new();
+ tt_assert(buf);
+
+ /* Copy an empty buffer. */
+ tt_int_op(0, ==, generic_buffer_set_to_copy(&buf2, buf));
+ tt_assert(buf2);
+ tt_int_op(0, ==, generic_buffer_len(buf2));
+
+ /* Now try with a short buffer. */
+ s = "And now comes an act of enormous enormance!";
+ len = strlen(s);
+ generic_buffer_add(buf, s, len);
+ tt_int_op(len, ==, generic_buffer_len(buf));
+ /* Add junk to buf2 so we can test replacing.*/
+ generic_buffer_add(buf2, "BLARG", 5);
+ tt_int_op(0, ==, generic_buffer_set_to_copy(&buf2, buf));
+ tt_int_op(len, ==, generic_buffer_len(buf2));
+ generic_buffer_get(buf2, b, len);
+ test_mem_op(b, ==, s, len);
+ /* Now free buf2 and retry so we can test allocating */
+ generic_buffer_free(buf2);
+ buf2 = NULL;
+ tt_int_op(0, ==, generic_buffer_set_to_copy(&buf2, buf));
+ tt_int_op(len, ==, generic_buffer_len(buf2));
+ generic_buffer_get(buf2, b, len);
+ test_mem_op(b, ==, s, len);
+ /* Clear buf for next test */
+ generic_buffer_get(buf, b, len);
+ tt_int_op(generic_buffer_len(buf),==,0);
+
+ /* Okay, now let's try a bigger buffer. */
+ s = "Quis autem vel eum iure reprehenderit qui in ea voluptate velit "
+ "esse quam nihil molestiae consequatur, vel illum qui dolorem eum "
+ "fugiat quo voluptas nulla pariatur?";
+ len = strlen(s);
+ for (i = 0; i < 256; ++i) {
+ b[0]=i;
+ generic_buffer_add(buf, b, 1);
+ generic_buffer_add(buf, s, len);
+ }
+ tt_int_op(0, ==, generic_buffer_set_to_copy(&buf2, buf));
+ tt_int_op(generic_buffer_len(buf2), ==, generic_buffer_len(buf));
+ for (i = 0; i < 256; ++i) {
+ generic_buffer_get(buf2, b, len+1);
+ tt_int_op((unsigned char)b[0],==,i);
+ test_mem_op(b+1, ==, s, len);
+ }
+
+ done:
+ if (buf)
+ generic_buffer_free(buf);
+ if (buf2)
+ generic_buffer_free(buf2);
+ buf_shrink_freelists(1);
+}
+
+static void
+test_buffer_ext_or_cmd(void *arg)
+{
+ ext_or_cmd_t *cmd = NULL;
+ generic_buffer_t *buf = generic_buffer_new();
+ char *tmp = NULL;
+ (void) arg;
+
+ /* Empty -- should give "not there. */
+ tt_int_op(0, ==, generic_buffer_fetch_ext_or_cmd(buf, &cmd));
+ tt_ptr_op(NULL, ==, cmd);
+
+ /* Three bytes: shouldn't work. */
+ generic_buffer_add(buf, "\x00\x20\x00", 3);
+ tt_int_op(0, ==, generic_buffer_fetch_ext_or_cmd(buf, &cmd));
+ tt_ptr_op(NULL, ==, cmd);
+ tt_int_op(3, ==, generic_buffer_len(buf));
+
+ /* 0020 0000: That's a nil command. It should work. */
+ generic_buffer_add(buf, "\x00", 1);
+ tt_int_op(1, ==, generic_buffer_fetch_ext_or_cmd(buf, &cmd));
+ tt_ptr_op(NULL, !=, cmd);
+ tt_int_op(0x20, ==, cmd->cmd);
+ tt_int_op(0, ==, cmd->len);
+ tt_int_op(0, ==, generic_buffer_len(buf));
+ ext_or_cmd_free(cmd);
+ cmd = NULL;
+
+ /* Now try a length-6 command with one byte missing. */
+ generic_buffer_add(buf, "\x10\x21\x00\x06""abcde", 9);
+ tt_int_op(0, ==, generic_buffer_fetch_ext_or_cmd(buf, &cmd));
+ tt_ptr_op(NULL, ==, cmd);
+ generic_buffer_add(buf, "f", 1);
+ tt_int_op(1, ==, generic_buffer_fetch_ext_or_cmd(buf, &cmd));
+ tt_ptr_op(NULL, !=, cmd);
+ tt_int_op(0x1021, ==, cmd->cmd);
+ tt_int_op(6, ==, cmd->len);
+ test_mem_op("abcdef", ==, cmd->body, 6);
+ tt_int_op(0, ==, generic_buffer_len(buf));
+ ext_or_cmd_free(cmd);
+ cmd = NULL;
+
+ /* Now try a length-10 command with 4 extra bytes. */
+ generic_buffer_add(buf, "\xff\xff\x00\x0a"
+ "loremipsum\x10\x00\xff\xff", 18);
+ tt_int_op(1, ==, generic_buffer_fetch_ext_or_cmd(buf, &cmd));
+ tt_ptr_op(NULL, !=, cmd);
+ tt_int_op(0xffff, ==, cmd->cmd);
+ tt_int_op(10, ==, cmd->len);
+ test_mem_op("loremipsum", ==, cmd->body, 10);
+ tt_int_op(4, ==, generic_buffer_len(buf));
+ ext_or_cmd_free(cmd);
+ cmd = NULL;
+
+ /* Finally, let's try a maximum-length command. We already have the header
+ * waiting. */
+ tt_int_op(0, ==, generic_buffer_fetch_ext_or_cmd(buf, &cmd));
+ tmp = tor_malloc_zero(65535);
+ generic_buffer_add(buf, tmp, 65535);
+ tt_int_op(1, ==, generic_buffer_fetch_ext_or_cmd(buf, &cmd));
+ tt_ptr_op(NULL, !=, cmd);
+ tt_int_op(0x1000, ==, cmd->cmd);
+ tt_int_op(0xffff, ==, cmd->len);
+ test_mem_op(tmp, ==, cmd->body, 65535);
+ tt_int_op(0, ==, generic_buffer_len(buf));
+ ext_or_cmd_free(cmd);
+ cmd = NULL;
+
+ done:
+ ext_or_cmd_free(cmd);
+ generic_buffer_free(buf);
+ tor_free(tmp);
+ buf_shrink_freelists(1);
+}
+
+static void
+test_buffer_allocation_tracking(void *arg)
+{
+ char *junk = tor_malloc(16384);
+ buf_t *buf1 = NULL, *buf2 = NULL;
+ int i;
+
+ (void)arg;
+
+ crypto_rand(junk, 16384);
+ tt_int_op(buf_get_total_allocation(), ==, 0);
+
+ buf1 = buf_new();
+ tt_assert(buf1);
+ buf2 = buf_new();
+ tt_assert(buf2);
+
+ tt_int_op(buf_allocation(buf1), ==, 0);
+ tt_int_op(buf_get_total_allocation(), ==, 0);
+
+ write_to_buf(junk, 4000, buf1);
+ write_to_buf(junk, 4000, buf1);
+ write_to_buf(junk, 4000, buf1);
+ write_to_buf(junk, 4000, buf1);
+ tt_int_op(buf_allocation(buf1), ==, 16384);
+ fetch_from_buf(junk, 100, buf1);
+ tt_int_op(buf_allocation(buf1), ==, 16384); /* still 4 4k chunks */
+
+ tt_int_op(buf_get_total_allocation(), ==, 16384);
+
+ fetch_from_buf(junk, 4096, buf1); /* drop a 1k chunk... */
+ tt_int_op(buf_allocation(buf1), ==, 3*4096); /* now 3 4k chunks */
+
+#ifdef ENABLE_BUF_FREELISTS
+ tt_int_op(buf_get_total_allocation(), ==, 16384); /* that chunk went onto
+ the freelist. */
+#else
+ tt_int_op(buf_get_total_allocation(), ==, 12288); /* that chunk was really
+ freed. */
+#endif
+
+ write_to_buf(junk, 4000, buf2);
+ tt_int_op(buf_allocation(buf2), ==, 4096); /* another 4k chunk. */
+ /*
+ * If we're using freelists, size stays at 16384 because we just pulled a
+ * chunk from the freelist. If we aren't, we bounce back up to 16384 by
+ * allocating a new chunk.
+ */
+ tt_int_op(buf_get_total_allocation(), ==, 16384);
+ write_to_buf(junk, 4000, buf2);
+ tt_int_op(buf_allocation(buf2), ==, 8192); /* another 4k chunk. */
+ tt_int_op(buf_get_total_allocation(), ==, 5*4096); /* that chunk was new. */
+
+ /* Make a really huge buffer */
+ for (i = 0; i < 1000; ++i) {
+ write_to_buf(junk, 4000, buf2);
+ }
+ tt_int_op(buf_allocation(buf2), >=, 4008000);
+ tt_int_op(buf_get_total_allocation(), >=, 4008000);
+ buf_free(buf2);
+ buf2 = NULL;
+
+ tt_int_op(buf_get_total_allocation(), <, 4008000);
+ buf_shrink_freelists(1);
+ tt_int_op(buf_get_total_allocation(), ==, buf_allocation(buf1));
+ buf_free(buf1);
+ buf1 = NULL;
+ buf_shrink_freelists(1);
+ tt_int_op(buf_get_total_allocation(), ==, 0);
+
+ done:
+ buf_free(buf1);
+ buf_free(buf2);
+ buf_shrink_freelists(1);
+ tor_free(junk);
+}
+
+static void
+test_buffer_time_tracking(void *arg)
+{
+ buf_t *buf=NULL, *buf2=NULL;
+ struct timeval tv0;
+ const time_t START = 1389288246;
+ const uint32_t START_MSEC = (uint32_t) ((uint64_t)START * 1000);
+ int i;
+ char tmp[4096];
+ (void)arg;
+
+ crypto_rand(tmp, sizeof(tmp));
+
+ tv0.tv_sec = START;
+ tv0.tv_usec = 0;
+
+ buf = buf_new_with_capacity(3000); /* rounds up to next power of 2. */
+ tt_assert(buf);
+
+ /* Empty buffer means the timestamp is 0. */
+ tt_int_op(0, ==, buf_get_oldest_chunk_timestamp(buf, START_MSEC));
+ tt_int_op(0, ==, buf_get_oldest_chunk_timestamp(buf, START_MSEC+1000));
+
+ tor_gettimeofday_cache_set(&tv0);
+ write_to_buf("ABCDEFG", 7, buf);
+ tt_int_op(1000, ==, buf_get_oldest_chunk_timestamp(buf, START_MSEC+1000));
+
+ buf2 = buf_copy(buf);
+ tt_assert(buf2);
+ tt_int_op(1234, ==, buf_get_oldest_chunk_timestamp(buf2, START_MSEC+1234));
+
+ /* Now add more bytes; enough to overflow the first chunk. */
+ tv0.tv_usec += 123 * 1000;
+ tor_gettimeofday_cache_set(&tv0);
+ for (i = 0; i < 600; ++i)
+ write_to_buf("ABCDEFG", 7, buf);
+ tt_int_op(4207, ==, buf_datalen(buf));
+
+ /* The oldest bytes are still in the front. */
+ tt_int_op(2000, ==, buf_get_oldest_chunk_timestamp(buf, START_MSEC+2000));
+
+ /* Once those bytes are dropped, the chunk is still on the first
+ * timestamp. */
+ fetch_from_buf(tmp, 100, buf);
+ tt_int_op(2000, ==, buf_get_oldest_chunk_timestamp(buf, START_MSEC+2000));
+
+ /* But once we discard the whole first chunk, we get the data in the second
+ * chunk. */
+ fetch_from_buf(tmp, 4000, buf);
+ tt_int_op(107, ==, buf_datalen(buf));
+ tt_int_op(2000, ==, buf_get_oldest_chunk_timestamp(buf, START_MSEC+2123));
+
+ /* This time we'll be grabbing a chunk from the freelist, and making sure
+ its time gets updated */
+ tv0.tv_sec += 5;
+ tv0.tv_usec = 617*1000;
+ tor_gettimeofday_cache_set(&tv0);
+ for (i = 0; i < 600; ++i)
+ write_to_buf("ABCDEFG", 7, buf);
+ tt_int_op(4307, ==, buf_datalen(buf));
+
+ tt_int_op(2000, ==, buf_get_oldest_chunk_timestamp(buf, START_MSEC+2123));
+ fetch_from_buf(tmp, 4000, buf);
+ fetch_from_buf(tmp, 306, buf);
+ tt_int_op(0, ==, buf_get_oldest_chunk_timestamp(buf, START_MSEC+5617));
+ tt_int_op(383, ==, buf_get_oldest_chunk_timestamp(buf, START_MSEC+6000));
+
+ done:
+ buf_free(buf);
+ buf_free(buf2);
+}
+
+static void
+test_buffers_zlib_impl(int finalize_with_nil)
+{
+ char *msg = NULL;
+ char *contents = NULL;
+ char *expanded = NULL;
+ buf_t *buf = NULL;
+ tor_zlib_state_t *zlib_state = NULL;
+ size_t out_len, in_len;
+ int done;
+
+ buf = buf_new_with_capacity(128); /* will round up */
+ zlib_state = tor_zlib_new(1, ZLIB_METHOD);
+
+ msg = tor_malloc(512);
+ crypto_rand(msg, 512);
+ tt_int_op(write_to_buf_zlib(buf, zlib_state, msg, 128, 0), ==, 0);
+ tt_int_op(write_to_buf_zlib(buf, zlib_state, msg+128, 128, 0), ==, 0);
+ tt_int_op(write_to_buf_zlib(buf, zlib_state, msg+256, 256, 0), ==, 0);
+ done = !finalize_with_nil;
+ tt_int_op(write_to_buf_zlib(buf, zlib_state, "all done", 9, done), ==, 0);
+ if (finalize_with_nil) {
+ tt_int_op(write_to_buf_zlib(buf, zlib_state, "", 0, 1), ==, 0);
+ }
+
+ in_len = buf_datalen(buf);
+ contents = tor_malloc(in_len);
+
+ tt_int_op(fetch_from_buf(contents, in_len, buf), ==, 0);
+
+ tt_int_op(0, ==, tor_gzip_uncompress(&expanded, &out_len,
+ contents, in_len,
+ ZLIB_METHOD, 1,
+ LOG_WARN));
+
+ tt_int_op(out_len, >=, 128);
+ tt_mem_op(msg, ==, expanded, 128);
+ tt_int_op(out_len, >=, 512);
+ tt_mem_op(msg, ==, expanded, 512);
+ tt_int_op(out_len, ==, 512+9);
+ tt_mem_op("all done", ==, expanded+512, 9);
+
+ done:
+ buf_free(buf);
+ tor_zlib_free(zlib_state);
+ tor_free(contents);
+ tor_free(expanded);
+ tor_free(msg);
+}
+
+static void
+test_buffers_zlib(void *arg)
+{
+ (void) arg;
+ test_buffers_zlib_impl(0);
+}
+static void
+test_buffers_zlib_fin_with_nil(void *arg)
+{
+ (void) arg;
+ test_buffers_zlib_impl(1);
+}
+
+static void
+test_buffers_zlib_fin_at_chunk_end(void *arg)
+{
+ char *msg = NULL;
+ char *contents = NULL;
+ char *expanded = NULL;
+ buf_t *buf = NULL;
+ tor_zlib_state_t *zlib_state = NULL;
+ size_t out_len, in_len;
+ size_t sz, headerjunk;
+ (void) arg;
+
+ buf = buf_new_with_capacity(128); /* will round up */
+ sz = buf_get_default_chunk_size(buf);
+ msg = tor_malloc_zero(sz);
+
+ write_to_buf(msg, 1, buf);
+ tt_assert(buf->head);
+
+ /* Fill up the chunk so the zlib stuff won't fit in one chunk. */
+ tt_uint_op(buf->head->memlen, <, sz);
+ headerjunk = buf->head->memlen - 7;
+ write_to_buf(msg, headerjunk-1, buf);
+ tt_uint_op(buf->head->datalen, ==, headerjunk);
+ printf("<%u>\n", (unsigned)buf_datalen(buf));
+ tt_uint_op(buf_datalen(buf), ==, headerjunk);
+ /* Write an empty string, with finalization on. */
+ zlib_state = tor_zlib_new(1, ZLIB_METHOD);
+ tt_int_op(write_to_buf_zlib(buf, zlib_state, "", 0, 1), ==, 0);
+
+ printf("<%u>\n", (unsigned)buf_datalen(buf));
+
+ in_len = buf_datalen(buf);
+ contents = tor_malloc(in_len);
+
+ tt_int_op(fetch_from_buf(contents, in_len, buf), ==, 0);
+
+ tt_uint_op(in_len, >, headerjunk);
+
+ tt_int_op(0, ==, tor_gzip_uncompress(&expanded, &out_len,
+ contents + headerjunk, in_len - headerjunk,
+ ZLIB_METHOD, 1,
+ LOG_WARN));
+
+ tt_int_op(out_len, ==, 0);
+ tt_assert(expanded);
+
+ done:
+ buf_free(buf);
+ tor_zlib_free(zlib_state);
+ tor_free(contents);
+ tor_free(expanded);
+ tor_free(msg);
+}
+
+struct testcase_t buffer_tests[] = {
+ { "basic", test_buffers_basic, TT_FORK, NULL, NULL },
+ { "copy", test_buffer_copy, TT_FORK, NULL, NULL },
+ { "pullup", test_buffer_pullup, TT_FORK, NULL, NULL },
+ { "ext_or_cmd", test_buffer_ext_or_cmd, TT_FORK, NULL, NULL },
+ { "allocation_tracking", test_buffer_allocation_tracking, TT_FORK,
+ NULL, NULL },
+ { "time_tracking", test_buffer_time_tracking, TT_FORK, NULL, NULL },
+ { "zlib", test_buffers_zlib, TT_FORK, NULL, NULL },
+ { "zlib_fin_with_nil", test_buffers_zlib_fin_with_nil, TT_FORK, NULL, NULL },
+ { "zlib_fin_at_chunk_end", test_buffers_zlib_fin_at_chunk_end, TT_FORK,
+ NULL, NULL},
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_cell_formats.c b/src/test/test_cell_formats.c
index 55d8d0f00..d7f60680c 100644
--- a/src/test/test_cell_formats.c
+++ b/src/test/test_cell_formats.c
@@ -8,7 +8,9 @@
#define CONNECTION_EDGE_PRIVATE
#define RELAY_PRIVATE
#include "or.h"
+#include "channel.h"
#include "connection_edge.h"
+#include "connection_or.h"
#include "onion.h"
#include "onion_tap.h"
#include "onion_fast.h"
@@ -872,6 +874,387 @@ test_cfmt_extended_cells(void *arg)
tor_free(mem_op_hex_tmp);
}
+static void
+test_cfmt_resolved_cells(void *arg)
+{
+ smartlist_t *addrs = smartlist_new();
+ relay_header_t rh;
+ cell_t cell;
+ int r, errcode;
+ address_ttl_t *a;
+
+ (void)arg;
+#define CLEAR_CELL() do { \
+ memset(&cell, 0, sizeof(cell)); \
+ memset(&rh, 0, sizeof(rh)); \
+ } while (0)
+#define CLEAR_ADDRS() do { \
+ SMARTLIST_FOREACH(addrs, address_ttl_t *, a, \
+ address_ttl_free(a); ); \
+ smartlist_clear(addrs); \
+ } while (0)
+#define SET_CELL(s) do { \
+ CLEAR_CELL(); \
+ memcpy(cell.payload + RELAY_HEADER_SIZE, (s), sizeof((s))-1); \
+ rh.length = sizeof((s))-1; \
+ rh.command = RELAY_COMMAND_RESOLVED; \
+ errcode = -1; \
+ } while (0)
+
+ /* The cell format is one or more answers; each of the form
+ * type [1 byte---0:hostname, 4:ipv4, 6:ipv6, f0:err-transient, f1:err]
+ * length [1 byte]
+ * body [length bytes]
+ * ttl [4 bytes]
+ */
+
+ /* Let's try an empty cell */
+ SET_CELL("");
+ r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
+ tt_int_op(errcode, ==, 0);
+ tt_int_op(r, ==, 0);
+ tt_int_op(smartlist_len(addrs), ==, 0);
+ CLEAR_ADDRS(); /* redundant but let's be consistent */
+
+ /* Cell with one ipv4 addr */
+ SET_CELL("\x04\x04" "\x7f\x00\x02\x0a" "\x00\00\x01\x00");
+ tt_int_op(rh.length, ==, 10);
+ r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
+ tt_int_op(errcode, ==, 0);
+ tt_int_op(r, ==, 0);
+ tt_int_op(smartlist_len(addrs), ==, 1);
+ a = smartlist_get(addrs, 0);
+ tt_str_op(fmt_addr(&a->addr), ==, "127.0.2.10");
+ tt_ptr_op(a->hostname, ==, NULL);
+ tt_int_op(a->ttl, ==, 256);
+ CLEAR_ADDRS();
+
+ /* Cell with one ipv6 addr */
+ SET_CELL("\x06\x10"
+ "\x20\x02\x90\x90\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\xf0\xf0\xab\xcd"
+ "\x02\00\x00\x01");
+ tt_int_op(rh.length, ==, 22);
+ r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
+ tt_int_op(errcode, ==, 0);
+ tt_int_op(r, ==, 0);
+ tt_int_op(smartlist_len(addrs), ==, 1);
+ a = smartlist_get(addrs, 0);
+ tt_str_op(fmt_addr(&a->addr), ==, "2002:9090::f0f0:abcd");
+ tt_ptr_op(a->hostname, ==, NULL);
+ tt_int_op(a->ttl, ==, 0x2000001);
+ CLEAR_ADDRS();
+
+ /* Cell with one hostname */
+ SET_CELL("\x00\x11"
+ "motherbrain.zebes"
+ "\x00\00\x00\x00");
+ tt_int_op(rh.length, ==, 23);
+ r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
+ tt_int_op(errcode, ==, 0);
+ tt_int_op(r, ==, 0);
+ tt_int_op(smartlist_len(addrs), ==, 1);
+ a = smartlist_get(addrs, 0);
+ tt_assert(tor_addr_is_null(&a->addr));
+ tt_str_op(a->hostname, ==, "motherbrain.zebes");
+ tt_int_op(a->ttl, ==, 0);
+ CLEAR_ADDRS();
+
+#define LONG_NAME \
+ "this-hostname-has-255-characters.in-order-to-test-whether-very-long.ho" \
+ "stnames-are-accepted.i-am-putting-it-in-a-macro-because-although.this-" \
+ "function-is-already-very-full.of-copy-and-pasted-stuff.having-this-app" \
+ "ear-more-than-once-would-bother-me-somehow.is"
+
+ tt_int_op(strlen(LONG_NAME), ==, 255);
+ SET_CELL("\x00\xff"
+ LONG_NAME
+ "\x00\01\x00\x00");
+ tt_int_op(rh.length, ==, 261);
+ r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
+ tt_int_op(errcode, ==, 0);
+ tt_int_op(r, ==, 0);
+ tt_int_op(smartlist_len(addrs), ==, 1);
+ a = smartlist_get(addrs, 0);
+ tt_assert(tor_addr_is_null(&a->addr));
+ tt_str_op(a->hostname, ==, LONG_NAME);
+ tt_int_op(a->ttl, ==, 65536);
+ CLEAR_ADDRS();
+
+ /* Cells with an error */
+ SET_CELL("\xf0\x2b"
+ "I'm sorry, Dave. I'm afraid I can't do that"
+ "\x00\x11\x22\x33");
+ tt_int_op(rh.length, ==, 49);
+ r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
+ tt_int_op(errcode, ==, RESOLVED_TYPE_ERROR_TRANSIENT);
+ tt_int_op(r, ==, 0);
+ tt_int_op(smartlist_len(addrs), ==, 0);
+ CLEAR_ADDRS();
+
+ SET_CELL("\xf1\x40"
+ "This hostname is too important for me to allow you to resolve it"
+ "\x00\x00\x00\x00");
+ tt_int_op(rh.length, ==, 70);
+ r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
+ tt_int_op(errcode, ==, RESOLVED_TYPE_ERROR);
+ tt_int_op(r, ==, 0);
+ tt_int_op(smartlist_len(addrs), ==, 0);
+ CLEAR_ADDRS();
+
+ /* Cell with an unrecognized type */
+ SET_CELL("\xee\x16"
+ "fault in the AE35 unit"
+ "\x09\x09\x01\x01");
+ tt_int_op(rh.length, ==, 28);
+ r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
+ tt_int_op(errcode, ==, 0);
+ tt_int_op(r, ==, 0);
+ tt_int_op(smartlist_len(addrs), ==, 0);
+ CLEAR_ADDRS();
+
+ /* Cell with one of each */
+ SET_CELL(/* unrecognized: */
+ "\xee\x16"
+ "fault in the AE35 unit"
+ "\x09\x09\x01\x01"
+ /* error: */
+ "\xf0\x2b"
+ "I'm sorry, Dave. I'm afraid I can't do that"
+ "\x00\x11\x22\x33"
+ /* IPv6: */
+ "\x06\x10"
+ "\x20\x02\x90\x90\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\xf0\xf0\xab\xcd"
+ "\x02\00\x00\x01"
+ /* IPv4: */
+ "\x04\x04" "\x7f\x00\x02\x0a" "\x00\00\x01\x00"
+ /* Hostname: */
+ "\x00\x11"
+ "motherbrain.zebes"
+ "\x00\00\x00\x00"
+ );
+ r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
+ tt_int_op(errcode, ==, 0); /* no error reported; we got answers */
+ tt_int_op(r, ==, 0);
+ tt_int_op(smartlist_len(addrs), ==, 3);
+ a = smartlist_get(addrs, 0);
+ tt_str_op(fmt_addr(&a->addr), ==, "2002:9090::f0f0:abcd");
+ tt_ptr_op(a->hostname, ==, NULL);
+ tt_int_op(a->ttl, ==, 0x2000001);
+ a = smartlist_get(addrs, 1);
+ tt_str_op(fmt_addr(&a->addr), ==, "127.0.2.10");
+ tt_ptr_op(a->hostname, ==, NULL);
+ tt_int_op(a->ttl, ==, 256);
+ a = smartlist_get(addrs, 2);
+ tt_assert(tor_addr_is_null(&a->addr));
+ tt_str_op(a->hostname, ==, "motherbrain.zebes");
+ tt_int_op(a->ttl, ==, 0);
+ CLEAR_ADDRS();
+
+ /* Cell with several of similar type */
+ SET_CELL(/* IPv4 */
+ "\x04\x04" "\x7f\x00\x02\x0a" "\x00\00\x01\x00"
+ "\x04\x04" "\x08\x08\x08\x08" "\x00\00\x01\x05"
+ "\x04\x04" "\x7f\xb0\x02\xb0" "\x00\01\xff\xff"
+ /* IPv6 */
+ "\x06\x10"
+ "\x20\x02\x90\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\xca\xfe\xf0\x0d"
+ "\x00\00\x00\x01"
+ "\x06\x10"
+ "\x20\x02\x90\x01\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\xfa\xca\xde"
+ "\x00\00\x00\x03");
+ r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
+ tt_int_op(errcode, ==, 0);
+ tt_int_op(r, ==, 0);
+ tt_int_op(smartlist_len(addrs), ==, 5);
+ a = smartlist_get(addrs, 0);
+ tt_str_op(fmt_addr(&a->addr), ==, "127.0.2.10");
+ tt_ptr_op(a->hostname, ==, NULL);
+ tt_int_op(a->ttl, ==, 256);
+ a = smartlist_get(addrs, 1);
+ tt_str_op(fmt_addr(&a->addr), ==, "8.8.8.8");
+ tt_ptr_op(a->hostname, ==, NULL);
+ tt_int_op(a->ttl, ==, 261);
+ a = smartlist_get(addrs, 2);
+ tt_str_op(fmt_addr(&a->addr), ==, "127.176.2.176");
+ tt_ptr_op(a->hostname, ==, NULL);
+ tt_int_op(a->ttl, ==, 131071);
+ a = smartlist_get(addrs, 3);
+ tt_str_op(fmt_addr(&a->addr), ==, "2002:9000::cafe:f00d");
+ tt_ptr_op(a->hostname, ==, NULL);
+ tt_int_op(a->ttl, ==, 1);
+ a = smartlist_get(addrs, 4);
+ tt_str_op(fmt_addr(&a->addr), ==, "2002:9001::fa:cade");
+ tt_ptr_op(a->hostname, ==, NULL);
+ tt_int_op(a->ttl, ==, 3);
+ CLEAR_ADDRS();
+
+ /* Full cell */
+#define LONG_NAME2 \
+ "this-name-has-231-characters.so-that-it-plus-LONG_NAME-can-completely-" \
+ "fill-up-the-payload-of-a-cell.its-important-to-check-for-the-full-thin" \
+ "g-case.to-avoid-off-by-one-errors.where-full-things-are-misreported-as" \
+ ".overflowing-by-one.z"
+
+ tt_int_op(strlen(LONG_NAME2), ==, 231);
+ SET_CELL("\x00\xff"
+ LONG_NAME
+ "\x00\01\x00\x00"
+ "\x00\xe7"
+ LONG_NAME2
+ "\x00\01\x00\x00");
+ tt_int_op(rh.length, ==, RELAY_PAYLOAD_SIZE);
+ r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
+ tt_int_op(errcode, ==, 0);
+ tt_int_op(r, ==, 0);
+ tt_int_op(smartlist_len(addrs), ==, 2);
+ a = smartlist_get(addrs, 0);
+ tt_str_op(a->hostname, ==, LONG_NAME);
+ a = smartlist_get(addrs, 1);
+ tt_str_op(a->hostname, ==, LONG_NAME2);
+ CLEAR_ADDRS();
+
+ /* BAD CELLS */
+
+ /* Invalid length on an IPv4 */
+ SET_CELL("\x04\x03zzz1234");
+ r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
+ tt_int_op(errcode, ==, 0);
+ tt_int_op(r, ==, -1);
+ tt_int_op(smartlist_len(addrs), ==, 0);
+ SET_CELL("\x04\x04" "\x7f\x00\x02\x0a" "\x00\00\x01\x00"
+ "\x04\x05zzzzz1234");
+ r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
+ tt_int_op(errcode, ==, 0);
+ tt_int_op(r, ==, -1);
+ tt_int_op(smartlist_len(addrs), ==, 0);
+
+ /* Invalid length on an IPv6 */
+ SET_CELL("\x06\x03zzz1234");
+ r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
+ tt_int_op(errcode, ==, 0);
+ tt_int_op(r, ==, -1);
+ tt_int_op(smartlist_len(addrs), ==, 0);
+ SET_CELL("\x04\x04" "\x7f\x00\x02\x0a" "\x00\00\x01\x00"
+ "\x06\x17wwwwwwwwwwwwwwwww1234");
+ r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
+ tt_int_op(errcode, ==, 0);
+ tt_int_op(r, ==, -1);
+ tt_int_op(smartlist_len(addrs), ==, 0);
+ SET_CELL("\x04\x04" "\x7f\x00\x02\x0a" "\x00\00\x01\x00"
+ "\x06\x10xxxx");
+ r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
+ tt_int_op(errcode, ==, 0);
+ tt_int_op(r, ==, -1);
+ tt_int_op(smartlist_len(addrs), ==, 0);
+
+ /* Empty hostname */
+ SET_CELL("\x00\x00xxxx");
+ r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
+ tt_int_op(errcode, ==, 0);
+ tt_int_op(r, ==, -1);
+ tt_int_op(smartlist_len(addrs), ==, 0);
+
+ /* rh.length out of range */
+ CLEAR_CELL();
+ rh.length = 499;
+ r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
+ tt_int_op(errcode, ==, 0);
+ tt_int_op(r, ==, -1);
+ tt_int_op(smartlist_len(addrs), ==, 0);
+
+ /* Item length extends beyond rh.length */
+ CLEAR_CELL();
+ SET_CELL("\x00\xff"
+ LONG_NAME
+ "\x00\01\x00\x00");
+ rh.length -= 1;
+ r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
+ tt_int_op(r, ==, -1);
+ tt_int_op(smartlist_len(addrs), ==, 0);
+ rh.length -= 5;
+ r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
+ tt_int_op(r, ==, -1);
+ tt_int_op(smartlist_len(addrs), ==, 0);
+
+ SET_CELL("\x04\x04" "\x7f\x00\x02\x0a" "\x00\00\x01\x00");
+ rh.length -= 1;
+ r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
+ tt_int_op(r, ==, -1);
+ tt_int_op(smartlist_len(addrs), ==, 0);
+
+ SET_CELL("\xee\x10"
+ "\x20\x02\x90\x01\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\xfa\xca\xde"
+ "\x00\00\x00\x03");
+ rh.length -= 1;
+ r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
+ tt_int_op(r, ==, -1);
+ tt_int_op(smartlist_len(addrs), ==, 0);
+
+ /* Truncated item after first character */
+ SET_CELL("\x04");
+ r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
+ tt_int_op(r, ==, -1);
+ tt_int_op(smartlist_len(addrs), ==, 0);
+
+ SET_CELL("\xee");
+ r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
+ tt_int_op(r, ==, -1);
+ tt_int_op(smartlist_len(addrs), ==, 0);
+
+ done:
+ CLEAR_ADDRS();
+ CLEAR_CELL();
+ smartlist_free(addrs);
+#undef CLEAR_ADDRS
+#undef CLEAR_CELL
+}
+
+static void
+test_cfmt_is_destroy(void *arg)
+{
+ cell_t cell;
+ packed_cell_t packed;
+ circid_t circid = 0;
+ channel_t *chan;
+ (void)arg;
+
+ chan = tor_malloc_zero(sizeof(channel_t));
+
+ memset(&cell, 0xff, sizeof(cell));
+ cell.circ_id = 3003;
+ cell.command = CELL_RELAY;
+
+ cell_pack(&packed, &cell, 0);
+ chan->wide_circ_ids = 0;
+ tt_assert(! packed_cell_is_destroy(chan, &packed, &circid));
+ tt_int_op(circid, ==, 0);
+
+ cell_pack(&packed, &cell, 1);
+ chan->wide_circ_ids = 1;
+ tt_assert(! packed_cell_is_destroy(chan, &packed, &circid));
+ tt_int_op(circid, ==, 0);
+
+ cell.command = CELL_DESTROY;
+
+ cell_pack(&packed, &cell, 0);
+ chan->wide_circ_ids = 0;
+ tt_assert(packed_cell_is_destroy(chan, &packed, &circid));
+ tt_int_op(circid, ==, 3003);
+
+ circid = 0;
+ cell_pack(&packed, &cell, 1);
+ chan->wide_circ_ids = 1;
+ tt_assert(packed_cell_is_destroy(chan, &packed, &circid));
+
+ done:
+ tor_free(chan);
+}
+
#define TEST(name, flags) \
{ #name, test_cfmt_ ## name, flags, 0, NULL }
@@ -883,6 +1266,8 @@ struct testcase_t cell_format_tests[] = {
TEST(created_cells, 0),
TEST(extend_cells, 0),
TEST(extended_cells, 0),
+ TEST(resolved_cells, 0),
+ TEST(is_destroy, 0),
END_OF_TESTCASES
};
diff --git a/src/test/test_cell_queue.c b/src/test/test_cell_queue.c
new file mode 100644
index 000000000..92629823e
--- /dev/null
+++ b/src/test/test_cell_queue.c
@@ -0,0 +1,158 @@
+/* Copyright (c) 2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#define CIRCUITLIST_PRIVATE
+#define RELAY_PRIVATE
+#include "or.h"
+#include "circuitlist.h"
+#include "relay.h"
+#include "test.h"
+
+static void
+test_cq_manip(void *arg)
+{
+ packed_cell_t *pc1=NULL, *pc2=NULL, *pc3=NULL, *pc4=NULL, *pc_tmp=NULL;
+ cell_queue_t cq;
+ cell_t cell;
+ (void) arg;
+
+#ifdef ENABLE_MEMPOOLS
+ init_cell_pool();
+#endif /* ENABLE_MEMPOOLS */
+
+ cell_queue_init(&cq);
+ tt_int_op(cq.n, ==, 0);
+
+ pc1 = packed_cell_new();
+ pc2 = packed_cell_new();
+ pc3 = packed_cell_new();
+ pc4 = packed_cell_new();
+ tt_assert(pc1 && pc2 && pc3 && pc4);
+
+ tt_ptr_op(NULL, ==, cell_queue_pop(&cq));
+
+ /* Add and remove a singleton. */
+ cell_queue_append(&cq, pc1);
+ tt_int_op(cq.n, ==, 1);
+ tt_ptr_op(pc1, ==, cell_queue_pop(&cq));
+ tt_int_op(cq.n, ==, 0);
+
+ /* Add and remove four items */
+ cell_queue_append(&cq, pc4);
+ cell_queue_append(&cq, pc3);
+ cell_queue_append(&cq, pc2);
+ cell_queue_append(&cq, pc1);
+ tt_int_op(cq.n, ==, 4);
+ tt_ptr_op(pc4, ==, cell_queue_pop(&cq));
+ tt_ptr_op(pc3, ==, cell_queue_pop(&cq));
+ tt_ptr_op(pc2, ==, cell_queue_pop(&cq));
+ tt_ptr_op(pc1, ==, cell_queue_pop(&cq));
+ tt_int_op(cq.n, ==, 0);
+ tt_ptr_op(NULL, ==, cell_queue_pop(&cq));
+
+ /* Try a packed copy (wide, then narrow, which is a bit of a cheat, since a
+ * real cell queue has only one type.) */
+ memset(&cell, 0, sizeof(cell));
+ cell.circ_id = 0x12345678;
+ cell.command = 10;
+ strlcpy((char*)cell.payload, "Lorax ipsum gruvvulus thneed amet, snergelly "
+ "once-ler lerkim, sed do barbaloot tempor gluppitus ut labore et "
+ "truffula magna aliqua.",
+ sizeof(cell.payload));
+ cell_queue_append_packed_copy(NULL /*circ*/, &cq, 0 /*exitward*/, &cell,
+ 1 /*wide*/, 0 /*stats*/);
+ cell.circ_id = 0x2013;
+ cell_queue_append_packed_copy(NULL /*circ*/, &cq, 0 /*exitward*/, &cell,
+ 0 /*wide*/, 0 /*stats*/);
+ tt_int_op(cq.n, ==, 2);
+
+ pc_tmp = cell_queue_pop(&cq);
+ tt_int_op(cq.n, ==, 1);
+ tt_ptr_op(pc_tmp, !=, NULL);
+ test_mem_op(pc_tmp->body, ==, "\x12\x34\x56\x78\x0a", 5);
+ test_mem_op(pc_tmp->body+5, ==, cell.payload, sizeof(cell.payload));
+ packed_cell_free(pc_tmp);
+
+ pc_tmp = cell_queue_pop(&cq);
+ tt_int_op(cq.n, ==, 0);
+ tt_ptr_op(pc_tmp, !=, NULL);
+ test_mem_op(pc_tmp->body, ==, "\x20\x13\x0a", 3);
+ test_mem_op(pc_tmp->body+3, ==, cell.payload, sizeof(cell.payload));
+ packed_cell_free(pc_tmp);
+ pc_tmp = NULL;
+
+ tt_ptr_op(NULL, ==, cell_queue_pop(&cq));
+
+ /* Now make sure cell_queue_clear works. */
+ cell_queue_append(&cq, pc2);
+ cell_queue_append(&cq, pc1);
+ tt_int_op(cq.n, ==, 2);
+ cell_queue_clear(&cq);
+ pc2 = pc1 = NULL; /* prevent double-free */
+ tt_int_op(cq.n, ==, 0);
+
+ done:
+ packed_cell_free(pc1);
+ packed_cell_free(pc2);
+ packed_cell_free(pc3);
+ packed_cell_free(pc4);
+ packed_cell_free(pc_tmp);
+
+ cell_queue_clear(&cq);
+
+#ifdef ENABLE_MEMPOOLS
+ free_cell_pool();
+#endif /* ENABLE_MEMPOOLS */
+}
+
+static void
+test_circuit_n_cells(void *arg)
+{
+ packed_cell_t *pc1=NULL, *pc2=NULL, *pc3=NULL, *pc4=NULL, *pc5=NULL;
+ origin_circuit_t *origin_c=NULL;
+ or_circuit_t *or_c=NULL;
+
+ (void)arg;
+
+#ifdef ENABLE_MEMPOOLS
+ init_cell_pool();
+#endif /* ENABLE_MEMPOOLS */
+
+ pc1 = packed_cell_new();
+ pc2 = packed_cell_new();
+ pc3 = packed_cell_new();
+ pc4 = packed_cell_new();
+ pc5 = packed_cell_new();
+ tt_assert(pc1 && pc2 && pc3 && pc4 && pc5);
+
+ or_c = or_circuit_new(0, NULL);
+ origin_c = origin_circuit_new();
+ origin_c->base_.purpose = CIRCUIT_PURPOSE_C_GENERAL;
+
+ tt_int_op(n_cells_in_circ_queues(TO_CIRCUIT(or_c)), ==, 0);
+ cell_queue_append(&or_c->p_chan_cells, pc1);
+ tt_int_op(n_cells_in_circ_queues(TO_CIRCUIT(or_c)), ==, 1);
+ cell_queue_append(&or_c->base_.n_chan_cells, pc2);
+ cell_queue_append(&or_c->base_.n_chan_cells, pc3);
+ tt_int_op(n_cells_in_circ_queues(TO_CIRCUIT(or_c)), ==, 3);
+
+ tt_int_op(n_cells_in_circ_queues(TO_CIRCUIT(origin_c)), ==, 0);
+ cell_queue_append(&origin_c->base_.n_chan_cells, pc4);
+ cell_queue_append(&origin_c->base_.n_chan_cells, pc5);
+ tt_int_op(n_cells_in_circ_queues(TO_CIRCUIT(origin_c)), ==, 2);
+
+ done:
+ circuit_free(TO_CIRCUIT(or_c));
+ circuit_free(TO_CIRCUIT(origin_c));
+
+#ifdef ENABLE_MEMPOOLS
+ free_cell_pool();
+#endif /* ENABLE_MEMPOOLS */
+}
+
+struct testcase_t cell_queue_tests[] = {
+ { "basic", test_cq_manip, TT_FORK, NULL, NULL, },
+ { "circ_n_cells", test_circuit_n_cells, TT_FORK, 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..b19edd1fd
--- /dev/null
+++ b/src/test/test_circuitlist.c
@@ -0,0 +1,342 @@
+/* Copyright (c) 2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#define TOR_CHANNEL_INTERNAL_
+#define CIRCUITBUILD_PRIVATE
+#define CIRCUITLIST_PRIVATE
+#include "or.h"
+#include "channel.h"
+#include "circuitbuild.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_int_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:
+ if (or_c1)
+ circuit_free(TO_CIRCUIT(or_c1));
+ if (or_c2)
+ circuit_free(TO_CIRCUIT(or_c2));
+ tor_free(ch1);
+ tor_free(ch2);
+ tor_free(ch3);
+ UNMOCK(circuitmux_attach_circuit);
+ UNMOCK(circuitmux_detach_circuit);
+}
+
+static void
+test_rend_token_maps(void *arg)
+{
+ or_circuit_t *c1, *c2, *c3, *c4;
+ const uint8_t tok1[REND_TOKEN_LEN] = "The cat can't tell y";
+ const uint8_t tok2[REND_TOKEN_LEN] = "ou its name, and it ";
+ const uint8_t tok3[REND_TOKEN_LEN] = "doesn't really care.";
+ /* -- Adapted from a quote by Fredrik Lundh. */
+
+ (void)arg;
+ (void)tok1; //xxxx
+ c1 = or_circuit_new(0, NULL);
+ c2 = or_circuit_new(0, NULL);
+ c3 = or_circuit_new(0, NULL);
+ c4 = or_circuit_new(0, NULL);
+
+ /* Make sure we really filled up the tok* variables */
+ tt_int_op(tok1[REND_TOKEN_LEN-1], ==, 'y');
+ tt_int_op(tok2[REND_TOKEN_LEN-1], ==, ' ');
+ tt_int_op(tok3[REND_TOKEN_LEN-1], ==, '.');
+
+ /* No maps; nothing there. */
+ tt_ptr_op(NULL, ==, circuit_get_rendezvous(tok1));
+ tt_ptr_op(NULL, ==, circuit_get_intro_point(tok1));
+
+ circuit_set_rendezvous_cookie(c1, tok1);
+ circuit_set_intro_point_digest(c2, tok2);
+
+ tt_ptr_op(NULL, ==, circuit_get_rendezvous(tok3));
+ tt_ptr_op(NULL, ==, circuit_get_intro_point(tok3));
+ tt_ptr_op(NULL, ==, circuit_get_rendezvous(tok2));
+ tt_ptr_op(NULL, ==, circuit_get_intro_point(tok1));
+
+ /* Without purpose set, we don't get the circuits */
+ tt_ptr_op(NULL, ==, circuit_get_rendezvous(tok1));
+ tt_ptr_op(NULL, ==, circuit_get_intro_point(tok2));
+
+ c1->base_.purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING;
+ c2->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT;
+
+ /* Okay, make sure they show up now. */
+ tt_ptr_op(c1, ==, circuit_get_rendezvous(tok1));
+ tt_ptr_op(c2, ==, circuit_get_intro_point(tok2));
+
+ /* Two items at the same place with the same token. */
+ c3->base_.purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING;
+ circuit_set_rendezvous_cookie(c3, tok2);
+ tt_ptr_op(c2, ==, circuit_get_intro_point(tok2));
+ tt_ptr_op(c3, ==, circuit_get_rendezvous(tok2));
+
+ /* Marking a circuit makes it not get returned any more */
+ circuit_mark_for_close(TO_CIRCUIT(c1), END_CIRC_REASON_FINISHED);
+ tt_ptr_op(NULL, ==, circuit_get_rendezvous(tok1));
+ circuit_free(TO_CIRCUIT(c1));
+ c1 = NULL;
+
+ /* Freeing a circuit makes it not get returned any more. */
+ circuit_free(TO_CIRCUIT(c2));
+ c2 = NULL;
+ tt_ptr_op(NULL, ==, circuit_get_intro_point(tok2));
+
+ /* c3 -- are you still there? */
+ tt_ptr_op(c3, ==, circuit_get_rendezvous(tok2));
+ /* Change its cookie. This never happens in Tor per se, but hey. */
+ c3->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT;
+ circuit_set_intro_point_digest(c3, tok3);
+
+ tt_ptr_op(NULL, ==, circuit_get_rendezvous(tok2));
+ tt_ptr_op(c3, ==, circuit_get_intro_point(tok3));
+
+ /* Now replace c3 with c4. */
+ c4->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT;
+ circuit_set_intro_point_digest(c4, tok3);
+
+ tt_ptr_op(c4, ==, circuit_get_intro_point(tok3));
+
+ tt_ptr_op(c3->rendinfo, ==, NULL);
+ tt_ptr_op(c4->rendinfo, !=, NULL);
+ test_mem_op(c4->rendinfo, ==, tok3, REND_TOKEN_LEN);
+
+ /* Now clear c4's cookie. */
+ circuit_set_intro_point_digest(c4, NULL);
+ tt_ptr_op(c4->rendinfo, ==, NULL);
+ tt_ptr_op(NULL, ==, circuit_get_intro_point(tok3));
+
+ done:
+ if (c1)
+ circuit_free(TO_CIRCUIT(c1));
+ if (c2)
+ circuit_free(TO_CIRCUIT(c2));
+ if (c3)
+ circuit_free(TO_CIRCUIT(c3));
+ if (c4)
+ circuit_free(TO_CIRCUIT(c4));
+}
+
+static void
+test_pick_circid(void *arg)
+{
+ bitarray_t *ba = NULL;
+ channel_t *chan1, *chan2;
+ circid_t circid;
+ int i;
+ (void) arg;
+
+ chan1 = tor_malloc_zero(sizeof(channel_t));
+ chan2 = tor_malloc_zero(sizeof(channel_t));
+ chan2->wide_circ_ids = 1;
+
+ chan1->circ_id_type = CIRC_ID_TYPE_NEITHER;
+ tt_int_op(0, ==, get_unique_circ_id_by_chan(chan1));
+
+ /* Basic tests, with no collisions */
+ chan1->circ_id_type = CIRC_ID_TYPE_LOWER;
+ for (i = 0; i < 50; ++i) {
+ circid = get_unique_circ_id_by_chan(chan1);
+ tt_uint_op(0, <, circid);
+ tt_uint_op(circid, <, (1<<15));
+ }
+ chan1->circ_id_type = CIRC_ID_TYPE_HIGHER;
+ for (i = 0; i < 50; ++i) {
+ circid = get_unique_circ_id_by_chan(chan1);
+ tt_uint_op((1<<15), <, circid);
+ tt_uint_op(circid, <, (1<<16));
+ }
+
+ chan2->circ_id_type = CIRC_ID_TYPE_LOWER;
+ for (i = 0; i < 50; ++i) {
+ circid = get_unique_circ_id_by_chan(chan2);
+ tt_uint_op(0, <, circid);
+ tt_uint_op(circid, <, (1u<<31));
+ }
+ chan2->circ_id_type = CIRC_ID_TYPE_HIGHER;
+ for (i = 0; i < 50; ++i) {
+ circid = get_unique_circ_id_by_chan(chan2);
+ tt_uint_op((1u<<31), <, circid);
+ }
+
+ /* Now make sure that we can behave well when we are full up on circuits */
+ chan1->circ_id_type = CIRC_ID_TYPE_LOWER;
+ chan2->circ_id_type = CIRC_ID_TYPE_LOWER;
+ chan1->wide_circ_ids = chan2->wide_circ_ids = 0;
+ ba = bitarray_init_zero((1<<15));
+ for (i = 0; i < (1<<15); ++i) {
+ circid = get_unique_circ_id_by_chan(chan1);
+ if (circid == 0) {
+ tt_int_op(i, >, (1<<14));
+ break;
+ }
+ tt_uint_op(circid, <, (1<<15));
+ tt_assert(! bitarray_is_set(ba, circid));
+ bitarray_set(ba, circid);
+ channel_mark_circid_unusable(chan1, circid);
+ }
+ tt_int_op(i, <, (1<<15));
+ /* Make sure that being full on chan1 does not interfere with chan2 */
+ for (i = 0; i < 100; ++i) {
+ circid = get_unique_circ_id_by_chan(chan2);
+ tt_uint_op(circid, >, 0);
+ tt_uint_op(circid, <, (1<<15));
+ channel_mark_circid_unusable(chan2, circid);
+ }
+
+ done:
+ tor_free(chan1);
+ tor_free(chan2);
+ bitarray_free(ba);
+ circuit_free_all();
+}
+
+struct testcase_t circuitlist_tests[] = {
+ { "maps", test_clist_maps, TT_FORK, NULL, NULL },
+ { "rend_token_maps", test_rend_token_maps, TT_FORK, NULL, NULL },
+ { "pick_circid", test_pick_circid, TT_FORK, NULL, NULL },
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_circuitmux.c b/src/test/test_circuitmux.c
new file mode 100644
index 000000000..b9c0436eb
--- /dev/null
+++ b/src/test/test_circuitmux.c
@@ -0,0 +1,88 @@
+/* Copyright (c) 2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#define TOR_CHANNEL_INTERNAL_
+#define CIRCUITMUX_PRIVATE
+#define RELAY_PRIVATE
+#include "or.h"
+#include "channel.h"
+#include "circuitmux.h"
+#include "relay.h"
+#include "test.h"
+
+/* XXXX duplicated function from test_circuitlist.c */
+static channel_t *
+new_fake_channel(void)
+{
+ channel_t *chan = tor_malloc_zero(sizeof(channel_t));
+ channel_init(chan);
+ return chan;
+}
+
+static int
+has_queued_writes(channel_t *c)
+{
+ (void) c;
+ return 1;
+}
+
+/** Test destroy cell queue with no interference from other queues. */
+static void
+test_cmux_destroy_cell_queue(void *arg)
+{
+ circuitmux_t *cmux = NULL;
+ channel_t *ch = NULL;
+ circuit_t *circ = NULL;
+ cell_queue_t *cq = NULL;
+ packed_cell_t *pc = NULL;
+
+#ifdef ENABLE_MEMPOOLS
+ init_cell_pool();
+#endif /* ENABLE_MEMPOOLS */
+ (void) arg;
+
+ cmux = circuitmux_alloc();
+ tt_assert(cmux);
+ ch = new_fake_channel();
+ ch->has_queued_writes = has_queued_writes;
+ ch->wide_circ_ids = 1;
+
+ circ = circuitmux_get_first_active_circuit(cmux, &cq);
+ tt_assert(!circ);
+ tt_assert(!cq);
+
+ circuitmux_append_destroy_cell(ch, cmux, 100, 10);
+ circuitmux_append_destroy_cell(ch, cmux, 190, 6);
+ circuitmux_append_destroy_cell(ch, cmux, 30, 1);
+
+ tt_int_op(circuitmux_num_cells(cmux), ==, 3);
+
+ circ = circuitmux_get_first_active_circuit(cmux, &cq);
+ tt_assert(!circ);
+ tt_assert(cq);
+
+ tt_int_op(cq->n, ==, 3);
+
+ pc = cell_queue_pop(cq);
+ tt_assert(pc);
+ test_mem_op(pc->body, ==, "\x00\x00\x00\x64\x04\x0a\x00\x00\x00", 9);
+ packed_cell_free(pc);
+ pc = NULL;
+
+ tt_int_op(circuitmux_num_cells(cmux), ==, 2);
+
+ done:
+ circuitmux_free(cmux);
+ channel_free(ch);
+ packed_cell_free(pc);
+
+#ifdef ENABLE_MEMPOOLS
+ free_cell_pool();
+#endif /* ENABLE_MEMPOOLS */
+}
+
+struct testcase_t circuitmux_tests[] = {
+ { "destroy_cell_queue", test_cmux_destroy_cell_queue, TT_FORK, NULL, NULL },
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_cmdline_args.py b/src/test/test_cmdline_args.py
new file mode 100755
index 000000000..55d1cdb80
--- /dev/null
+++ b/src/test/test_cmdline_args.py
@@ -0,0 +1,292 @@
+#!/usr/bin/python
+
+import binascii
+import hashlib
+import os
+import re
+import shutil
+import subprocess
+import sys
+import tempfile
+import unittest
+
+TOR = "./src/or/tor"
+TOP_SRCDIR = "."
+
+if len(sys.argv) > 1:
+ TOR = sys.argv[1]
+ del sys.argv[1]
+
+if len(sys.argv) > 1:
+ TOP_SRCDIR = sys.argv[1]
+ del sys.argv[1]
+
+class UnexpectedSuccess(Exception):
+ pass
+
+class UnexpectedFailure(Exception):
+ pass
+
+if sys.version < '3':
+ def b2s(b):
+ return b
+ def s2b(s):
+ return s
+ def NamedTemporaryFile():
+ return tempfile.NamedTemporaryFile(delete=False)
+else:
+ def b2s(b):
+ return str(b, 'ascii')
+ def s2b(s):
+ return s.encode('ascii')
+ def NamedTemporaryFile():
+ return tempfile.NamedTemporaryFile(mode="w",delete=False,encoding="ascii")
+
+def contents(fn):
+ f = open(fn)
+ try:
+ return f.read()
+ finally:
+ f.close()
+
+def run_tor(args, failure=False):
+ p = subprocess.Popen([TOR] + args, stdout=subprocess.PIPE)
+ output, _ = p.communicate()
+ result = p.poll()
+ if result and not failure:
+ raise UnexpectedFailure()
+ elif not result and failure:
+ raise UnexpectedSuccess()
+ return b2s(output)
+
+def spaceify_fp(fp):
+ for i in range(0, len(fp), 4):
+ yield fp[i:i+4]
+
+def lines(s):
+ out = s.split("\n")
+ if out and out[-1] == '':
+ del out[-1]
+ return out
+
+def strip_log_junk(line):
+ m = re.match(r'([^\[]+\[[a-z]*\] *)(.*)', line)
+ if not m:
+ return ""+line
+ return m.group(2).strip()
+
+def randstring(entropy_bytes):
+ s = os.urandom(entropy_bytes)
+ return b2s(binascii.b2a_hex(s))
+
+def findLineContaining(lines, s):
+ for ln in lines:
+ if s in ln:
+ return True
+ return False
+
+class CmdlineTests(unittest.TestCase):
+
+ def test_version(self):
+ out = run_tor(["--version"])
+ self.assertTrue(out.startswith("Tor version "))
+ self.assertEqual(len(lines(out)), 1)
+
+ def test_quiet(self):
+ out = run_tor(["--quiet", "--quumblebluffin", "1"], failure=True)
+ self.assertEqual(out, "")
+
+ def test_help(self):
+ out = run_tor(["--help"], failure=False)
+ out2 = run_tor(["-h"], failure=False)
+ self.assertTrue(out.startswith("Copyright (c) 2001"))
+ self.assertTrue(out.endswith(
+ "tor -f <torrc> [args]\n"
+ "See man page for options, or https://www.torproject.org/ for documentation.\n"))
+ self.assertTrue(out == out2)
+
+ def test_hush(self):
+ torrc = NamedTemporaryFile()
+ torrc.close()
+ try:
+ out = run_tor(["--hush", "-f", torrc.name,
+ "--quumblebluffin", "1"], failure=True)
+ finally:
+ os.unlink(torrc.name)
+ self.assertEqual(len(lines(out)), 2)
+ ln = [ strip_log_junk(l) for l in lines(out) ]
+ self.assertEqual(ln[0], "Failed to parse/validate config: Unknown option 'quumblebluffin'. Failing.")
+ self.assertEqual(ln[1], "Reading config failed--see warnings above.")
+
+ def test_missing_argument(self):
+ out = run_tor(["--hush", "--hash-password"], failure=True)
+ self.assertEqual(len(lines(out)), 2)
+ ln = [ strip_log_junk(l) for l in lines(out) ]
+ self.assertEqual(ln[0], "Command-line option '--hash-password' with no value. Failing.")
+
+ def test_hash_password(self):
+ out = run_tor(["--hash-password", "woodwose"])
+ result = lines(out)[-1]
+ self.assertEqual(result[:3], "16:")
+ self.assertEqual(len(result), 61)
+ r = binascii.a2b_hex(result[3:])
+ self.assertEqual(len(r), 29)
+
+ salt, how, hashed = r[:8], r[8], r[9:]
+ self.assertEqual(len(hashed), 20)
+ if type(how) == type("A"):
+ how = ord(how)
+
+ count = (16 + (how & 15)) << ((how >> 4) + 6)
+ stuff = salt + s2b("woodwose")
+ repetitions = count // len(stuff) + 1
+ inp = stuff * repetitions
+ inp = inp[:count]
+
+ self.assertEqual(hashlib.sha1(inp).digest(), hashed)
+
+ def test_digests(self):
+ main_c = os.path.join(TOP_SRCDIR, "src", "or", "main.c")
+
+ if os.stat(TOR).st_mtime < os.stat(main_c).st_mtime:
+ self.skipTest(TOR+" not up to date")
+ out = run_tor(["--digests"])
+ main_line = [ l for l in lines(out) if l.endswith("/main.c") ]
+ digest, name = main_line[0].split()
+ f = open(main_c, 'rb')
+ actual = hashlib.sha1(f.read()).hexdigest()
+ f.close()
+ self.assertEqual(digest, actual)
+
+ def test_dump_options(self):
+ default_torrc = NamedTemporaryFile()
+ torrc = NamedTemporaryFile()
+ torrc.write("SocksPort 9999")
+ torrc.close()
+ default_torrc.write("SafeLogging 0")
+ default_torrc.close()
+ out_sh = out_nb = out_fl = None
+ opts = [ "-f", torrc.name,
+ "--defaults-torrc", default_torrc.name ]
+ try:
+ out_sh = run_tor(["--dump-config", "short"]+opts)
+ out_nb = run_tor(["--dump-config", "non-builtin"]+opts)
+ out_fl = run_tor(["--dump-config", "full"]+opts)
+ out_nr = run_tor(["--dump-config", "bliznert"]+opts,
+ failure=True)
+
+ out_verif = run_tor(["--verify-config"]+opts)
+ finally:
+ os.unlink(torrc.name)
+ os.unlink(default_torrc.name)
+
+ self.assertEqual(len(lines(out_sh)), 2)
+ self.assertTrue(lines(out_sh)[0].startswith("DataDirectory "))
+ self.assertEqual(lines(out_sh)[1:],
+ [ "SocksPort 9999" ])
+
+ self.assertEqual(len(lines(out_nb)), 2)
+ self.assertEqual(lines(out_nb),
+ [ "SafeLogging 0",
+ "SocksPort 9999" ])
+
+ out_fl = lines(out_fl)
+ self.assertTrue(len(out_fl) > 100)
+ self.assertTrue("SocksPort 9999" in out_fl)
+ self.assertTrue("SafeLogging 0" in out_fl)
+ self.assertTrue("ClientOnly 0" in out_fl)
+
+ self.assertTrue(out_verif.endswith("Configuration was valid\n"))
+
+ def test_list_fingerprint(self):
+ tmpdir = tempfile.mkdtemp(prefix='ttca_')
+ torrc = NamedTemporaryFile()
+ torrc.write("ORPort 9999\n")
+ torrc.write("DataDirectory %s\n"%tmpdir)
+ torrc.write("Nickname tippi")
+ torrc.close()
+ opts = ["-f", torrc.name]
+ try:
+ out = run_tor(["--list-fingerprint"]+opts)
+ fp = contents(os.path.join(tmpdir, "fingerprint"))
+ finally:
+ os.unlink(torrc.name)
+ shutil.rmtree(tmpdir)
+
+ out = lines(out)
+ lastlog = strip_log_junk(out[-2])
+ lastline = out[-1]
+ fp = fp.strip()
+ nn_fp = fp.split()[0]
+ space_fp = " ".join(spaceify_fp(fp.split()[1]))
+ self.assertEqual(lastlog,
+ "Your Tor server's identity key fingerprint is '%s'"%fp)
+ self.assertEqual(lastline, "tippi %s"%space_fp)
+ self.assertEqual(nn_fp, "tippi")
+
+ def test_list_options(self):
+ out = lines(run_tor(["--list-torrc-options"]))
+ self.assertTrue(len(out)>100)
+ self.assertTrue(out[0] <= 'AccountingMax')
+ self.assertTrue("UseBridges" in out)
+ self.assertTrue("SocksPort" in out)
+
+ def test_cmdline_args(self):
+ default_torrc = NamedTemporaryFile()
+ torrc = NamedTemporaryFile()
+ torrc.write("SocksPort 9999\n")
+ torrc.write("SocksPort 9998\n")
+ torrc.write("ORPort 9000\n")
+ torrc.write("ORPort 9001\n")
+ torrc.write("Nickname eleventeen\n")
+ torrc.write("ControlPort 9500\n")
+ torrc.close()
+ default_torrc.write("")
+ default_torrc.close()
+ out_sh = out_nb = out_fl = None
+ opts = [ "-f", torrc.name,
+ "--defaults-torrc", default_torrc.name,
+ "--dump-config", "short" ]
+ try:
+ out_1 = run_tor(opts)
+ out_2 = run_tor(opts+["+ORPort", "9003",
+ "SocksPort", "9090",
+ "/ControlPort",
+ "/TransPort",
+ "+ExtORPort", "9005"])
+ finally:
+ os.unlink(torrc.name)
+ os.unlink(default_torrc.name)
+
+ out_1 = [ l for l in lines(out_1) if not l.startswith("DataDir") ]
+ out_2 = [ l for l in lines(out_2) if not l.startswith("DataDir") ]
+
+ self.assertEqual(out_1,
+ ["ControlPort 9500",
+ "Nickname eleventeen",
+ "ORPort 9000",
+ "ORPort 9001",
+ "SocksPort 9999",
+ "SocksPort 9998"])
+ self.assertEqual(out_2,
+ ["ExtORPort 9005",
+ "Nickname eleventeen",
+ "ORPort 9000",
+ "ORPort 9001",
+ "ORPort 9003",
+ "SocksPort 9090"])
+
+ def test_missing_torrc(self):
+ fname = "nonexistent_file_"+randstring(8)
+ out = run_tor(["-f", fname, "--verify-config"], failure=True)
+ ln = [ strip_log_junk(l) for l in lines(out) ]
+ self.assertTrue("Unable to open configuration file" in ln[-2])
+ self.assertTrue("Reading config failed" in ln[-1])
+
+ out = run_tor(["-f", fname, "--verify-config", "--ignore-missing-torrc"])
+ ln = [ strip_log_junk(l) for l in lines(out) ]
+ self.assertTrue(findLineContaining(ln, ", using reasonable defaults"))
+ self.assertTrue("Configuration was valid" in ln[-1])
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/src/test/test_config.c b/src/test/test_config.c
index e20fe7329..94ac4dca1 100644
--- a/src/test/test_config.c
+++ b/src/test/test_config.c
@@ -4,12 +4,16 @@
/* See LICENSE for licensing information */
#include "orconfig.h"
+
+#define CONFIG_PRIVATE
#include "or.h"
#include "addressmap.h"
#include "config.h"
#include "confparse.h"
#include "connection_edge.h"
#include "test.h"
+#include "util.h"
+#include "address.h"
static void
test_config_addressmap(void *arg)
@@ -120,6 +124,7 @@ test_config_addressmap(void *arg)
test_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL));
/* Test top-level-domain matching a bit harder */
+ config_free_lines(get_options_mutable()->AddressMap);
addressmap_clear_configured();
strlcpy(buf, "MapAddress *.com *.torserver.exit\n"
"MapAddress *.torproject.org 1.1.1.1\n"
@@ -149,6 +154,7 @@ test_config_addressmap(void *arg)
test_streq(address, "2.2.2.2");
/* We don't support '*' as a mapping directive */
+ config_free_lines(get_options_mutable()->AddressMap);
addressmap_clear_configured();
strlcpy(buf, "MapAddress * *.torserver.exit\n", sizeof(buf));
config_get_lines(buf, &(get_options_mutable()->AddressMap), 0);
@@ -166,7 +172,421 @@ test_config_addressmap(void *arg)
#undef addressmap_rewrite
done:
- ;
+ config_free_lines(get_options_mutable()->AddressMap);
+ get_options_mutable()->AddressMap = NULL;
+}
+
+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;
+ const char *subdir = "test_stats";
+ char *subpath;
+ struct stat st;
+ int r;
+#if !defined (_WIN32) || defined (WINCE)
+ unsigned group_permission;
+#endif
+ (void)arg;
+
+ tor_free(options->DataDirectory);
+ datadir = options->DataDirectory = tor_strdup(get_fname("datadir-0"));
+ subpath = get_datadir_fname(subdir);
+
+#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));
+
+ r = stat(subpath, &st);
+ if (r) {
+ tt_abort_perror("stat");
+ }
+
+#if !defined (_WIN32) || defined (WINCE)
+ group_permission = st.st_mode | 0070;
+ r = chmod(subpath, group_permission);
+
+ if (r) {
+ tt_abort_perror("chmod");
+ }
+
+ // 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;
+ char *cp = NULL;
+ 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 = NULL;
+ (void)arg;
+
+ tor_free(options->DataDirectory);
+ datadir = options->DataDirectory = tor_strdup(get_fname("datadir-1"));
+ filepath = get_datadir_fname2(subdir, fname);
+
+#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));
+ cp = read_file_to_str(filepath, 0, NULL);
+ test_streq(cp, str);
+ tor_free(cp);
+
+ // A second write operation should overwrite the old content.
+ test_assert(!write_to_data_subdir(subdir, fname, str, NULL));
+ cp = read_file_to_str(filepath, 0, NULL);
+ test_streq(cp, str);
+ tor_free(cp);
+
+ done:
+ (void) unlink(filepath);
+ rmdir(options->DataDirectory);
+ tor_free(datadir);
+ tor_free(filepath);
+ tor_free(cp);
+}
+
+/* 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);
+ if (bridge_line)
+ TT_FAIL(("%s was supposed to fail, but it didn't.", 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);
+ }
+
+ {
+ smartlist_t *sl_tmp = smartlist_new();
+ smartlist_add_asprintf(sl_tmp, "dub=come");
+ smartlist_add_asprintf(sl_tmp, "save=me");
+
+ good_bridge_line_test("transport 192.0.2.1:12 "
+ "4352e58420e68f5e40bf7c74faddccd9d1349666 "
+ "dub=come save=me",
+
+ "192.0.2.1:12",
+ "4352e58420e68f5e40bf7c74faddccd9d1349666",
+ "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");
+}
+
+static void
+test_config_parse_transport_options_line(void *arg)
+{
+ smartlist_t *options_sl = NULL, *sl_tmp = NULL;
+
+ (void) arg;
+
+ { /* too small line */
+ options_sl = get_options_from_transport_options_line("valley", NULL);
+ test_assert(!options_sl);
+ }
+
+ { /* no k=v values */
+ options_sl = get_options_from_transport_options_line("hit it!", NULL);
+ test_assert(!options_sl);
+ }
+
+ { /* correct line, but wrong transport specified */
+ options_sl =
+ get_options_from_transport_options_line("trebuchet k=v", "rook");
+ test_assert(!options_sl);
+ }
+
+ { /* correct -- no transport specified */
+ sl_tmp = smartlist_new();
+ smartlist_add_asprintf(sl_tmp, "ladi=dadi");
+ smartlist_add_asprintf(sl_tmp, "weliketo=party");
+
+ options_sl =
+ get_options_from_transport_options_line("rook ladi=dadi weliketo=party",
+ NULL);
+ test_assert(options_sl);
+ test_assert(smartlist_strings_eq(options_sl, sl_tmp));
+
+ SMARTLIST_FOREACH(sl_tmp, char *, s, tor_free(s));
+ smartlist_free(sl_tmp);
+ sl_tmp = NULL;
+ SMARTLIST_FOREACH(options_sl, char *, s, tor_free(s));
+ smartlist_free(options_sl);
+ options_sl = NULL;
+ }
+
+ { /* correct -- correct transport specified */
+ sl_tmp = smartlist_new();
+ smartlist_add_asprintf(sl_tmp, "ladi=dadi");
+ smartlist_add_asprintf(sl_tmp, "weliketo=party");
+
+ options_sl =
+ get_options_from_transport_options_line("rook ladi=dadi weliketo=party",
+ "rook");
+ test_assert(options_sl);
+ test_assert(smartlist_strings_eq(options_sl, sl_tmp));
+ SMARTLIST_FOREACH(sl_tmp, char *, s, tor_free(s));
+ smartlist_free(sl_tmp);
+ sl_tmp = NULL;
+ SMARTLIST_FOREACH(options_sl, char *, s, tor_free(s));
+ smartlist_free(options_sl);
+ options_sl = NULL;
+ }
+
+ done:
+ if (options_sl) {
+ SMARTLIST_FOREACH(options_sl, char *, s, tor_free(s));
+ smartlist_free(options_sl);
+ }
+ if (sl_tmp) {
+ SMARTLIST_FOREACH(sl_tmp, char *, s, tor_free(s));
+ smartlist_free(sl_tmp);
+ }
+}
+
+// Tests if an options with MyFamily fingerprints missing '$' normalises
+// them correctly and also ensure it also works with multiple fingerprints
+static void
+test_config_fix_my_family(void *arg)
+{
+ char *err = NULL;
+ const char *family = "$1111111111111111111111111111111111111111, "
+ "1111111111111111111111111111111111111112, "
+ "$1111111111111111111111111111111111111113";
+
+ or_options_t* options = options_new();
+ or_options_t* defaults = options_new();
+ (void) arg;
+
+ options_init(options);
+ options_init(defaults);
+ options->MyFamily = tor_strdup(family);
+
+ options_validate(NULL, options, defaults, 0, &err) ;
+
+ if (err != NULL) {
+ TT_FAIL(("options_validate failed: %s", err));
+ }
+
+ test_streq(options->MyFamily, "$1111111111111111111111111111111111111111, "
+ "$1111111111111111111111111111111111111112, "
+ "$1111111111111111111111111111111111111113");
+
+ done:
+ if (err != NULL) {
+ tor_free(err);
+ }
+
+ or_options_free(options);
+ or_options_free(defaults);
}
#define CONFIG_TEST(name, flags) \
@@ -174,6 +594,11 @@ test_config_addressmap(void *arg)
struct testcase_t config_tests[] = {
CONFIG_TEST(addressmap, 0),
+ CONFIG_TEST(parse_bridge_line, 0),
+ CONFIG_TEST(parse_transport_options_line, 0),
+ CONFIG_TEST(check_or_create_data_subdir, TT_FORK),
+ CONFIG_TEST(write_to_data_subdir, TT_FORK),
+ CONFIG_TEST(fix_my_family, 0),
END_OF_TESTCASES
};
diff --git a/src/test/test_containers.c b/src/test/test_containers.c
index 005e102e2..067c4c190 100644
--- a/src/test/test_containers.c
+++ b/src/test/test_containers.c
@@ -469,6 +469,51 @@ test_container_smartlist_join(void)
tor_free(joined);
}
+static void
+test_container_smartlist_ints_eq(void *arg)
+{
+ smartlist_t *sl1 = NULL, *sl2 = NULL;
+ int x;
+ (void)arg;
+
+ tt_assert(smartlist_ints_eq(NULL, NULL));
+
+ sl1 = smartlist_new();
+ tt_assert(!smartlist_ints_eq(sl1, NULL));
+ tt_assert(!smartlist_ints_eq(NULL, sl1));
+
+ sl2 = smartlist_new();
+ tt_assert(smartlist_ints_eq(sl1, sl2));
+
+ x = 5;
+ smartlist_add(sl1, tor_memdup(&x, sizeof(int)));
+ smartlist_add(sl2, tor_memdup(&x, sizeof(int)));
+ x = 90;
+ smartlist_add(sl1, tor_memdup(&x, sizeof(int)));
+ smartlist_add(sl2, tor_memdup(&x, sizeof(int)));
+ tt_assert(smartlist_ints_eq(sl1, sl2));
+
+ x = -50;
+ smartlist_add(sl1, tor_memdup(&x, sizeof(int)));
+ tt_assert(! smartlist_ints_eq(sl1, sl2));
+ tt_assert(! smartlist_ints_eq(sl2, sl1));
+ smartlist_add(sl2, tor_memdup(&x, sizeof(int)));
+ tt_assert(smartlist_ints_eq(sl1, sl2));
+
+ *(int*)smartlist_get(sl1, 1) = 101010;
+ tt_assert(! smartlist_ints_eq(sl2, sl1));
+ *(int*)smartlist_get(sl2, 1) = 101010;
+ tt_assert(smartlist_ints_eq(sl1, sl2));
+
+ done:
+ if (sl1)
+ SMARTLIST_FOREACH(sl1, int *, ip, tor_free(ip));
+ if (sl2)
+ SMARTLIST_FOREACH(sl2, int *, ip, tor_free(ip));
+ smartlist_free(sl1);
+ smartlist_free(sl2);
+}
+
/** Run unit tests for bitarray code */
static void
test_container_bitarray(void)
@@ -784,7 +829,7 @@ test_container_order_functions(void)
}
static void
-test_di_map(void *arg)
+test_container_di_map(void *arg)
{
di_digest256_map_t *map = NULL;
const uint8_t key1[] = "In view of the fact that it was ";
@@ -856,12 +901,12 @@ test_container_fp_pair_map(void)
memset(fp6.second, 0x62, DIGEST_LEN);
v = fp_pair_map_set(map, &fp1, (void*)99);
- test_eq(v, NULL);
+ tt_ptr_op(v, ==, NULL);
test_assert(!fp_pair_map_isempty(map));
v = fp_pair_map_set(map, &fp2, (void*)101);
- test_eq(v, NULL);
+ tt_ptr_op(v, ==, NULL);
v = fp_pair_map_set(map, &fp1, (void*)100);
- test_eq(v, (void*)99);
+ tt_ptr_op(v, ==, (void*)99);
test_eq_ptr(fp_pair_map_get(map, &fp1), (void*)100);
test_eq_ptr(fp_pair_map_get(map, &fp2), (void*)101);
test_eq_ptr(fp_pair_map_get(map, &fp3), NULL);
@@ -912,18 +957,22 @@ test_container_fp_pair_map(void)
#define CONTAINER_LEGACY(name) \
{ #name, legacy_test_helper, 0, &legacy_setup, test_container_ ## name }
+#define CONTAINER(name, flags) \
+ { #name, test_container_ ## name, (flags), NULL, NULL }
+
struct testcase_t container_tests[] = {
CONTAINER_LEGACY(smartlist_basic),
CONTAINER_LEGACY(smartlist_strings),
CONTAINER_LEGACY(smartlist_overlap),
CONTAINER_LEGACY(smartlist_digests),
CONTAINER_LEGACY(smartlist_join),
+ CONTAINER(smartlist_ints_eq, 0),
CONTAINER_LEGACY(bitarray),
CONTAINER_LEGACY(digestset),
CONTAINER_LEGACY(strmap),
CONTAINER_LEGACY(pqueue),
CONTAINER_LEGACY(order_functions),
- { "di_map", test_di_map, 0, NULL, NULL },
+ CONTAINER(di_map, 0),
CONTAINER_LEGACY(fp_pair_map),
END_OF_TESTCASES
};
diff --git a/src/test/test_controller_events.c b/src/test/test_controller_events.c
new file mode 100644
index 000000000..b45e97a41
--- /dev/null
+++ b/src/test/test_controller_events.c
@@ -0,0 +1,307 @@
+/* Copyright (c) 2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#define CONNECTION_PRIVATE
+#define TOR_CHANNEL_INTERNAL_
+#define CONTROL_PRIVATE
+#include "or.h"
+#include "channel.h"
+#include "channeltls.h"
+#include "connection.h"
+#include "control.h"
+#include "test.h"
+
+static void
+help_test_bucket_note_empty(uint32_t expected_msec_since_midnight,
+ int tokens_before, size_t tokens_removed,
+ uint32_t msec_since_epoch)
+{
+ uint32_t timestamp_var = 0;
+ struct timeval tvnow;
+ tvnow.tv_sec = msec_since_epoch / 1000;
+ tvnow.tv_usec = (msec_since_epoch % 1000) * 1000;
+ connection_buckets_note_empty_ts(&timestamp_var, tokens_before,
+ tokens_removed, &tvnow);
+ tt_int_op(expected_msec_since_midnight, ==, timestamp_var);
+
+ done:
+ ;
+}
+
+static void
+test_cntev_bucket_note_empty(void *arg)
+{
+ (void)arg;
+
+ /* Two cases with nothing to note, because bucket was empty before;
+ * 86442200 == 1970-01-02 00:00:42.200000 */
+ help_test_bucket_note_empty(0, 0, 0, 86442200);
+ help_test_bucket_note_empty(0, -100, 100, 86442200);
+
+ /* Nothing to note, because bucket has not been emptied. */
+ help_test_bucket_note_empty(0, 101, 100, 86442200);
+
+ /* Bucket was emptied, note 42200 msec since midnight. */
+ help_test_bucket_note_empty(42200, 101, 101, 86442200);
+ help_test_bucket_note_empty(42200, 101, 102, 86442200);
+}
+
+static void
+test_cntev_bucket_millis_empty(void *arg)
+{
+ struct timeval tvnow;
+ (void)arg;
+
+ /* 1970-01-02 00:00:42.200000 */
+ tvnow.tv_sec = 86400 + 42;
+ tvnow.tv_usec = 200000;
+
+ /* Bucket has not been refilled. */
+ tt_int_op(0, ==, bucket_millis_empty(0, 42120, 0, 100, &tvnow));
+ tt_int_op(0, ==, bucket_millis_empty(-10, 42120, -10, 100, &tvnow));
+
+ /* Bucket was not empty. */
+ tt_int_op(0, ==, bucket_millis_empty(10, 42120, 20, 100, &tvnow));
+
+ /* Bucket has been emptied 80 msec ago and has just been refilled. */
+ tt_int_op(80, ==, bucket_millis_empty(-20, 42120, -10, 100, &tvnow));
+ tt_int_op(80, ==, bucket_millis_empty(-10, 42120, 0, 100, &tvnow));
+ tt_int_op(80, ==, bucket_millis_empty(0, 42120, 10, 100, &tvnow));
+
+ /* Bucket has been emptied 180 msec ago, last refill was 100 msec ago
+ * which was insufficient to make it positive, so cap msec at 100. */
+ tt_int_op(100, ==, bucket_millis_empty(0, 42020, 1, 100, &tvnow));
+
+ /* 1970-01-02 00:00:00:050000 */
+ tvnow.tv_sec = 86400;
+ tvnow.tv_usec = 50000;
+
+ /* Last emptied 30 msec before midnight, tvnow is 50 msec after
+ * midnight, that's 80 msec in total. */
+ tt_int_op(80, ==, bucket_millis_empty(0, 86400000 - 30, 1, 100, &tvnow));
+
+ done:
+ ;
+}
+
+static void
+add_testing_cell_stats_entry(circuit_t *circ, uint8_t command,
+ unsigned int waiting_time,
+ unsigned int removed, unsigned int exitward)
+{
+ testing_cell_stats_entry_t *ent = tor_malloc_zero(
+ sizeof(testing_cell_stats_entry_t));
+ ent->command = command;
+ ent->waiting_time = waiting_time;
+ ent->removed = removed;
+ ent->exitward = exitward;
+ if (!circ->testing_cell_stats)
+ circ->testing_cell_stats = smartlist_new();
+ smartlist_add(circ->testing_cell_stats, ent);
+}
+
+static void
+test_cntev_sum_up_cell_stats(void *arg)
+{
+ or_circuit_t *or_circ;
+ circuit_t *circ;
+ cell_stats_t *cell_stats = NULL;
+ (void)arg;
+
+ /* This circuit is fake. */
+ or_circ = tor_malloc_zero(sizeof(or_circuit_t));
+ or_circ->base_.magic = OR_CIRCUIT_MAGIC;
+ or_circ->base_.purpose = CIRCUIT_PURPOSE_OR;
+ circ = TO_CIRCUIT(or_circ);
+
+ /* A single RELAY cell was added to the appward queue. */
+ cell_stats = tor_malloc_zero(sizeof(cell_stats_t));
+ add_testing_cell_stats_entry(circ, CELL_RELAY, 0, 0, 0);
+ sum_up_cell_stats_by_command(circ, cell_stats);
+ tt_u64_op(1, ==, cell_stats->added_cells_appward[CELL_RELAY]);
+
+ /* A single RELAY cell was added to the exitward queue. */
+ add_testing_cell_stats_entry(circ, CELL_RELAY, 0, 0, 1);
+ sum_up_cell_stats_by_command(circ, cell_stats);
+ tt_u64_op(1, ==, cell_stats->added_cells_exitward[CELL_RELAY]);
+
+ /* A single RELAY cell was removed from the appward queue where it spent
+ * 20 msec. */
+ add_testing_cell_stats_entry(circ, CELL_RELAY, 2, 1, 0);
+ sum_up_cell_stats_by_command(circ, cell_stats);
+ tt_u64_op(20, ==, cell_stats->total_time_appward[CELL_RELAY]);
+ tt_u64_op(1, ==, cell_stats->removed_cells_appward[CELL_RELAY]);
+
+ /* A single RELAY cell was removed from the exitward queue where it
+ * spent 30 msec. */
+ add_testing_cell_stats_entry(circ, CELL_RELAY, 3, 1, 1);
+ sum_up_cell_stats_by_command(circ, cell_stats);
+ tt_u64_op(30, ==, cell_stats->total_time_exitward[CELL_RELAY]);
+ tt_u64_op(1, ==, cell_stats->removed_cells_exitward[CELL_RELAY]);
+
+ done:
+ tor_free(cell_stats);
+ tor_free(or_circ);
+}
+
+static void
+test_cntev_append_cell_stats(void *arg)
+{
+ smartlist_t *event_parts;
+ char *cp = NULL;
+ const char *key = "Z";
+ uint64_t include_if_non_zero[CELL_COMMAND_MAX_ + 1],
+ number_to_include[CELL_COMMAND_MAX_ + 1];
+ (void)arg;
+
+ event_parts = smartlist_new();
+ memset(include_if_non_zero, 0,
+ (CELL_COMMAND_MAX_ + 1) * sizeof(uint64_t));
+ memset(number_to_include, 0,
+ (CELL_COMMAND_MAX_ + 1) * sizeof(uint64_t));
+
+ /* All array entries empty. */
+ append_cell_stats_by_command(event_parts, key,
+ include_if_non_zero,
+ number_to_include);
+ tt_int_op(0, ==, smartlist_len(event_parts));
+
+ /* There's a RELAY cell to include, but the corresponding field in
+ * include_if_non_zero is still zero. */
+ number_to_include[CELL_RELAY] = 1;
+ append_cell_stats_by_command(event_parts, key,
+ include_if_non_zero,
+ number_to_include);
+ tt_int_op(0, ==, smartlist_len(event_parts));
+
+ /* Now include single RELAY cell. */
+ include_if_non_zero[CELL_RELAY] = 2;
+ append_cell_stats_by_command(event_parts, key,
+ include_if_non_zero,
+ number_to_include);
+ cp = smartlist_pop_last(event_parts);
+ tt_str_op("Z=relay:1", ==, cp);
+ tor_free(cp);
+
+ /* Add four CREATE cells. */
+ include_if_non_zero[CELL_CREATE] = 3;
+ number_to_include[CELL_CREATE] = 4;
+ append_cell_stats_by_command(event_parts, key,
+ include_if_non_zero,
+ number_to_include);
+ cp = smartlist_pop_last(event_parts);
+ tt_str_op("Z=create:4,relay:1", ==, cp);
+
+ done:
+ tor_free(cp);
+ smartlist_free(event_parts);
+}
+
+static void
+test_cntev_format_cell_stats(void *arg)
+{
+ char *event_string = NULL;
+ origin_circuit_t *ocirc = NULL;
+ or_circuit_t *or_circ = NULL;
+ cell_stats_t *cell_stats = NULL;
+ channel_tls_t *n_chan=NULL, *p_chan=NULL;
+ (void)arg;
+
+ n_chan = tor_malloc_zero(sizeof(channel_tls_t));
+ n_chan->base_.global_identifier = 1;
+
+ ocirc = tor_malloc_zero(sizeof(origin_circuit_t));
+ ocirc->base_.magic = ORIGIN_CIRCUIT_MAGIC;
+ ocirc->base_.purpose = CIRCUIT_PURPOSE_C_GENERAL;
+ ocirc->global_identifier = 2;
+ ocirc->base_.n_circ_id = 3;
+ ocirc->base_.n_chan = &(n_chan->base_);
+
+ /* Origin circuit was completely idle. */
+ cell_stats = tor_malloc_zero(sizeof(cell_stats_t));
+ format_cell_stats(&event_string, TO_CIRCUIT(ocirc), cell_stats);
+ tt_str_op("ID=2 OutboundQueue=3 OutboundConn=1", ==, event_string);
+ tor_free(event_string);
+
+ /* Origin circuit had 4 RELAY cells added to its exitward queue. */
+ cell_stats->added_cells_exitward[CELL_RELAY] = 4;
+ format_cell_stats(&event_string, TO_CIRCUIT(ocirc), cell_stats);
+ tt_str_op("ID=2 OutboundQueue=3 OutboundConn=1 OutboundAdded=relay:4",
+ ==, event_string);
+ tor_free(event_string);
+
+ /* Origin circuit also had 5 CREATE2 cells added to its exitward
+ * queue. */
+ cell_stats->added_cells_exitward[CELL_CREATE2] = 5;
+ format_cell_stats(&event_string, TO_CIRCUIT(ocirc), cell_stats);
+ tt_str_op("ID=2 OutboundQueue=3 OutboundConn=1 OutboundAdded=relay:4,"
+ "create2:5", ==, event_string);
+ tor_free(event_string);
+
+ /* Origin circuit also had 7 RELAY cells removed from its exitward queue
+ * which together spent 6 msec in the queue. */
+ cell_stats->total_time_exitward[CELL_RELAY] = 6;
+ cell_stats->removed_cells_exitward[CELL_RELAY] = 7;
+ format_cell_stats(&event_string, TO_CIRCUIT(ocirc), cell_stats);
+ tt_str_op("ID=2 OutboundQueue=3 OutboundConn=1 OutboundAdded=relay:4,"
+ "create2:5 OutboundRemoved=relay:7 OutboundTime=relay:6",
+ ==, event_string);
+ tor_free(event_string);
+
+ p_chan = tor_malloc_zero(sizeof(channel_tls_t));
+ p_chan->base_.global_identifier = 2;
+
+ or_circ = tor_malloc_zero(sizeof(or_circuit_t));
+ or_circ->base_.magic = OR_CIRCUIT_MAGIC;
+ or_circ->base_.purpose = CIRCUIT_PURPOSE_OR;
+ or_circ->p_circ_id = 8;
+ or_circ->p_chan = &(p_chan->base_);
+ or_circ->base_.n_circ_id = 9;
+ or_circ->base_.n_chan = &(n_chan->base_);
+
+ tor_free(cell_stats);
+
+ /* OR circuit was idle. */
+ cell_stats = tor_malloc_zero(sizeof(cell_stats_t));
+ format_cell_stats(&event_string, TO_CIRCUIT(or_circ), cell_stats);
+ tt_str_op("InboundQueue=8 InboundConn=2 OutboundQueue=9 OutboundConn=1",
+ ==, event_string);
+ tor_free(event_string);
+
+ /* OR circuit had 3 RELAY cells added to its appward queue. */
+ cell_stats->added_cells_appward[CELL_RELAY] = 3;
+ format_cell_stats(&event_string, TO_CIRCUIT(or_circ), cell_stats);
+ tt_str_op("InboundQueue=8 InboundConn=2 InboundAdded=relay:3 "
+ "OutboundQueue=9 OutboundConn=1", ==, event_string);
+ tor_free(event_string);
+
+ /* OR circuit had 7 RELAY cells removed from its appward queue which
+ * together spent 6 msec in the queue. */
+ cell_stats->total_time_appward[CELL_RELAY] = 6;
+ cell_stats->removed_cells_appward[CELL_RELAY] = 7;
+ format_cell_stats(&event_string, TO_CIRCUIT(or_circ), cell_stats);
+ tt_str_op("InboundQueue=8 InboundConn=2 InboundAdded=relay:3 "
+ "InboundRemoved=relay:7 InboundTime=relay:6 "
+ "OutboundQueue=9 OutboundConn=1", ==, event_string);
+
+ done:
+ tor_free(cell_stats);
+ tor_free(event_string);
+ tor_free(or_circ);
+ tor_free(ocirc);
+ tor_free(p_chan);
+ tor_free(n_chan);
+}
+
+#define TEST(name, flags) \
+ { #name, test_cntev_ ## name, flags, 0, NULL }
+
+struct testcase_t controller_event_tests[] = {
+ TEST(bucket_note_empty, 0),
+ TEST(bucket_millis_empty, 0),
+ TEST(sum_up_cell_stats, 0),
+ TEST(append_cell_stats, 0),
+ TEST(format_cell_stats, 0),
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_crypto.c b/src/test/test_crypto.c
index f92bfd673..5d8edb655 100644
--- a/src/test/test_crypto.c
+++ b/src/test/test_crypto.c
@@ -4,16 +4,20 @@
/* See LICENSE for licensing information */
#include "orconfig.h"
-#define CRYPTO_PRIVATE
#define CRYPTO_CURVE25519_PRIVATE
#include "or.h"
#include "test.h"
#include "aes.h"
#include "util.h"
+#include "siphash.h"
#ifdef CURVE25519_ENABLED
#include "crypto_curve25519.h"
#endif
+extern const char AUTHORITY_SIGNKEY_3[];
+extern const char AUTHORITY_SIGNKEY_A_DIGEST[];
+extern const char AUTHORITY_SIGNKEY_A_DIGEST256[];
+
/** Run unit tests for Diffie-Hellman functionality. */
static void
test_crypto_dh(void)
@@ -269,34 +273,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 +398,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 +482,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 +509,85 @@ test_crypto_pk(void)
tor_free(encoded);
}
+static void
+test_crypto_pk_fingerprints(void *arg)
+{
+ crypto_pk_t *pk = NULL;
+ char encoded[512];
+ char d[DIGEST_LEN], d2[DIGEST_LEN];
+ char fingerprint[FINGERPRINT_LEN+1];
+ int n;
+ unsigned i;
+ char *mem_op_hex_tmp=NULL;
+
+ (void)arg;
+
+ pk = pk_generate(1);
+ tt_assert(pk);
+ n = crypto_pk_asn1_encode(pk, encoded, sizeof(encoded));
+ tt_int_op(n, >, 0);
+ tt_int_op(n, >, 128);
+ tt_int_op(n, <, 256);
+
+ /* Is digest as expected? */
+ crypto_digest(d, encoded, n);
+ tt_int_op(0, ==, crypto_pk_get_digest(pk, d2));
+ test_memeq(d, d2, DIGEST_LEN);
+
+ /* Is fingerprint right? */
+ tt_int_op(0, ==, crypto_pk_get_fingerprint(pk, fingerprint, 0));
+ tt_int_op(strlen(fingerprint), ==, DIGEST_LEN * 2);
+ test_memeq_hex(d, fingerprint);
+
+ /* Are spaces right? */
+ tt_int_op(0, ==, crypto_pk_get_fingerprint(pk, fingerprint, 1));
+ for (i = 4; i < strlen(fingerprint); i += 5) {
+ tt_int_op(fingerprint[i], ==, ' ');
+ }
+ tor_strstrip(fingerprint, " ");
+ tt_int_op(strlen(fingerprint), ==, DIGEST_LEN * 2);
+ test_memeq_hex(d, fingerprint);
+
+ /* Now hash again and check crypto_pk_get_hashed_fingerprint. */
+ crypto_digest(d2, d, sizeof(d));
+ tt_int_op(0, ==, crypto_pk_get_hashed_fingerprint(pk, fingerprint));
+ tt_int_op(strlen(fingerprint), ==, DIGEST_LEN * 2);
+ test_memeq_hex(d2, fingerprint);
+
+ done:
+ crypto_pk_free(pk);
+ tor_free(mem_op_hex_tmp);
+}
+
+/** 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_3, -1);
+ test_assert(!r);
+
+ r = crypto_pk_get_digest(k, digest);
+ test_assert(r == 0);
+ test_memeq(hex_str(digest, DIGEST_LEN),
+ AUTHORITY_SIGNKEY_A_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_A_DIGEST, HEX_DIGEST_LEN);
+ test_memeq(hex_str(pkey_digests.d[DIGEST_SHA256], DIGEST256_LEN),
+ AUTHORITY_SIGNKEY_A_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 +682,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);
@@ -730,11 +782,13 @@ test_crypto_aes_iv(void *arg)
/* Decrypt with the wrong key. */
decrypted_size = crypto_cipher_decrypt_with_iv(key2, decrypted2, 4095,
encrypted1, encrypted_size);
+ test_eq(decrypted_size, 4095);
test_memneq(plain, decrypted2, decrypted_size);
/* Alter the initialization vector. */
encrypted1[0] += 42;
decrypted_size = crypto_cipher_decrypt_with_iv(key1, decrypted1, 4095,
encrypted1, encrypted_size);
+ test_eq(decrypted_size, 4095);
test_memneq(plain, decrypted2, 4095);
/* Special length case: 1. */
encrypted_size = crypto_cipher_encrypt_with_iv(key1, encrypted1, 16 + 1,
@@ -1078,7 +1132,8 @@ test_crypto_curve25519_persist(void *arg)
content = read_file_to_str(fname, RFTS_BIN, &st);
tt_assert(content);
taglen = strlen("== c25519v1: testing ==");
- tt_int_op(st.st_size, ==, 32+CURVE25519_PUBKEY_LEN+CURVE25519_SECKEY_LEN);
+ tt_u64_op((uint64_t)st.st_size, ==,
+ 32+CURVE25519_PUBKEY_LEN+CURVE25519_SECKEY_LEN);
tt_assert(fast_memeq(content, "== c25519v1: testing ==", taglen));
tt_assert(tor_mem_is_zero(content+taglen, 32-taglen));
cp = content + 32;
@@ -1108,6 +1163,102 @@ test_crypto_curve25519_persist(void *arg)
#endif
+static void
+test_crypto_siphash(void *arg)
+{
+ /* From the reference implementation, taking
+ k = 00 01 02 ... 0f
+ and in = 00; 00 01; 00 01 02; ...
+ */
+ const uint8_t VECTORS[64][8] =
+ {
+ { 0x31, 0x0e, 0x0e, 0xdd, 0x47, 0xdb, 0x6f, 0x72, },
+ { 0xfd, 0x67, 0xdc, 0x93, 0xc5, 0x39, 0xf8, 0x74, },
+ { 0x5a, 0x4f, 0xa9, 0xd9, 0x09, 0x80, 0x6c, 0x0d, },
+ { 0x2d, 0x7e, 0xfb, 0xd7, 0x96, 0x66, 0x67, 0x85, },
+ { 0xb7, 0x87, 0x71, 0x27, 0xe0, 0x94, 0x27, 0xcf, },
+ { 0x8d, 0xa6, 0x99, 0xcd, 0x64, 0x55, 0x76, 0x18, },
+ { 0xce, 0xe3, 0xfe, 0x58, 0x6e, 0x46, 0xc9, 0xcb, },
+ { 0x37, 0xd1, 0x01, 0x8b, 0xf5, 0x00, 0x02, 0xab, },
+ { 0x62, 0x24, 0x93, 0x9a, 0x79, 0xf5, 0xf5, 0x93, },
+ { 0xb0, 0xe4, 0xa9, 0x0b, 0xdf, 0x82, 0x00, 0x9e, },
+ { 0xf3, 0xb9, 0xdd, 0x94, 0xc5, 0xbb, 0x5d, 0x7a, },
+ { 0xa7, 0xad, 0x6b, 0x22, 0x46, 0x2f, 0xb3, 0xf4, },
+ { 0xfb, 0xe5, 0x0e, 0x86, 0xbc, 0x8f, 0x1e, 0x75, },
+ { 0x90, 0x3d, 0x84, 0xc0, 0x27, 0x56, 0xea, 0x14, },
+ { 0xee, 0xf2, 0x7a, 0x8e, 0x90, 0xca, 0x23, 0xf7, },
+ { 0xe5, 0x45, 0xbe, 0x49, 0x61, 0xca, 0x29, 0xa1, },
+ { 0xdb, 0x9b, 0xc2, 0x57, 0x7f, 0xcc, 0x2a, 0x3f, },
+ { 0x94, 0x47, 0xbe, 0x2c, 0xf5, 0xe9, 0x9a, 0x69, },
+ { 0x9c, 0xd3, 0x8d, 0x96, 0xf0, 0xb3, 0xc1, 0x4b, },
+ { 0xbd, 0x61, 0x79, 0xa7, 0x1d, 0xc9, 0x6d, 0xbb, },
+ { 0x98, 0xee, 0xa2, 0x1a, 0xf2, 0x5c, 0xd6, 0xbe, },
+ { 0xc7, 0x67, 0x3b, 0x2e, 0xb0, 0xcb, 0xf2, 0xd0, },
+ { 0x88, 0x3e, 0xa3, 0xe3, 0x95, 0x67, 0x53, 0x93, },
+ { 0xc8, 0xce, 0x5c, 0xcd, 0x8c, 0x03, 0x0c, 0xa8, },
+ { 0x94, 0xaf, 0x49, 0xf6, 0xc6, 0x50, 0xad, 0xb8, },
+ { 0xea, 0xb8, 0x85, 0x8a, 0xde, 0x92, 0xe1, 0xbc, },
+ { 0xf3, 0x15, 0xbb, 0x5b, 0xb8, 0x35, 0xd8, 0x17, },
+ { 0xad, 0xcf, 0x6b, 0x07, 0x63, 0x61, 0x2e, 0x2f, },
+ { 0xa5, 0xc9, 0x1d, 0xa7, 0xac, 0xaa, 0x4d, 0xde, },
+ { 0x71, 0x65, 0x95, 0x87, 0x66, 0x50, 0xa2, 0xa6, },
+ { 0x28, 0xef, 0x49, 0x5c, 0x53, 0xa3, 0x87, 0xad, },
+ { 0x42, 0xc3, 0x41, 0xd8, 0xfa, 0x92, 0xd8, 0x32, },
+ { 0xce, 0x7c, 0xf2, 0x72, 0x2f, 0x51, 0x27, 0x71, },
+ { 0xe3, 0x78, 0x59, 0xf9, 0x46, 0x23, 0xf3, 0xa7, },
+ { 0x38, 0x12, 0x05, 0xbb, 0x1a, 0xb0, 0xe0, 0x12, },
+ { 0xae, 0x97, 0xa1, 0x0f, 0xd4, 0x34, 0xe0, 0x15, },
+ { 0xb4, 0xa3, 0x15, 0x08, 0xbe, 0xff, 0x4d, 0x31, },
+ { 0x81, 0x39, 0x62, 0x29, 0xf0, 0x90, 0x79, 0x02, },
+ { 0x4d, 0x0c, 0xf4, 0x9e, 0xe5, 0xd4, 0xdc, 0xca, },
+ { 0x5c, 0x73, 0x33, 0x6a, 0x76, 0xd8, 0xbf, 0x9a, },
+ { 0xd0, 0xa7, 0x04, 0x53, 0x6b, 0xa9, 0x3e, 0x0e, },
+ { 0x92, 0x59, 0x58, 0xfc, 0xd6, 0x42, 0x0c, 0xad, },
+ { 0xa9, 0x15, 0xc2, 0x9b, 0xc8, 0x06, 0x73, 0x18, },
+ { 0x95, 0x2b, 0x79, 0xf3, 0xbc, 0x0a, 0xa6, 0xd4, },
+ { 0xf2, 0x1d, 0xf2, 0xe4, 0x1d, 0x45, 0x35, 0xf9, },
+ { 0x87, 0x57, 0x75, 0x19, 0x04, 0x8f, 0x53, 0xa9, },
+ { 0x10, 0xa5, 0x6c, 0xf5, 0xdf, 0xcd, 0x9a, 0xdb, },
+ { 0xeb, 0x75, 0x09, 0x5c, 0xcd, 0x98, 0x6c, 0xd0, },
+ { 0x51, 0xa9, 0xcb, 0x9e, 0xcb, 0xa3, 0x12, 0xe6, },
+ { 0x96, 0xaf, 0xad, 0xfc, 0x2c, 0xe6, 0x66, 0xc7, },
+ { 0x72, 0xfe, 0x52, 0x97, 0x5a, 0x43, 0x64, 0xee, },
+ { 0x5a, 0x16, 0x45, 0xb2, 0x76, 0xd5, 0x92, 0xa1, },
+ { 0xb2, 0x74, 0xcb, 0x8e, 0xbf, 0x87, 0x87, 0x0a, },
+ { 0x6f, 0x9b, 0xb4, 0x20, 0x3d, 0xe7, 0xb3, 0x81, },
+ { 0xea, 0xec, 0xb2, 0xa3, 0x0b, 0x22, 0xa8, 0x7f, },
+ { 0x99, 0x24, 0xa4, 0x3c, 0xc1, 0x31, 0x57, 0x24, },
+ { 0xbd, 0x83, 0x8d, 0x3a, 0xaf, 0xbf, 0x8d, 0xb7, },
+ { 0x0b, 0x1a, 0x2a, 0x32, 0x65, 0xd5, 0x1a, 0xea, },
+ { 0x13, 0x50, 0x79, 0xa3, 0x23, 0x1c, 0xe6, 0x60, },
+ { 0x93, 0x2b, 0x28, 0x46, 0xe4, 0xd7, 0x06, 0x66, },
+ { 0xe1, 0x91, 0x5f, 0x5c, 0xb1, 0xec, 0xa4, 0x6c, },
+ { 0xf3, 0x25, 0x96, 0x5c, 0xa1, 0x6d, 0x62, 0x9f, },
+ { 0x57, 0x5f, 0xf2, 0x8e, 0x60, 0x38, 0x1b, 0xe5, },
+ { 0x72, 0x45, 0x06, 0xeb, 0x4c, 0x32, 0x8a, 0x95, }
+ };
+
+ const struct sipkey K = { U64_LITERAL(0x0706050403020100),
+ U64_LITERAL(0x0f0e0d0c0b0a0908) };
+ uint8_t input[64];
+ int i, j;
+
+ (void)arg;
+
+ for (i = 0; i < 64; ++i)
+ input[i] = i;
+
+ for (i = 0; i < 64; ++i) {
+ uint64_t r = siphash24(input, i, &K);
+ for (j = 0; j < 8; ++j) {
+ tt_int_op( (r >> (j*8)) & 0xff, ==, VECTORS[i][j]);
+ }
+ }
+
+ done:
+ ;
+}
+
static void *
pass_data_setup_fn(const struct testcase_t *testcase)
{
@@ -1134,6 +1285,8 @@ struct testcase_t crypto_tests[] = {
{ "aes_EVP", test_crypto_aes, TT_FORK, &pass_data, (void*)"evp" },
CRYPTO_LEGACY(sha),
CRYPTO_LEGACY(pk),
+ { "pk_fingerprints", test_crypto_pk_fingerprints, TT_FORK, NULL, NULL },
+ CRYPTO_LEGACY(digests),
CRYPTO_LEGACY(dh),
CRYPTO_LEGACY(s2k),
{ "aes_iv_AES", test_crypto_aes_iv, TT_FORK, &pass_data, (void*)"aes" },
@@ -1148,6 +1301,7 @@ struct testcase_t crypto_tests[] = {
{ "curve25519_encode", test_crypto_curve25519_encode, 0, NULL, NULL },
{ "curve25519_persist", test_crypto_curve25519_persist, 0, NULL, NULL },
#endif
+ { "siphash", test_crypto_siphash, 0, NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_data.c b/src/test/test_data.c
index 5f0f7cba0..0c51c98f1 100644
--- a/src/test/test_data.c
+++ b/src/test/test_data.c
@@ -3,8 +3,18 @@
* Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+/* Our unit test expect that the AUTHORITY_CERT_* public keys will sort
+ * in this order. */
+#define AUTHORITY_CERT_A AUTHORITY_CERT_3
+#define AUTHORITY_CERT_B AUTHORITY_CERT_1
+#define AUTHORITY_CERT_C AUTHORITY_CERT_2
+
+#define AUTHORITY_SIGNKEY_A AUTHORITY_SIGNKEY_3
+#define AUTHORITY_SIGNKEY_B AUTHORITY_SIGNKEY_1
+#define AUTHORITY_SIGNKEY_C AUTHORITY_SIGNKEY_2
+
/** First of 3 example authority certificates for unit testing. */
-const char AUTHORITY_CERT_1[] =
+const char AUTHORITY_CERT_A[] =
"dir-key-certificate-version 3\n"
"fingerprint D867ACF56A9D229B35C25F0090BC9867E906BE69\n"
"dir-key-published 2008-12-12 18:07:24\n"
@@ -46,7 +56,7 @@ const char AUTHORITY_CERT_1[] =
"-----END SIGNATURE-----\n";
/** The private signing key for AUTHORITY_CERT_1 */
-const char AUTHORITY_SIGNKEY_1[] =
+const char AUTHORITY_SIGNKEY_A[] =
"-----BEGIN RSA PRIVATE KEY-----\n"
"MIICWwIBAAKBgQCz0lCJ8rhLujVdzY6M6ZWp4iBAc0FxI79cff/pqp8GQAaWFZrs\n"
"vQPJ8XqMmN7GRbJ2MDVvyGYwIBtt6RJnr7txfi+JsjI42mujkZdzIEWEOIJrhaqX\n"
@@ -63,111 +73,128 @@ const char AUTHORITY_SIGNKEY_1[] =
"Yx4lqK0ca5IkTp3HevwnlWaJgbaOTUspCVshzJBhDA==\n"
"-----END RSA PRIVATE KEY-----\n";
+const char AUTHORITY_SIGNKEY_A_DIGEST[] =
+ "CBF56A83368A5150F1A9AAADAFB4D77F8C4170E2";
+const char AUTHORITY_SIGNKEY_A_DIGEST256[] =
+ "AF7C5468DBE3BA54A052726038D7F15F3C4CA511B1952645B3D96D83A8DFB51C";
+
/** Second of 3 example authority certificates for unit testing. */
-const char AUTHORITY_CERT_2[] =
+const char AUTHORITY_CERT_B[] =
"dir-key-certificate-version 3\n"
-"fingerprint 4D44AE0470B9E88FD4558EFEC82698FB33715400\n"
-"dir-key-published 2007-06-13 16:52:32\n"
-"dir-key-expires 2008-06-13 16:52:32\n"
+"fingerprint AD011E25302925A9D39A80E0E32576442E956467\n"
+"dir-key-published 2013-11-14 14:12:05\n"
+"dir-key-expires 2014-11-14 14:12:05\n"
"dir-identity-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
-"MIIBigKCAYEAqukDwQRm1Oy1pPY+7GNRnRNFJzEVPUBfJwC4tBH19tkvdRQPuIGI\n"
-"2jiTy/rmZ6CLcl1G0oulSgxfKEX75QdptOasZu+rKUrRRSxx0QrXhs9a7up0rpXh\n"
-"13fw3mh1Vl/As3rJYF30Hjk01BTOJMxi/HY2y0ALQytFWjiMGY74A9Y6+uDcHkB2\n"
-"KflBjxIl8zpCsXsTTnUhN5kXqaOOnK46XaUShSpXsyOxTMJXuJEtgLz9XCyA8XjW\n"
-"d75QLHucEnlTqxUAdI5YSN2KIlIJiySCVnAorDpJey2mE9VncpHQWMCv/FPFdnSU\n"
-"EMMPUc4bBShcoNFf0mMJeV2sv+dBkgKAL0GLM19PuJIThJhfN/B6+YQTxw4HEpPV\n"
-"plfUqYRN0fYC+5hCTS6rroO/uCfDR7NBtoeDNm9dQrvjfk3b/Mywah1rdWNjnVqs\n"
-"tPJaz3fc/CVBOUUexhmyktgLuwSNEYIQilQ+BydkWN/4RObhV+YSV5BgekEDVaoS\n"
-"RHw4IbYBDHVxAgMBAAE=\n"
+"MIIBigKCAYEAyXYEMlGNRAixXdg65xf2WPkskYj2Wo8ysKMTls1JCXdIOAPvC2k2\n"
+"+AC6i3x9JHzUgCjWr4Jd5PSi7ODGyFC543igYl4wzkxNTU2L+SQ+hMe9qbEuUNhH\n"
+"sRR0xofdoH//3UuKj+HXEiMhhHbRWQGtWFuJqtGBruJqjZqIGOrp5nFjdlP0R98n\n"
+"Rx5wWlPgdJzifkXjKouu4mV+KzLl7f0gAtngA9DkSjt1wzga5IlL/lxDciD0SyJU\n"
+"tKMmls056omrZNbTnBxnY2pOlq9nx/zFrt/KQm1fTAQMjMBCf9KnDIV7NhaaHx7F\n"
+"7Nk8L7Hha353SvR+bsOFpiu05/EMZFTTIhO3MhUxZiCVZ0hKXvW1xe0HoGC5wbB+\n"
+"NyXu8oa4fIKLJ+WJ8Z60BNc0DcxJiQOf1eolGM/qrBul1lFZznds5/7182d+nF2W\n"
+"+bEjSm0fgXIxPfSD/7hB0FvgtmB3TXybHGBfPZgX0sTzFB6LNtP0BHicRoMXKdLF\n"
+"hM3tgIjEAsoZAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
"dir-signing-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
-"MIGJAoGBAOu3dgrQth3iqvi/UzfywaANw0bBUuMOBhnMBeiLEcRLneJHUJkVvrpR\n"
-"/EDQkdMov1e7CX6aqBKygVnbDNYjJ+bcQej8MKpuuW+zIknnz5lfnAVZO5uAmo3Y\n"
-"DpG574oQ2FFMdkWHSBloIRxSj/E4Jn1M2qJjElBXP0E33Ka/Noo7AgMBAAE=\n"
+"MIGJAoGBAJ567PZIGG/mYWEY4szYi/C5XXvf0BkquzKTHKrqVjysZEys9giz56Gv\n"
+"B08kIRxsxYKEWkq60rv0xtTc1WyEMcDpV1WLU0KSTQSVXzLu7BT8jbTsWzGsxdTV\n"
+"TdeyOirwHh8Cyyon5lppuMH5twUHrL5O7pWWbxjjrQjAHCn3gd+NAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+"dir-key-crosscert\n"
+"-----BEGIN ID SIGNATURE-----\n"
+"OC+gaukd4K7xJOsgTPbRhacf5mDUGxsu3ho/J1oJdtni4CK9WscVs6/Goj1o5Lot\n"
+"H1nCAMaR96Jnqq5c63Aaj1sEXdeYHlu5cI7YHgtGI5MmtjiUNXUCWMjCwSQYwGKe\n"
+"2YDYGAKAGt97n7XMKhJWGjAmv1TgmK3DvL1jt/aazL8=\n"
+"-----END ID SIGNATURE-----\n"
"dir-key-certification\n"
"-----BEGIN SIGNATURE-----\n"
-"Fv0Li68QUdAiChY3OklZOakHzwXAUfCzDNxkqe+HLC0n6ZECE9ZCvLVo69XmgVhH\n"
-"L5qYr2rxT6QpF+9yuOHbN9gWn8EsDcli06MlhX9TUt/IYVxHa/9tJwNoTfEw2w2D\n"
-"tyHhWm94IfOK7/Sea6jHnjckl80X+kk0ZNtAGs3/6fP4iltKNGXnvBwfgLpEgW7X\n"
-"NpDl0OLeDuA79zem2GogwQZQdoDbePByU0TJVx9jYi2Bzx2Nb2H0hRTPP6+dY0HQ\n"
-"MHb7yyyTQRad5iAUnExKhhyt22p7X3a6lgkAhq4YrNn/zVPkpnT2dzjsOydTHOW8\n"
-"2BQs33QlGNe095i47pJBDYsUgmJaXfqB/RG6dFg7jwIsc3/7dZcvcqfxY7wKcD/T\n"
-"wtogCIKxDvWbZn7f0hqYkT6uQC8Zom8bcnedmyzufOZCyA2SqQ2wvio6lznR4RIB\n"
-"a8qDHR0tPS9/VkqTPcvUWCZeY3UiDeWPjoK1nea1pz6DHDWglKPx86a0amjjayZQ\n"
-"-----END SIGNATURE-----\n";
+"BddmCKsvS6VoFXIf9Aj9OZnfyVCx527517QtsQHN+NaVm20LzUkJ5MWGXYx4wgh3\n"
+"ExsHvVQguiVfnonkQpEHHKg+TbldlkuDhIdlb9f7dL7V3HLCsEdmS1c3A+TEyrPH\n"
+"i44p6QB5IMFAdgUMV/9ueKMh7pMoam6VNakMOd+Axx9BSJTrCRzcepjtM4Z0cPsj\n"
+"nmDgZi0df1+ca1t+HnuWyt3trxlqoUxRcPZKz28kEFDJsgnRNvoHrIvNTuy9qY4x\n"
+"rONnPuLr5kTO7VQVVZxgxt6WX3p6d8tj+WYHubydr2pG0dwu2vGDTy4qXvDIm/I4\n"
+"Gyo6OAoPbYV8fl0584EgiEbAWcX/Pze8mXr9lmXbf73xbSBHqveAs0UfB+4sBI98\n"
+"v4ax4NZkGs8cCIfugtAOLgZE0WCh/TQYnQ3PFcrUtj0RW+tM1z7S8P3UfEVBHVkJ\n"
+"8SqSB+pbsY6PwMuy6TC3WujW7gmjVanbwkbW19El9l9jRzteFerz7grG/WQkshqF\n"
+ "-----END SIGNATURE-----\n";
/** The private signing key for AUTHORITY_CERT_2 */
-const char AUTHORITY_SIGNKEY_2[] =
+const char AUTHORITY_SIGNKEY_B[] =
"-----BEGIN RSA PRIVATE KEY-----\n"
-"MIICXgIBAAKBgQDrt3YK0LYd4qr4v1M38sGgDcNGwVLjDgYZzAXoixHES53iR1CZ\n"
-"Fb66UfxA0JHTKL9Xuwl+mqgSsoFZ2wzWIyfm3EHo/DCqbrlvsyJJ58+ZX5wFWTub\n"
-"gJqN2A6Rue+KENhRTHZFh0gZaCEcUo/xOCZ9TNqiYxJQVz9BN9ymvzaKOwIDAQAB\n"
-"AoGAJ+I9/ex8tCfTSA2PdisEKiHKBeHWNYb870Z/RW6qje1BhLUOZSixwfL3XLwt\n"
-"wG3nml+SZrKid69uhZaz4FPIf0tqCgURf6dDrF5vuzzr7VLVqkZHYSBp0vE6bu0R\n"
-"Sgc5QNxI2talgc4bsp0O0C+Zd4n3Yto0pXl/I6NHVAxlFBECQQD2mahkY+QEHWPV\n"
-"yRY3w3HhRmWBcrkY2zVyvPpqfn/sdHRPYW/yj4Xr/d1CO9VyFmEs4k324lIvu6LT\n"
-"WDdpPlcJAkEA9LOZv5aNeAm8ckvvXH7iv8KiONiSz0n9wlisxMhNYTEkOCo1g7jG\n"
-"AX5ZknRC9s4sWCPOBpMhloUvemdQ5FCEIwJBAMqCFwoSCf7jD8hRcUBr7QodoF/0\n"
-"kVJ7OeI2lMJ9jZnlbFp/3snn2Qeam2e38SnWfQi582KKKwnt4eIDMMXpntkCQQDI\n"
-"v1Lh11wl3y7nQZ6T7lCNatp08k+2mQgCWYcbRQweMRd6sD4I2xwt+372ZETPfyLo\n"
-"CC+sOyYx+v+RVpMJS3irAkEA6l98nMteZKmhOgyKSjdolP+ahpZunb+WnCdAtP97\n"
-"rjZyXmEZS3oe7TRCDD28GAGMmxSDvNfOOpyn14ishEs5AQ==\n"
+"MIICWwIBAAKBgQCeeuz2SBhv5mFhGOLM2IvwuV1739AZKrsykxyq6lY8rGRMrPYI\n"
+"s+ehrwdPJCEcbMWChFpKutK79MbU3NVshDHA6VdVi1NCkk0ElV8y7uwU/I207Fsx\n"
+"rMXU1U3Xsjoq8B4fAssqJ+ZaabjB+bcFB6y+Tu6Vlm8Y460IwBwp94HfjQIDAQAB\n"
+"AoGAfHQ4ZmfTmPyoeGHcqdVcgBxxh3gJqdnezCavGqGQO3F+CqDBTbBKNLSI3uOW\n"
+"hQX+TTK23Xy9RRFCm6MYj3F4x7OOrSHSFyhMmzRnAZi3zGbtQZn30XoqTwCmVevY\n"
+"p5JbVvhP2BJcvdsyQhiIG23FRQ7MMHWtksAxmovTto1h/hkCQQDNCfMqSztgJZDn\n"
+"JSf5ASHBOw8QzfZBeYi3hqfiDtAN1RxT1uQnEiFQFJqwCz5lCbcwVrfQbrrk5M+h\n"
+"ooYrX7tTAkEAxd6Tl0N0WM3zCKz+3/Hoiyty6olnnpzNoPCg7LLBJcetABQi0KUv\n"
+"swYWlKP3eOFZkiBzTqa9nBK7eYLKV3d9nwJAKNM3WI98Nguky3FJgTnpd6kDuevY\n"
+"gXbqcuhb2xXp9Sceqc7axLDGc0R2/GBwvvttPzG1DcpOai7o7J0Iq/A2wwJAYuKI\n"
+"/99GFdtWyc8q0OAkRui/1VY14p6aZQPcaG4s+KSBYLivbXYgEGfKgR4wXsi/6rcs\n"
+"6PGLcKQr7N3gITYmIQJAaQn6djUWygCn1noKyWU+Sa7G5qqU2GWkLq9dMaRLm1/I\n"
+"nqi+2K1mN15rra0QtFVqSH4JXr8h3KAGyU45voGM7A==\n"
"-----END RSA PRIVATE KEY-----\n";
/** Third of 3 example authority certificates for unit testing. */
-const char AUTHORITY_CERT_3[] =
+const char AUTHORITY_CERT_C[] =
"dir-key-certificate-version 3\n"
-"fingerprint ED3719BF554DE9D7D59F5CA5A4F5AD121D020ED9\n"
-"dir-key-published 2007-06-13 16:52:40\n"
-"dir-key-expires 2008-06-13 16:52:40\n"
+"fingerprint 628C2086EC29C9D26E638C5A8B2065BFBD35829B\n"
+"dir-key-published 2013-11-14 14:12:18\n"
+"dir-key-expires 2014-11-14 14:12:18\n"
"dir-identity-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
-"MIIBigKCAYEAtB+yw4BNxtZAG4cPaedkhWNmeij7IuNWmXjh58ZYEGurvGyHs1w4\n"
-"QlwNYI2UftSIeIGdWZ5fJ17h9P3xvO6eeJuOt4KPrNOxUbSGrELEx1Lje1fDAJ1X\n"
-"SvN+dvptusxtyFUr8afgTPrFIvYuazQ6q/Rw+NDagjmDx3h/A/enihpBnjwzeH8j\n"
-"Xzu7b+HKnzFnNfveTDdvSy0NSC6tCOnrfXo31XbXRXtlesnMIpbJClUcAv55eyai\n"
-"/PrVPCCUz8mk0sQnn2Xhv1YJmwOlQTGMfg0a0kWLmh+UWcHsGQ4VWxBZJcuzgFHG\n"
-"hu2/Fz6DXSpX5Q6B9HKoGmnH1oBh24l0kUW1jL8BxPY4YDU1Lt5t3qgcDn9dXYcI\n"
-"o8VvyI0ecSc26Q2PYFWX1hpN4VIBZ8uGaW3IpyTdNiRq0g3iMGRFEXcDlWuyMB9E\n"
-"EbSM7m/79V/z7SjDd75EP8Z0qDPESEVB8a8LbuSJtzFVE0KHd7RzkIEN5sorXspZ\n"
-"/THukftSmkIvAgMBAAE=\n"
+"MIIBigKCAYEAuzPA82lRVUAc1uZgfDehhK0rBU5xt+qhJXUSH0DxsuocYCLW//q+\n"
+"7+L7q9SochqZK3R5+SxJaZRlVK4rAeIHsxXFxsnGvuqasGM3he80EV1RpVRkvLaO\n"
+"2dDmHcfEjYBadft2DEq811yvqSRqbFXmK0hLucA6LI6NnEw9VNWlguaV6ACVLyKQ\n"
+"iYVFz2JOJIAi0Zz57WZg7eHypUAGoyXjtYTJPsh6pUe/0NLFJVd3JHcJX+bNqU2a\n"
+"QU37r+CQ9f3T+8fZGJQ/CXNnYUNHa0j+toOFuPEiZBBh8C4PE7FJWjidvhe9uI7T\n"
+"Py41RZhy8e05MAQmUBNRKBHWPKHoy2zWZZxTkcfWFdJJz/dzsNrIjrqf2fYId9To\n"
+"fDpHzYd/UjzZaaVYRVS/Oyf3pN8DKw8LMhEArS0X9pblPVkWWjmYMU6f0VR7pelc\n"
+"gGYuML3gOiKdNbeMWgAv3HNRsVsuW0HZLrhXUGYzTRPJ/GxVCwA/NmYgMTNVWRwF\n"
+"7M78YHpayyEPAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
"dir-signing-key\n"
"-----BEGIN RSA PUBLIC KEY-----\n"
-"MIGJAoGBANrSZlUq38Boz3iuUOydYTJV57rTbq1bz805FP2QG2Z+2bwpgKIOZag/\n"
-"gN2A1ySJaIYLgZIg9irxrLkqlY/UAjC23y6V9fJXP1S3TXoqLmHleW8PsaDLuwTo\n"
-"hCWaR61Mx9WG7IXcodn2Z7RiCfZpSW4Rztbk5WtjQa5jPXSFOuBJAgMBAAE=\n"
+"MIGJAoGBANESf/hRRWCK3TLQyNb9Y42tYedCORUc8Rl+Q4wrvdz3R0TNr6rztE9N\n"
+"u8v3Wbvjtiqm1xL1I5PaOObFQQj61QZxKiCm1yU4eFH15dNmcvBEy5BjEXVYiDgy\n"
+"zKRyePzjHYQIZF3ZaQTABUplkXVpY0YvAurluhEy+dKEvZMwWFZTAgMBAAE=\n"
"-----END RSA PUBLIC KEY-----\n"
+"dir-key-crosscert\n"
+"-----BEGIN ID SIGNATURE-----\n"
+"NHNBya6Dt7Ww3qSGA0DBEl6pZFBzmYXM+QdqF+ESpdyYCQ54EYimaxl4VcXoGaxy\n"
+"xk8/VOXPC6h7hVnTWDTsC86G6eXug1yzpd/uhQbcDJMH5q8/Yg5WXGOnGhMWNCBh\n"
+"u2UmbtAjdjLrObQaB50FfOpuOV9kdG4SEzaPUBR2ayU=\n"
+"-----END ID SIGNATURE-----\n"
"dir-key-certification\n"
"-----BEGIN SIGNATURE-----\n"
-"UNXZy+4OQ8iat+gw+vg2ynvKj2BYbqZt+EAZAV3rmw6gux44U9TLRECRd6LsA08N\n"
-"4+Vz01TU81xqMgfrUy94ei2YvcfpO8art9/muWHTP9SmOX8S1uqDqLWA+n723C9A\n"
-"HyVXn4aINncO2081gJcIW5+Ul8WTCeZe/n3LVPTCKbTdqxvmrPUdCWlJTQUmb19M\n"
-"T+kcCjaEfgQGLC+Y2MHqYe/nxz+aBKqpjiWUDdjc35va6r/2e3c0jGi1B1xRZxN1\n"
-"xThPZ+CifjDoWBxJdDGlIfZRK1lMnOCJY9w9ibTXQ1UnvE4whFvmB55/t9/XLq4q\n"
-"3pnZz0H7funey3+ilmTxDohoAYT1GX+4a+3xYH07UmAFqlTzqKClj84XEHn+Cer7\n"
-"Nun9kJlJFuBgUpQjwCkzedFZKKLOHgB2h7trJfnqcBpAM8Rup1Bb5u/RcBx9gy1q\n"
-"pMc65FviIrc/Q5TUku6NNbCbnGll1599PvWuUzkG42lJ17V6psKHIsqGtVdHlCUc\n"
+"NocTkLl9iKglVo+yrpY0slsqgPviuScMyEfOJ3i65KeJb4Dr1huIs0Fip40zFD8D\n"
+"cz/SYu09FbANuRwBJIRdVWZLLwVFLBj5F8U65iJRAPBw/O/xgSVBvWoOhBUZqmJA\n"
+"Jp1IUutQHYFfnAOO9za4r8Ox6yPaOWF9Ks5gL0kU/fI8Bdi5E9p3e9fMtoM7hROg\n"
+"oX1AoV/za3LcM0oMsGsdXQ7B8vRqY0eUX523kpRpF1fUDyvBUvvMsXdZDN6anCV6\n"
+"NtSq2UaM/msTX1oQ8gzyD1gMXH0Ek26YMhd+6WZE6KUeb1x5HJgXtKtYzMLB6nQM\n"
+"4Q/OA4NND/Veflofy6xx8uzXe8H+MoUHK9WiORtwqvBl0E9qk6SVCuo4ipR4Ybgk\n"
+"PAFOXA58j80dlNYYEVgV8MXF1Y/g/thuXlf2dWiLAExdHTtE0AzC4quWshegaImC\n"
+"4aziHeA43TRDszAXcJorREAM0AhSxp3aWDde4Jt46ODOJR8t+gHreks29eDttEIn\n"
"-----END SIGNATURE-----\n";
/** The private signing key for AUTHORITY_CERT_3 */
-const char AUTHORITY_SIGNKEY_3[] =
+const char AUTHORITY_SIGNKEY_C[] =
"-----BEGIN RSA PRIVATE KEY-----\n"
-"MIICXgIBAAKBgQDa0mZVKt/AaM94rlDsnWEyVee6026tW8/NORT9kBtmftm8KYCi\n"
-"DmWoP4DdgNckiWiGC4GSIPYq8ay5KpWP1AIwtt8ulfXyVz9Ut016Ki5h5XlvD7Gg\n"
-"y7sE6IQlmketTMfVhuyF3KHZ9me0Ygn2aUluEc7W5OVrY0GuYz10hTrgSQIDAQAB\n"
-"AoGBAIyoeG1AnQmildKeQpiGZackf0uhg2BeRwpFKg//5Q0Sd0Wza+M/2+q1v1Ei\n"
-"86ihxxV7KfPTykk6hmuUSwVkI28Z+5J9NYTr35EzPiUlqpo0iclTkFqrlbqSPULx\n"
-"9fQhvcOGv1c0m5CnYrHsM8eu3tagLg+6OE4abLOYX4Az5pkxAkEA/NwHhVaVJrXH\n"
-"lGDrRAfGtaD5Tzeeg1H9DNZi5lmFiSNR0O11sgDLkiZNP5oM8knyqo8Gq08hwxEb\n"
-"yqMXM3XtJQJBAN2KJbFhOjDIkvJyYvbmcP6P7vV2c9j+oUTKkFMF7vvfWunxMi9j\n"
-"ghbdUKgl7tU0VFpw7ufDDD0pkN6sua3gp1UCQQCvNzTK861U7p/GtMYyFQVf9JTt\n"
-"jMf9jYHBNInBvwTme6AFG5bz6tMlif77dJ9GAXHzODrR2Hq3thJA/3RjR3M1AkBg\n"
-"+6M4ncmtpYC+5lhwob0Bk90WU/6vFflfdhXsYoKWfNb95vsDR9qhS82Nbt25NClh\n"
-"VmMfzoFDHTkwYgj/F4PpAkEA+RaaSRP7BmbvFNqvlm8J/m0RVdAH4+p/Q5Z5u6Yo\n"
-"N7xC/gFi0qFPGKsDvD2CncAYmt+KNsd8S0JGDN4eieKn+Q==\n"
+"MIICXAIBAAKBgQDREn/4UUVgit0y0MjW/WONrWHnQjkVHPEZfkOMK73c90dEza+q\n"
+"87RPTbvL91m747YqptcS9SOT2jjmxUEI+tUGcSogptclOHhR9eXTZnLwRMuQYxF1\n"
+"WIg4Msykcnj84x2ECGRd2WkEwAVKZZF1aWNGLwLq5boRMvnShL2TMFhWUwIDAQAB\n"
+"AoGAU68L+eDN3C65CzX2rdcOmg7kOSSQpJrJBmM7tkdr3546sJeD0PFrIrMCkEmZ\n"
+"aVNj/v545+WnL+8RB4280lNUIF4AMNaMZUL+4FAtwekqWua3QvvqgRMjCdG3/h/d\n"
+"bOAUiiKKEimflTaIVHNVSCvOIntftOu3PhebctuabnZzg0ECQQD9i+FX7M9UXT1A\n"
+"bVm+bRIJuQtG+u9jD3VxrvHsmh0QnOAL3oa/ofTCwoTJLZs8Qy0GeAoJNf28rY1q\n"
+"AgNMEeEXAkEA0xhxNX2fDQ2yvKwPkPMrRycJVWry+KHvSZG2+XYh+V5sVGQ5H7Gu\n"
+"krc6IzRZlIKQhEGktkw8ih0DEHQbAihiJQJBAKi/SnFcePjrPXL91Hb63MB/2dOZ\n"
+"+21wwnexOe6A+8ssvajop8IvJlnhYMMMiX7oLrVZe0R6HLBQyge94zfjxm0CQGye\n"
+"dRIrE34qAEBo4JGbLjesdHcJUwBwgqn+WoI+MPkZhvBdqa8PRF6l/TpEI5vxGt+S\n"
+"z2gmDjia+QqsU4FmuikCQDDOs85uwNSKJFax9XMzd1qd1QwX20F8lvnOsWErXiDw\n"
+"Fy2+rmIRHoSxn4D+rE5ivqkO99E9jAlz+uuQz/6WqwE=\n"
"-----END RSA PRIVATE KEY-----\n";
diff --git a/src/test/test_dir.c b/src/test/test_dir.c
index 56ac3b34c..c03b63be2 100644
--- a/src/test/test_dir.c
+++ b/src/test/test_dir.c
@@ -11,6 +11,7 @@
#define ROUTER_PRIVATE
#define ROUTERLIST_PRIVATE
#define HIBERNATE_PRIVATE
+#define NETWORKSTATUS_PRIVATE
#include "or.h"
#include "config.h"
#include "directory.h"
@@ -97,7 +98,6 @@ test_dir_formats(void)
get_platform_str(platform, sizeof(platform));
r1 = tor_malloc_zero(sizeof(routerinfo_t));
- r1->address = tor_strdup("18.244.0.1");
r1->addr = 0xc0a80001u; /* 192.168.0.1 */
r1->cache_info.published_on = 0;
r1->or_port = 9000;
@@ -124,7 +124,6 @@ test_dir_formats(void)
ex2->maskbits = 8;
ex2->prt_min = ex2->prt_max = 24;
r2 = tor_malloc_zero(sizeof(routerinfo_t));
- r2->address = tor_strdup("1.1.1.1");
r2->addr = 0x0a030201u; /* 10.3.2.1 */
r2->platform = tor_strdup(platform);
r2->cache_info.published_on = 5;
@@ -153,7 +152,7 @@ test_dir_formats(void)
tor_free(options->ContactInfo);
test_assert(buf);
- strlcpy(buf2, "router Magri 18.244.0.1 9000 0 9003\n"
+ strlcpy(buf2, "router Magri 192.168.0.1 9000 0 9003\n"
"or-address [1:2:3:4::]:9999\n"
"platform Tor "VERSION" on ", sizeof(buf2));
strlcat(buf2, get_uname(), sizeof(buf2));
@@ -187,7 +186,7 @@ test_dir_formats(void)
cp = buf;
rp1 = router_parse_entry_from_string((const char*)cp,NULL,1,0,NULL);
test_assert(rp1);
- test_streq(rp1->address, r1->address);
+ test_eq(rp1->addr, r1->addr);
test_eq(rp1->or_port, r1->or_port);
//test_eq(rp1->dir_port, r1->dir_port);
test_eq(rp1->bandwidthrate, r1->bandwidthrate);
@@ -196,9 +195,10 @@ test_dir_formats(void)
test_assert(crypto_pk_cmp_keys(rp1->onion_pkey, pk1) == 0);
test_assert(crypto_pk_cmp_keys(rp1->identity_pkey, pk2) == 0);
//test_assert(rp1->exit_policy == NULL);
+ tor_free(buf);
strlcpy(buf2,
- "router Fred 1.1.1.1 9005 0 0\n"
+ "router Fred 10.3.2.1 9005 0 0\n"
"platform Tor "VERSION" on ", sizeof(buf2));
strlcat(buf2, get_uname(), sizeof(buf2));
strlcat(buf2, "\n"
@@ -214,8 +214,10 @@ test_dir_formats(void)
strlcat(buf2, "signing-key\n", sizeof(buf2));
strlcat(buf2, pk1_str, sizeof(buf2));
strlcat(buf2, "hidden-service-dir\n", sizeof(buf2));
+#ifdef CURVE25519_ENABLED
strlcat(buf2, "ntor-onion-key "
"skyinAnvardNostarsNomoonNowindormistsorsnow=\n", sizeof(buf2));
+#endif
strlcat(buf2, "accept *:80\nreject 18.0.0.0/8:24\n", sizeof(buf2));
strlcat(buf2, "router-signature\n", sizeof(buf2));
@@ -229,15 +231,17 @@ test_dir_formats(void)
cp = buf;
rp2 = router_parse_entry_from_string((const char*)cp,NULL,1,0,NULL);
test_assert(rp2);
- test_streq(rp2->address, r2->address);
+ test_eq(rp2->addr, r2->addr);
test_eq(rp2->or_port, r2->or_port);
test_eq(rp2->dir_port, r2->dir_port);
test_eq(rp2->bandwidthrate, r2->bandwidthrate);
test_eq(rp2->bandwidthburst, r2->bandwidthburst);
test_eq(rp2->bandwidthcapacity, r2->bandwidthcapacity);
+#ifdef CURVE25519_ENABLED
test_memeq(rp2->onion_curve25519_pkey->public_key,
r2->onion_curve25519_pkey->public_key,
CURVE25519_PUBKEY_LEN);
+#endif
test_assert(crypto_pk_cmp_keys(rp2->onion_pkey, pk2) == 0);
test_assert(crypto_pk_cmp_keys(rp2->identity_pkey, pk1) == 0);
@@ -275,6 +279,8 @@ test_dir_formats(void)
routerinfo_free(r1);
if (r2)
routerinfo_free(r2);
+ if (rp2)
+ routerinfo_free(rp2);
tor_free(buf);
tor_free(pk1_str);
@@ -937,7 +943,7 @@ gen_routerstatus_for_v3ns(int idx, time_t now)
tor_addr_copy(&rs->ipv6_addr, &addr_ipv6);
rs->ipv6_orport = 4711;
rs->is_exit = rs->is_stable = rs->is_fast = rs->is_flagged_running =
- rs->is_valid = rs->is_v2_dir = rs->is_possible_guard = 1;
+ rs->is_valid = rs->is_possible_guard = 1;
break;
case 2:
/* Generate the third routerstatus. */
@@ -952,7 +958,7 @@ gen_routerstatus_for_v3ns(int idx, time_t now)
rs->or_port = 400;
rs->dir_port = 9999;
rs->is_authority = rs->is_exit = rs->is_stable = rs->is_fast =
- rs->is_flagged_running = rs->is_valid = rs->is_v2_dir =
+ rs->is_flagged_running = rs->is_valid =
rs->is_possible_guard = 1;
break;
case 3:
@@ -1009,16 +1015,14 @@ vote_tweaks_for_v3ns(networkstatus_t *v, int voter, time_t now)
/* Monkey around with the list a bit */
vrs = smartlist_get(v->routerstatus_list, 2);
smartlist_del_keeporder(v->routerstatus_list, 2);
- tor_free(vrs->version);
- tor_free(vrs);
+ vote_routerstatus_free(vrs);
vrs = smartlist_get(v->routerstatus_list, 0);
vrs->status.is_fast = 1;
if (voter == 3) {
vrs = smartlist_get(v->routerstatus_list, 0);
smartlist_del_keeporder(v->routerstatus_list, 0);
- tor_free(vrs->version);
- tor_free(vrs);
+ vote_routerstatus_free(vrs);
vrs = smartlist_get(v->routerstatus_list, 0);
memset(vrs->status.descriptor_digest, (int)'Z', DIGEST_LEN);
test_assert(router_add_to_routerlist(
@@ -1061,7 +1065,8 @@ test_vrs_for_v3ns(vote_routerstatus_t *vrs, int voter, time_t now)
test_eq(rs->addr, 0x99008801);
test_eq(rs->or_port, 443);
test_eq(rs->dir_port, 8000);
- test_eq(vrs->flags, U64_LITERAL(16)); // no flags except "running"
+ /* no flags except "running" (16) and "v2dir" (64) */
+ tt_u64_op(vrs->flags, ==, U64_LITERAL(80));
} else if (tor_memeq(rs->identity_digest,
"\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5"
"\x5\x5\x5\x5",
@@ -1086,10 +1091,11 @@ test_vrs_for_v3ns(vote_routerstatus_t *vrs, int voter, time_t now)
test_assert(tor_addr_eq(&rs->ipv6_addr, &addr_ipv6));
test_eq(rs->ipv6_orport, 4711);
if (voter == 1) {
- test_eq(vrs->flags, U64_LITERAL(254)); // all flags except "authority."
+ /* all except "authority" (1) and "v2dir" (64) */
+ tt_u64_op(vrs->flags, ==, U64_LITERAL(190));
} else {
- /* 1023 - authority(1) - madeofcheese(16) - madeoftin(32) */
- test_eq(vrs->flags, U64_LITERAL(974));
+ /* 1023 - authority(1) - madeofcheese(16) - madeoftin(32) - v2dir(256) */
+ tt_u64_op(vrs->flags, ==, U64_LITERAL(718));
}
} else if (tor_memeq(rs->identity_digest,
"\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33"
@@ -1157,7 +1163,6 @@ test_routerstatus_for_v3ns(routerstatus_t *rs, time_t now)
test_assert(!rs->is_stable);
/* (If it wasn't running it wouldn't be here) */
test_assert(rs->is_flagged_running);
- test_assert(!rs->is_v2_dir);
test_assert(!rs->is_valid);
test_assert(!rs->is_named);
/* XXXX check version */
@@ -1184,7 +1189,6 @@ test_routerstatus_for_v3ns(routerstatus_t *rs, time_t now)
test_assert(rs->is_possible_guard);
test_assert(rs->is_stable);
test_assert(rs->is_flagged_running);
- test_assert(rs->is_v2_dir);
test_assert(rs->is_valid);
test_assert(!rs->is_named);
/* XXXX check version */
@@ -1226,7 +1230,8 @@ test_a_networkstatus(
vote_routerstatus_t *vrs;
routerstatus_t *rs;
int idx, n_rs, n_vrs;
- char *v1_text=NULL, *v2_text=NULL, *v3_text=NULL, *consensus_text=NULL, *cp;
+ char *v1_text=NULL, *v2_text=NULL, *v3_text=NULL, *consensus_text=NULL,
+ *cp=NULL;
smartlist_t *votes = smartlist_new();
/* For generating the two other consensuses. */
@@ -1244,7 +1249,6 @@ test_a_networkstatus(
/* Parse certificates and keys. */
cert1 = authority_cert_parse_from_string(AUTHORITY_CERT_1, NULL);
test_assert(cert1);
- test_assert(cert1->is_cross_certified);
cert2 = authority_cert_parse_from_string(AUTHORITY_CERT_2, NULL);
test_assert(cert2);
cert3 = authority_cert_parse_from_string(AUTHORITY_CERT_3, NULL);
@@ -1358,7 +1362,8 @@ test_a_networkstatus(
vote->dist_seconds = 300;
authority_cert_free(vote->cert);
vote->cert = authority_cert_dup(cert2);
- vote->net_params = smartlist_new();
+ SMARTLIST_FOREACH(vote->net_params, char *, c, tor_free(c));
+ smartlist_clear(vote->net_params);
smartlist_split_string(vote->net_params, "bar=2000000000 circuitwindow=20",
NULL, 0, 0);
tor_free(vote->client_versions);
@@ -1402,7 +1407,8 @@ test_a_networkstatus(
vote->dist_seconds = 250;
authority_cert_free(vote->cert);
vote->cert = authority_cert_dup(cert3);
- vote->net_params = smartlist_new();
+ SMARTLIST_FOREACH(vote->net_params, char *, c, tor_free(c));
+ smartlist_clear(vote->net_params);
smartlist_split_string(vote->net_params, "circuitwindow=80 foo=660",
NULL, 0, 0);
smartlist_add(vote->supported_methods, tor_strdup("4"));
@@ -1645,6 +1651,7 @@ test_a_networkstatus(
}
done:
+ tor_free(cp);
smartlist_free(votes);
tor_free(v1_text);
tor_free(v2_text);
@@ -1768,7 +1775,7 @@ test_dir_random_weighted(void *testdata)
inp[i].u64 = vals[i];
total += vals[i];
}
- tt_int_op(total, ==, 45);
+ tt_u64_op(total, ==, 45);
for (i=0; i<n; ++i) {
choice = choose_array_element_by_weight(inp, 10);
tt_int_op(choice, >=, 0);
@@ -1886,7 +1893,7 @@ gen_routerstatus_for_umbw(int idx, time_t now)
tor_addr_copy(&rs->ipv6_addr, &addr_ipv6);
rs->ipv6_orport = 4711;
rs->is_exit = rs->is_stable = rs->is_fast = rs->is_flagged_running =
- rs->is_valid = rs->is_v2_dir = rs->is_possible_guard = 1;
+ rs->is_valid = rs->is_possible_guard = 1;
/*
* This one has measured bandwidth above the clip cutoff, and
* so shouldn't be clipped; we'll have to test that it isn't
@@ -1909,7 +1916,7 @@ gen_routerstatus_for_umbw(int idx, time_t now)
rs->or_port = 400;
rs->dir_port = 9999;
rs->is_authority = rs->is_exit = rs->is_stable = rs->is_fast =
- rs->is_flagged_running = rs->is_valid = rs->is_v2_dir =
+ rs->is_flagged_running = rs->is_valid =
rs->is_possible_guard = 1;
/*
* This one has unmeasured bandwidth above the clip cutoff, and
@@ -1978,6 +1985,7 @@ vote_tweaks_for_umbw(networkstatus_t *v, int voter, time_t now)
(void)now;
test_assert(v->supported_methods);
+ SMARTLIST_FOREACH(v->supported_methods, char *, c, tor_free(c));
smartlist_clear(v->supported_methods);
/* Method 17 is MIN_METHOD_TO_CLIP_UNMEASURED_BW_KB */
smartlist_split_string(v->supported_methods,
@@ -2145,7 +2153,6 @@ test_routerstatus_for_umbw(routerstatus_t *rs, time_t now)
test_assert(!rs->is_stable);
/* (If it wasn't running it wouldn't be here) */
test_assert(rs->is_flagged_running);
- test_assert(!rs->is_v2_dir);
test_assert(!rs->is_valid);
test_assert(!rs->is_named);
/* This one should have measured bandwidth below the clip cutoff */
@@ -2176,7 +2183,6 @@ test_routerstatus_for_umbw(routerstatus_t *rs, time_t now)
test_assert(rs->is_possible_guard);
test_assert(rs->is_stable);
test_assert(rs->is_flagged_running);
- test_assert(rs->is_v2_dir);
test_assert(rs->is_valid);
test_assert(!rs->is_named);
/* This one should have measured bandwidth above the clip cutoff */
@@ -2254,82 +2260,6 @@ test_dir_clip_unmeasured_bw_kb_alt(void)
test_routerstatus_for_umbw);
}
-extern time_t time_of_process_start; /* from main.c */
-
-static void
-test_dir_v2_dir(void *arg)
-{
- /* Runs in a forked process: acts like a v2 directory just enough to make and
- * sign a v2 networkstatus opinion */
-
- cached_dir_t *v2 = NULL;
- or_options_t *options = get_options_mutable();
- crypto_pk_t *id_key = pk_generate(4);
- (void) arg;
-
- options->ORPort_set = 1; /* So we believe we're a server. */
- options->DirPort_set = 1;
- options->Address = tor_strdup("99.99.99.99");
- options->Nickname = tor_strdup("TestV2Auth");
- options->ContactInfo = tor_strdup("TestV2Auth <testv2auth@example.com>");
- {
- /* Give it a DirPort */
- smartlist_t *ports = (smartlist_t *)get_configured_ports();
- port_cfg_t *port = tor_malloc_zero(sizeof(port_cfg_t));
- port->type = CONN_TYPE_DIR_LISTENER;
- port->port = 9999;
- smartlist_add(ports, port);
- }
- set_server_identity_key(id_key);
- set_client_identity_key(id_key);
-
- /* Add a router. */
- {
- was_router_added_t wra;
- const char *msg = NULL;
- routerinfo_t *r1 = tor_malloc_zero(sizeof(routerinfo_t));
- r1->address = tor_strdup("18.244.0.1");
- r1->addr = 0xc0a80001u; /* 192.168.0.1 */
- r1->cache_info.published_on = time(NULL)-60;
- r1->or_port = 9000;
- r1->dir_port = 9003;
- tor_addr_parse(&r1->ipv6_addr, "1:2:3:4::");
- r1->ipv6_orport = 9999;
- r1->onion_pkey = pk_generate(1);
- r1->identity_pkey = pk_generate(2);
- r1->bandwidthrate = 1000;
- r1->bandwidthburst = 5000;
- r1->bandwidthcapacity = 10000;
- r1->exit_policy = NULL;
- r1->nickname = tor_strdup("Magri");
- r1->platform = tor_strdup("Tor 0.2.7.7-gamma");
- r1->cache_info.routerlist_index = -1;
- r1->cache_info.signed_descriptor_body =
- router_dump_router_to_string(r1, r1->identity_pkey);
- r1->cache_info.signed_descriptor_len =
- strlen(r1->cache_info.signed_descriptor_body);
- wra = router_add_to_routerlist(r1, &msg, 0, 0);
- tt_int_op(wra, ==, ROUTER_ADDED_SUCCESSFULLY);
- }
-
- /* Prevent call of rep_hist_note_router_unreachable(). */
- time_of_process_start = time(NULL);
-
- /* Make a directory so there's somewhere to store the thing */
-#ifdef _WIN32
- mkdir(get_fname("cached-status"));
-#else
- mkdir(get_fname("cached-status"), 0700);
-#endif
-
- v2 = generate_v2_networkstatus_opinion();
- tt_assert(v2);
-
- done:
- crypto_pk_free(id_key);
- cached_dir_decref(v2);
-}
-
static void
test_dir_fmt_control_ns(void *arg)
{
@@ -2357,13 +2287,81 @@ test_dir_fmt_control_ns(void *arg)
"r TetsuoMilk U3RhdGVseSwgcGx1bXAgQnVjayA "
"TXVsbGlnYW4gY2FtZSB1cCBmcm8 2013-04-02 17:53:18 "
"32.48.64.80 9001 9002\n"
- "s Exit Fast Running\n"
+ "s Exit Fast Running V2Dir\n"
"w Bandwidth=1000\n");
done:
tor_free(s);
}
+static void
+test_dir_http_handling(void *args)
+{
+ char *url = NULL;
+ (void)args;
+
+ /* Parse http url tests: */
+ /* Good headers */
+ test_eq(parse_http_url("GET /tor/a/b/c.txt HTTP/1.1\r\n"
+ "Host: example.com\r\n"
+ "User-Agent: Mozilla/5.0 (Windows;"
+ " U; Windows NT 6.1; en-US; rv:1.9.1.5)\r\n",
+ &url), 0);
+ test_streq(url, "/tor/a/b/c.txt");
+ tor_free(url);
+
+ test_eq(parse_http_url("GET /tor/a/b/c.txt HTTP/1.0\r\n", &url), 0);
+ test_streq(url, "/tor/a/b/c.txt");
+ tor_free(url);
+
+ test_eq(parse_http_url("GET /tor/a/b/c.txt HTTP/1.600\r\n", &url), 0);
+ test_streq(url, "/tor/a/b/c.txt");
+ tor_free(url);
+
+ /* Should prepend '/tor/' to url if required */
+ test_eq(parse_http_url("GET /a/b/c.txt HTTP/1.1\r\n"
+ "Host: example.com\r\n"
+ "User-Agent: Mozilla/5.0 (Windows;"
+ " U; Windows NT 6.1; en-US; rv:1.9.1.5)\r\n",
+ &url), 0);
+ test_streq(url, "/tor/a/b/c.txt");
+ tor_free(url);
+
+ /* Bad headers -- no HTTP/1.x*/
+ test_eq(parse_http_url("GET /a/b/c.txt\r\n"
+ "Host: example.com\r\n"
+ "User-Agent: Mozilla/5.0 (Windows;"
+ " U; Windows NT 6.1; en-US; rv:1.9.1.5)\r\n",
+ &url), -1);
+ tt_assert(!url);
+
+ /* Bad headers */
+ test_eq(parse_http_url("GET /a/b/c.txt\r\n"
+ "Host: example.com\r\n"
+ "User-Agent: Mozilla/5.0 (Windows;"
+ " U; Windows NT 6.1; en-US; rv:1.9.1.5)\r\n",
+ &url), -1);
+ tt_assert(!url);
+
+ test_eq(parse_http_url("GET /tor/a/b/c.txt", &url), -1);
+ tt_assert(!url);
+
+ test_eq(parse_http_url("GET /tor/a/b/c.txt HTTP/1.1", &url), -1);
+ tt_assert(!url);
+
+ test_eq(parse_http_url("GET /tor/a/b/c.txt HTTP/1.1x\r\n", &url), -1);
+ tt_assert(!url);
+
+ test_eq(parse_http_url("GET /tor/a/b/c.txt HTTP/1.", &url), -1);
+ tt_assert(!url);
+
+ test_eq(parse_http_url("GET /tor/a/b/c.txt HTTP/1.\r", &url), -1);
+ tt_assert(!url);
+
+ done:
+ tor_free(url);
+}
+
#define DIR_LEGACY(name) \
{ #name, legacy_test_helper, TT_FORK, &legacy_setup, test_dir_ ## name }
@@ -2384,8 +2382,8 @@ struct testcase_t dir_tests[] = {
DIR(scale_bw, 0),
DIR_LEGACY(clip_unmeasured_bw_kb),
DIR_LEGACY(clip_unmeasured_bw_kb_alt),
- DIR(v2_dir, TT_FORK),
DIR(fmt_control_ns, 0),
+ DIR(http_handling, 0),
END_OF_TESTCASES
};
diff --git a/src/test/test_extorport.c b/src/test/test_extorport.c
new file mode 100644
index 000000000..93c8f77d5
--- /dev/null
+++ b/src/test/test_extorport.c
@@ -0,0 +1,607 @@
+/* Copyright (c) 2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#define CONNECTION_PRIVATE
+#define EXT_ORPORT_PRIVATE
+#define MAIN_PRIVATE
+#include "or.h"
+#include "buffers.h"
+#include "connection.h"
+#include "connection_or.h"
+#include "config.h"
+#include "control.h"
+#include "ext_orport.h"
+#include "main.h"
+#include "test.h"
+
+/* Test connection_or_remove_from_ext_or_id_map and
+ * connection_or_set_ext_or_identifier */
+static void
+test_ext_or_id_map(void *arg)
+{
+ or_connection_t *c1 = NULL, *c2 = NULL, *c3 = NULL;
+ char *idp = NULL, *idp2 = NULL;
+ (void)arg;
+
+ /* pre-initialization */
+ tt_ptr_op(NULL, ==, connection_or_get_by_ext_or_id("xxxxxxxxxxxxxxxxxxxx"));
+
+ c1 = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
+ c2 = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
+ c3 = or_connection_new(CONN_TYPE_OR, AF_INET);
+
+ tt_ptr_op(c1->ext_or_conn_id, !=, NULL);
+ tt_ptr_op(c2->ext_or_conn_id, !=, NULL);
+ tt_ptr_op(c3->ext_or_conn_id, ==, NULL);
+
+ tt_ptr_op(c1, ==, connection_or_get_by_ext_or_id(c1->ext_or_conn_id));
+ tt_ptr_op(c2, ==, connection_or_get_by_ext_or_id(c2->ext_or_conn_id));
+ tt_ptr_op(NULL, ==, connection_or_get_by_ext_or_id("xxxxxxxxxxxxxxxxxxxx"));
+
+ idp = tor_memdup(c2->ext_or_conn_id, EXT_OR_CONN_ID_LEN);
+
+ /* Give c2 a new ID. */
+ connection_or_set_ext_or_identifier(c2);
+ test_mem_op(idp, !=, c2->ext_or_conn_id, EXT_OR_CONN_ID_LEN);
+ idp2 = tor_memdup(c2->ext_or_conn_id, EXT_OR_CONN_ID_LEN);
+ tt_assert(!tor_digest_is_zero(idp2));
+
+ tt_ptr_op(NULL, ==, connection_or_get_by_ext_or_id(idp));
+ tt_ptr_op(c2, ==, connection_or_get_by_ext_or_id(idp2));
+
+ /* Now remove it. */
+ connection_or_remove_from_ext_or_id_map(c2);
+ tt_ptr_op(NULL, ==, connection_or_get_by_ext_or_id(idp));
+ tt_ptr_op(NULL, ==, connection_or_get_by_ext_or_id(idp2));
+
+ done:
+ if (c1)
+ connection_free_(TO_CONN(c1));
+ if (c2)
+ connection_free_(TO_CONN(c2));
+ if (c3)
+ connection_free_(TO_CONN(c3));
+ tor_free(idp);
+ tor_free(idp2);
+ connection_or_clear_ext_or_id_map();
+}
+
+/* Simple connection_write_to_buf_impl_ replacement that unconditionally
+ * writes to outbuf. */
+static void
+connection_write_to_buf_impl_replacement(const char *string, size_t len,
+ connection_t *conn, int zlib)
+{
+ (void) zlib;
+
+ tor_assert(string);
+ tor_assert(conn);
+ write_to_buf(string, len, conn->outbuf);
+}
+
+static char *
+buf_get_contents(buf_t *buf, size_t *sz_out)
+{
+ char *out;
+ *sz_out = buf_datalen(buf);
+ if (*sz_out >= ULONG_MAX)
+ return NULL; /* C'mon, really? */
+ out = tor_malloc(*sz_out + 1);
+ if (fetch_from_buf(out, (unsigned long)*sz_out, buf) != 0) {
+ tor_free(out);
+ return NULL;
+ }
+ out[*sz_out] = '\0'; /* Hopefully gratuitous. */
+ return out;
+}
+
+static void
+test_ext_or_write_command(void *arg)
+{
+ or_connection_t *c1;
+ char *cp = NULL;
+ char *buf = NULL;
+ size_t sz;
+
+ (void) arg;
+ MOCK(connection_write_to_buf_impl_,
+ connection_write_to_buf_impl_replacement);
+
+ c1 = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
+ tt_assert(c1);
+
+ /* Length too long */
+ tt_int_op(connection_write_ext_or_command(TO_CONN(c1), 100, "X", 100000),
+ <, 0);
+
+ /* Empty command */
+ tt_int_op(connection_write_ext_or_command(TO_CONN(c1), 0x99, NULL, 0),
+ ==, 0);
+ cp = buf_get_contents(TO_CONN(c1)->outbuf, &sz);
+ tt_int_op(sz, ==, 4);
+ test_mem_op(cp, ==, "\x00\x99\x00\x00", 4);
+ tor_free(cp);
+
+ /* Medium command. */
+ tt_int_op(connection_write_ext_or_command(TO_CONN(c1), 0x99,
+ "Wai\0Hello", 9), ==, 0);
+ cp = buf_get_contents(TO_CONN(c1)->outbuf, &sz);
+ tt_int_op(sz, ==, 13);
+ test_mem_op(cp, ==, "\x00\x99\x00\x09Wai\x00Hello", 13);
+ tor_free(cp);
+
+ /* Long command */
+ buf = tor_malloc(65535);
+ memset(buf, 'x', 65535);
+ tt_int_op(connection_write_ext_or_command(TO_CONN(c1), 0xf00d,
+ buf, 65535), ==, 0);
+ cp = buf_get_contents(TO_CONN(c1)->outbuf, &sz);
+ tt_int_op(sz, ==, 65539);
+ test_mem_op(cp, ==, "\xf0\x0d\xff\xff", 4);
+ test_mem_op(cp+4, ==, buf, 65535);
+ tor_free(cp);
+
+ done:
+ if (c1)
+ connection_free_(TO_CONN(c1));
+ tor_free(cp);
+ tor_free(buf);
+ UNMOCK(connection_write_to_buf_impl_);
+}
+
+static int
+write_bytes_to_file_fail(const char *fname, const char *str, size_t len,
+ int bin)
+{
+ (void) fname;
+ (void) str;
+ (void) len;
+ (void) bin;
+
+ return -1;
+}
+
+static void
+test_ext_or_init_auth(void *arg)
+{
+ or_options_t *options = get_options_mutable();
+ const char *fn;
+ char *cp = NULL;
+ struct stat st;
+ char cookie0[32];
+ (void)arg;
+
+ /* Check default filename location */
+ tor_free(options->DataDirectory);
+ options->DataDirectory = tor_strdup("foo");
+ cp = get_ext_or_auth_cookie_file_name();
+ tt_str_op(cp, ==, "foo"PATH_SEPARATOR"extended_orport_auth_cookie");
+ tor_free(cp);
+
+ /* Shouldn't be initialized already, or our tests will be a bit
+ * meaningless */
+ ext_or_auth_cookie = tor_malloc_zero(32);
+ test_assert(tor_mem_is_zero((char*)ext_or_auth_cookie, 32));
+
+ /* Now make sure we use a temporary file */
+ fn = get_fname("ext_cookie_file");
+ options->ExtORPortCookieAuthFile = tor_strdup(fn);
+ cp = get_ext_or_auth_cookie_file_name();
+ tt_str_op(cp, ==, fn);
+ tor_free(cp);
+
+ /* Test the initialization function with a broken
+ write_bytes_to_file(). See if the problem is handled properly. */
+ MOCK(write_bytes_to_file, write_bytes_to_file_fail);
+ tt_int_op(-1, ==, init_ext_or_cookie_authentication(1));
+ tt_int_op(ext_or_auth_cookie_is_set, ==, 0);
+ UNMOCK(write_bytes_to_file);
+
+ /* Now do the actual initialization. */
+ tt_int_op(0, ==, init_ext_or_cookie_authentication(1));
+ tt_int_op(ext_or_auth_cookie_is_set, ==, 1);
+ cp = read_file_to_str(fn, RFTS_BIN, &st);
+ tt_ptr_op(cp, !=, NULL);
+ tt_u64_op((uint64_t)st.st_size, ==, 64);
+ test_memeq(cp, "! Extended ORPort Auth Cookie !\x0a", 32);
+ test_memeq(cp+32, ext_or_auth_cookie, 32);
+ memcpy(cookie0, ext_or_auth_cookie, 32);
+ test_assert(!tor_mem_is_zero((char*)ext_or_auth_cookie, 32));
+
+ /* Operation should be idempotent. */
+ tt_int_op(0, ==, init_ext_or_cookie_authentication(1));
+ test_memeq(cookie0, ext_or_auth_cookie, 32);
+
+ done:
+ tor_free(cp);
+ ext_orport_free_all();
+}
+
+static void
+test_ext_or_cookie_auth(void *arg)
+{
+ char *reply=NULL, *reply2=NULL, *client_hash=NULL, *client_hash2=NULL;
+ size_t reply_len=0;
+ char hmac1[32], hmac2[32];
+
+ const char client_nonce[32] =
+ "Who is the third who walks alway";
+ char server_hash_input[] =
+ "ExtORPort authentication server-to-client hash"
+ "Who is the third who walks alway"
+ "................................";
+ char client_hash_input[] =
+ "ExtORPort authentication client-to-server hash"
+ "Who is the third who walks alway"
+ "................................";
+
+ (void)arg;
+
+ tt_int_op(strlen(client_hash_input), ==, 46+32+32);
+ tt_int_op(strlen(server_hash_input), ==, 46+32+32);
+
+ ext_or_auth_cookie = tor_malloc_zero(32);
+ memcpy(ext_or_auth_cookie, "s beside you? When I count, ther", 32);
+ ext_or_auth_cookie_is_set = 1;
+
+ /* For this authentication, the client sends 32 random bytes (ClientNonce)
+ * The server replies with 32 byte ServerHash and 32 byte ServerNonce,
+ * where ServerHash is:
+ * HMAC-SHA256(CookieString,
+ * "ExtORPort authentication server-to-client hash" | ClientNonce |
+ * ServerNonce)"
+ * The client must reply with 32-byte ClientHash, which we compute as:
+ * ClientHash is computed as:
+ * HMAC-SHA256(CookieString,
+ * "ExtORPort authentication client-to-server hash" | ClientNonce |
+ * ServerNonce)
+ */
+
+ /* Wrong length */
+ tt_int_op(-1, ==,
+ handle_client_auth_nonce(client_nonce, 33, &client_hash, &reply,
+ &reply_len));
+ tt_int_op(-1, ==,
+ handle_client_auth_nonce(client_nonce, 31, &client_hash, &reply,
+ &reply_len));
+
+ /* Now let's try this for real! */
+ tt_int_op(0, ==,
+ handle_client_auth_nonce(client_nonce, 32, &client_hash, &reply,
+ &reply_len));
+ tt_int_op(reply_len, ==, 64);
+ tt_ptr_op(reply, !=, NULL);
+ tt_ptr_op(client_hash, !=, NULL);
+ /* Fill in the server nonce into the hash inputs... */
+ memcpy(server_hash_input+46+32, reply+32, 32);
+ memcpy(client_hash_input+46+32, reply+32, 32);
+ /* Check the HMACs are correct... */
+ crypto_hmac_sha256(hmac1, (char*)ext_or_auth_cookie, 32, server_hash_input,
+ 46+32+32);
+ crypto_hmac_sha256(hmac2, (char*)ext_or_auth_cookie, 32, client_hash_input,
+ 46+32+32);
+ test_memeq(hmac1, reply, 32);
+ test_memeq(hmac2, client_hash, 32);
+
+ /* Now do it again and make sure that the results are *different* */
+ tt_int_op(0, ==,
+ handle_client_auth_nonce(client_nonce, 32, &client_hash2, &reply2,
+ &reply_len));
+ test_memneq(reply2, reply, reply_len);
+ test_memneq(client_hash2, client_hash, 32);
+ /* But that this one checks out too. */
+ memcpy(server_hash_input+46+32, reply2+32, 32);
+ memcpy(client_hash_input+46+32, reply2+32, 32);
+ /* Check the HMACs are correct... */
+ crypto_hmac_sha256(hmac1, (char*)ext_or_auth_cookie, 32, server_hash_input,
+ 46+32+32);
+ crypto_hmac_sha256(hmac2, (char*)ext_or_auth_cookie, 32, client_hash_input,
+ 46+32+32);
+ test_memeq(hmac1, reply2, 32);
+ test_memeq(hmac2, client_hash2, 32);
+
+ done:
+ tor_free(reply);
+ tor_free(client_hash);
+ tor_free(reply2);
+ tor_free(client_hash2);
+}
+
+static int
+crypto_rand_return_tse_str(char *to, size_t n)
+{
+ if (n != 32) {
+ TT_FAIL(("Asked for %d bytes, not 32", (int)n));
+ return -1;
+ }
+ memcpy(to, "te road There is always another ", 32);
+ return 0;
+}
+
+static void
+test_ext_or_cookie_auth_testvec(void *arg)
+{
+ char *reply=NULL, *client_hash=NULL;
+ size_t reply_len;
+ char *mem_op_hex_tmp=NULL;
+
+ const char client_nonce[] = "But when I look ahead up the whi";
+ (void)arg;
+
+ ext_or_auth_cookie = tor_malloc_zero(32);
+ memcpy(ext_or_auth_cookie, "Gliding wrapt in a brown mantle," , 32);
+ ext_or_auth_cookie_is_set = 1;
+
+ MOCK(crypto_rand, crypto_rand_return_tse_str);
+
+ tt_int_op(0, ==,
+ handle_client_auth_nonce(client_nonce, 32, &client_hash, &reply,
+ &reply_len));
+ tt_ptr_op(reply, !=, NULL );
+ tt_uint_op(reply_len, ==, 64);
+ test_memeq(reply+32, "te road There is always another ", 32);
+ /* HMACSHA256("Gliding wrapt in a brown mantle,"
+ * "ExtORPort authentication server-to-client hash"
+ * "But when I look ahead up the write road There is always another ");
+ */
+ test_memeq_hex(reply,
+ "ec80ed6e546d3b36fdfc22fe1315416b"
+ "029f1ade7610d910878b62eeb7403821");
+ /* HMACSHA256("Gliding wrapt in a brown mantle,"
+ * "ExtORPort authentication client-to-server hash"
+ * "But when I look ahead up the write road There is always another ");
+ * (Both values computed using Python CLI.)
+ */
+ test_memeq_hex(client_hash,
+ "ab391732dd2ed968cd40c087d1b1f25b"
+ "33b3cd77ff79bd80c2074bbf438119a2");
+
+ done:
+ UNMOCK(crypto_rand);
+ tor_free(reply);
+ tor_free(client_hash);
+ tor_free(mem_op_hex_tmp);
+}
+
+static void
+ignore_bootstrap_problem(const char *warn, int reason,
+ or_connection_t *conn)
+{
+ (void)warn;
+ (void)reason;
+ (void)conn;
+}
+
+static int is_reading = 1;
+static int handshake_start_called = 0;
+
+static void
+note_read_stopped(connection_t *conn)
+{
+ (void)conn;
+ is_reading=0;
+}
+static void
+note_read_started(connection_t *conn)
+{
+ (void)conn;
+ is_reading=1;
+}
+static int
+handshake_start(or_connection_t *conn, int receiving)
+{
+ if (!conn || !receiving)
+ TT_FAIL(("Bad arguments to handshake_start"));
+ handshake_start_called = 1;
+ return 0;
+}
+
+#define WRITE(s,n) \
+ do { \
+ write_to_buf((s), (n), TO_CONN(conn)->inbuf); \
+ } while (0)
+#define CONTAINS(s,n) \
+ do { \
+ tt_int_op((n), <=, sizeof(b)); \
+ tt_int_op(buf_datalen(TO_CONN(conn)->outbuf), ==, (n)); \
+ if ((n)) { \
+ fetch_from_buf(b, (n), TO_CONN(conn)->outbuf); \
+ test_memeq(b, (s), (n)); \
+ } \
+ } while (0)
+
+/* Helper: Do a successful Extended ORPort authentication handshake. */
+static void
+do_ext_or_handshake(or_connection_t *conn)
+{
+ char b[256];
+
+ tt_int_op(0, ==, connection_ext_or_start_auth(conn));
+ CONTAINS("\x01\x00", 2);
+ WRITE("\x01", 1);
+ WRITE("But when I look ahead up the whi", 32);
+ MOCK(crypto_rand, crypto_rand_return_tse_str);
+ tt_int_op(0, ==, connection_ext_or_process_inbuf(conn));
+ UNMOCK(crypto_rand);
+ tt_int_op(TO_CONN(conn)->state, ==, EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_HASH);
+ CONTAINS("\xec\x80\xed\x6e\x54\x6d\x3b\x36\xfd\xfc\x22\xfe\x13\x15\x41\x6b"
+ "\x02\x9f\x1a\xde\x76\x10\xd9\x10\x87\x8b\x62\xee\xb7\x40\x38\x21"
+ "te road There is always another ", 64);
+ /* Send the right response this time. */
+ WRITE("\xab\x39\x17\x32\xdd\x2e\xd9\x68\xcd\x40\xc0\x87\xd1\xb1\xf2\x5b"
+ "\x33\xb3\xcd\x77\xff\x79\xbd\x80\xc2\x07\x4b\xbf\x43\x81\x19\xa2",
+ 32);
+ tt_int_op(0, ==, connection_ext_or_process_inbuf(conn));
+ CONTAINS("\x01", 1);
+ tt_assert(! TO_CONN(conn)->marked_for_close);
+ tt_int_op(TO_CONN(conn)->state, ==, EXT_OR_CONN_STATE_OPEN);
+
+ done: ;
+}
+
+static void
+test_ext_or_handshake(void *arg)
+{
+ or_connection_t *conn=NULL;
+ char b[256];
+
+ (void) arg;
+ MOCK(connection_write_to_buf_impl_,
+ connection_write_to_buf_impl_replacement);
+ /* Use same authenticators as for test_ext_or_cookie_auth_testvec */
+ ext_or_auth_cookie = tor_malloc_zero(32);
+ memcpy(ext_or_auth_cookie, "Gliding wrapt in a brown mantle," , 32);
+ ext_or_auth_cookie_is_set = 1;
+
+ init_connection_lists();
+
+ conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
+ tt_int_op(0, ==, connection_ext_or_start_auth(conn));
+ /* The server starts by telling us about the one supported authtype. */
+ CONTAINS("\x01\x00", 2);
+ /* Say the client hasn't responded yet. */
+ tt_int_op(0, ==, connection_ext_or_process_inbuf(conn));
+ /* Let's say the client replies badly. */
+ WRITE("\x99", 1);
+ tt_int_op(-1, ==, connection_ext_or_process_inbuf(conn));
+ CONTAINS("", 0);
+ tt_assert(TO_CONN(conn)->marked_for_close);
+ close_closeable_connections();
+ conn = NULL;
+
+ /* Okay, try again. */
+ conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
+ tt_int_op(0, ==, connection_ext_or_start_auth(conn));
+ CONTAINS("\x01\x00", 2);
+ /* Let's say the client replies sensibly this time. "Yes, AUTHTYPE_COOKIE
+ * sounds delicious. Let's have some of that!" */
+ WRITE("\x01", 1);
+ /* Let's say that the client also sends part of a nonce. */
+ WRITE("But when I look ", 16);
+ tt_int_op(0, ==, connection_ext_or_process_inbuf(conn));
+ CONTAINS("", 0);
+ tt_int_op(TO_CONN(conn)->state, ==,
+ EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_NONCE);
+ /* Pump it again. Nothing should happen. */
+ tt_int_op(0, ==, connection_ext_or_process_inbuf(conn));
+ /* send the rest of the nonce. */
+ WRITE("ahead up the whi", 16);
+ MOCK(crypto_rand, crypto_rand_return_tse_str);
+ tt_int_op(0, ==, connection_ext_or_process_inbuf(conn));
+ UNMOCK(crypto_rand);
+ /* We should get the right reply from the server. */
+ CONTAINS("\xec\x80\xed\x6e\x54\x6d\x3b\x36\xfd\xfc\x22\xfe\x13\x15\x41\x6b"
+ "\x02\x9f\x1a\xde\x76\x10\xd9\x10\x87\x8b\x62\xee\xb7\x40\x38\x21"
+ "te road There is always another ", 64);
+ /* Send the wrong response. */
+ WRITE("not with a bang but a whimper...", 32);
+ MOCK(control_event_bootstrap_problem, ignore_bootstrap_problem);
+ tt_int_op(-1, ==, connection_ext_or_process_inbuf(conn));
+ CONTAINS("\x00", 1);
+ tt_assert(TO_CONN(conn)->marked_for_close);
+ /* XXXX Hold-open-until-flushed. */
+ close_closeable_connections();
+ conn = NULL;
+ UNMOCK(control_event_bootstrap_problem);
+
+ MOCK(connection_start_reading, note_read_started);
+ MOCK(connection_stop_reading, note_read_stopped);
+ MOCK(connection_tls_start_handshake, handshake_start);
+
+ /* Okay, this time let's succeed. */
+ conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
+ do_ext_or_handshake(conn);
+
+ /* Now let's run through some messages. */
+ /* First let's send some junk and make sure it's ignored. */
+ WRITE("\xff\xf0\x00\x03""ABC", 7);
+ tt_int_op(0, ==, connection_ext_or_process_inbuf(conn));
+ CONTAINS("", 0);
+ /* Now let's send a USERADDR command. */
+ WRITE("\x00\x01\x00\x0c""1.2.3.4:5678", 16);
+ tt_int_op(0, ==, connection_ext_or_process_inbuf(conn));
+ tt_int_op(TO_CONN(conn)->port, ==, 5678);
+ tt_int_op(tor_addr_to_ipv4h(&TO_CONN(conn)->addr), ==, 0x01020304);
+ /* Now let's send a TRANSPORT command. */
+ WRITE("\x00\x02\x00\x07""rfc1149", 11);
+ tt_int_op(0, ==, connection_ext_or_process_inbuf(conn));
+ tt_ptr_op(NULL, !=, conn->ext_or_transport);
+ tt_str_op("rfc1149", ==, conn->ext_or_transport);
+ tt_int_op(is_reading,==,1);
+ tt_int_op(TO_CONN(conn)->state, ==, EXT_OR_CONN_STATE_OPEN);
+ /* DONE */
+ WRITE("\x00\x00\x00\x00", 4);
+ tt_int_op(0, ==, connection_ext_or_process_inbuf(conn));
+ tt_int_op(TO_CONN(conn)->state, ==, EXT_OR_CONN_STATE_FLUSHING);
+ tt_int_op(is_reading,==,0);
+ CONTAINS("\x10\x00\x00\x00", 4);
+ tt_int_op(handshake_start_called,==,0);
+ tt_int_op(0, ==, connection_ext_or_finished_flushing(conn));
+ tt_int_op(is_reading,==,1);
+ tt_int_op(handshake_start_called,==,1);
+ tt_int_op(TO_CONN(conn)->type, ==, CONN_TYPE_OR);
+ tt_int_op(TO_CONN(conn)->state, ==, 0);
+ close_closeable_connections();
+ conn = NULL;
+
+ /* Okay, this time let's succeed the handshake but fail the USERADDR
+ command. */
+ conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
+ do_ext_or_handshake(conn);
+ /* USERADDR command with an extra NUL byte */
+ WRITE("\x00\x01\x00\x0d""1.2.3.4:5678\x00", 17);
+ MOCK(control_event_bootstrap_problem, ignore_bootstrap_problem);
+ tt_int_op(-1, ==, connection_ext_or_process_inbuf(conn));
+ CONTAINS("", 0);
+ tt_assert(TO_CONN(conn)->marked_for_close);
+ close_closeable_connections();
+ conn = NULL;
+ UNMOCK(control_event_bootstrap_problem);
+
+ /* Now fail the TRANSPORT command. */
+ conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
+ do_ext_or_handshake(conn);
+ /* TRANSPORT command with an extra NUL byte */
+ WRITE("\x00\x02\x00\x08""rfc1149\x00", 12);
+ MOCK(control_event_bootstrap_problem, ignore_bootstrap_problem);
+ tt_int_op(-1, ==, connection_ext_or_process_inbuf(conn));
+ CONTAINS("", 0);
+ tt_assert(TO_CONN(conn)->marked_for_close);
+ close_closeable_connections();
+ conn = NULL;
+ UNMOCK(control_event_bootstrap_problem);
+
+ /* Now fail the TRANSPORT command. */
+ conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
+ do_ext_or_handshake(conn);
+ /* TRANSPORT command with transport name with symbols (not a
+ C-identifier) */
+ WRITE("\x00\x02\x00\x07""rf*1149", 11);
+ MOCK(control_event_bootstrap_problem, ignore_bootstrap_problem);
+ tt_int_op(-1, ==, connection_ext_or_process_inbuf(conn));
+ CONTAINS("", 0);
+ tt_assert(TO_CONN(conn)->marked_for_close);
+ close_closeable_connections();
+ conn = NULL;
+ UNMOCK(control_event_bootstrap_problem);
+
+ done:
+ UNMOCK(connection_write_to_buf_impl_);
+ UNMOCK(crypto_rand);
+ if (conn)
+ connection_free_(TO_CONN(conn));
+#undef CONTAINS
+#undef WRITE
+}
+
+struct testcase_t extorport_tests[] = {
+ { "id_map", test_ext_or_id_map, TT_FORK, NULL, NULL },
+ { "write_command", test_ext_or_write_command, TT_FORK, NULL, NULL },
+ { "init_auth", test_ext_or_init_auth, TT_FORK, NULL, NULL },
+ { "cookie_auth", test_ext_or_cookie_auth, TT_FORK, NULL, NULL },
+ { "cookie_auth_testvec", test_ext_or_cookie_auth_testvec, TT_FORK,
+ NULL, NULL },
+ { "handshake", test_ext_or_handshake, TT_FORK, NULL, NULL },
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_hs.c b/src/test/test_hs.c
new file mode 100644
index 000000000..99ef7dd57
--- /dev/null
+++ b/src/test/test_hs.c
@@ -0,0 +1,129 @@
+/* Copyright (c) 2007-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file test_hs.c
+ * \brief Unit tests for hidden service.
+ **/
+
+#define CONTROL_PRIVATE
+#include "or.h"
+#include "test.h"
+#include "control.h"
+
+/* mock ID digest and longname for node that's in nodelist */
+#define HSDIR_EXIST_ID "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" \
+ "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+#define STR_HSDIR_EXIST_LONGNAME \
+ "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=TestDir"
+/* mock ID digest and longname for node that's not in nodelist */
+#define HSDIR_NONE_EXIST_ID "\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB" \
+ "\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB\xBB"
+#define STR_HSDIR_NONE_EXIST_LONGNAME \
+ "$BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
+
+/* Helper global variable for hidden service descriptor event test.
+ * It's used as a pointer to dynamically created message buffer in
+ * send_control_event_string_replacement function, which mocks
+ * send_control_event_string function.
+ *
+ * Always free it after use! */
+static char *received_msg = NULL;
+
+/** Mock function for send_control_event_string
+ */
+static void
+send_control_event_string_replacement(uint16_t event, event_format_t which,
+ const char *msg)
+{
+ (void) event;
+ (void) which;
+ tor_free(received_msg);
+ received_msg = tor_strdup(msg);
+}
+
+/** Mock function for node_describe_longname_by_id, it returns either
+ * STR_HSDIR_EXIST_LONGNAME or STR_HSDIR_NONE_EXIST_LONGNAME
+ */
+static const char *
+node_describe_longname_by_id_replacement(const char *id_digest)
+{
+ if (!strcmp(id_digest, HSDIR_EXIST_ID)) {
+ return STR_HSDIR_EXIST_LONGNAME;
+ } else {
+ return STR_HSDIR_NONE_EXIST_LONGNAME;
+ }
+}
+
+/** Make sure each hidden service descriptor async event generation
+ *
+ * function generates the message in expected format.
+ */
+static void
+test_hs_desc_event(void *arg)
+{
+ #define STR_HS_ADDR "ajhb7kljbiru65qo"
+ #define STR_HS_ID "b3oeducbhjmbqmgw2i3jtz4fekkrinwj"
+
+ rend_data_t rend_query;
+ const char *expected_msg;
+
+ (void) arg;
+ MOCK(send_control_event_string,
+ send_control_event_string_replacement);
+ MOCK(node_describe_longname_by_id,
+ node_describe_longname_by_id_replacement);
+
+ /* setup rend_query struct */
+ strncpy(rend_query.onion_address, STR_HS_ADDR,
+ REND_SERVICE_ID_LEN_BASE32+1);
+ rend_query.auth_type = 0;
+
+ /* test request event */
+ control_event_hs_descriptor_requested(&rend_query, HSDIR_EXIST_ID,
+ STR_HS_ID);
+ expected_msg = "650 HS_DESC REQUESTED "STR_HS_ADDR" NO_AUTH "\
+ STR_HSDIR_EXIST_LONGNAME" "STR_HS_ID"\r\n";
+ test_assert(received_msg);
+ test_streq(received_msg, expected_msg);
+ tor_free(received_msg);
+
+ /* test received event */
+ rend_query.auth_type = 1;
+ control_event_hs_descriptor_received(&rend_query, HSDIR_EXIST_ID);
+ expected_msg = "650 HS_DESC RECEIVED "STR_HS_ADDR" BASIC_AUTH "\
+ STR_HSDIR_EXIST_LONGNAME"\r\n";
+ test_assert(received_msg);
+ test_streq(received_msg, expected_msg);
+ tor_free(received_msg);
+
+ /* test failed event */
+ rend_query.auth_type = 2;
+ control_event_hs_descriptor_failed(&rend_query, HSDIR_NONE_EXIST_ID);
+ expected_msg = "650 HS_DESC FAILED "STR_HS_ADDR" STEALTH_AUTH "\
+ STR_HSDIR_NONE_EXIST_LONGNAME"\r\n";
+ test_assert(received_msg);
+ test_streq(received_msg, expected_msg);
+ tor_free(received_msg);
+
+ /* test invalid auth type */
+ rend_query.auth_type = 999;
+ control_event_hs_descriptor_failed(&rend_query, HSDIR_EXIST_ID);
+ expected_msg = "650 HS_DESC FAILED "STR_HS_ADDR" UNKNOWN "\
+ STR_HSDIR_EXIST_LONGNAME"\r\n";
+ test_assert(received_msg);
+ test_streq(received_msg, expected_msg);
+ tor_free(received_msg);
+
+ done:
+ UNMOCK(send_control_event_string);
+ UNMOCK(node_describe_longname_by_id);
+ tor_free(received_msg);
+}
+
+struct testcase_t hs_tests[] = {
+ { "hs_desc_event", test_hs_desc_event, TT_FORK,
+ NULL, NULL },
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_logging.c b/src/test/test_logging.c
new file mode 100644
index 000000000..7e558f83b
--- /dev/null
+++ b/src/test/test_logging.c
@@ -0,0 +1,135 @@
+/* Copyright (c) 2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+#include "or.h"
+#include "torlog.h"
+#include "test.h"
+
+static void
+dummy_cb_fn(int severity, uint32_t domain, const char *msg)
+{
+ (void)severity; (void)domain; (void)msg;
+}
+
+static void
+test_get_sigsafe_err_fds(void *arg)
+{
+ const int *fds;
+ int n;
+ log_severity_list_t include_bug, no_bug, no_bug2;
+ (void) arg;
+ init_logging();
+
+ n = tor_log_get_sigsafe_err_fds(&fds);
+ tt_int_op(n, ==, 1);
+ tt_int_op(fds[0], ==, STDERR_FILENO);
+
+ set_log_severity_config(LOG_WARN, LOG_ERR, &include_bug);
+ set_log_severity_config(LOG_WARN, LOG_ERR, &no_bug);
+ no_bug.masks[0] &= ~(LD_BUG|LD_GENERAL);
+ set_log_severity_config(LOG_INFO, LOG_NOTICE, &no_bug2);
+
+ /* Add some logs; make sure the output is as expected. */
+ mark_logs_temp();
+ add_stream_log(&include_bug, "dummy-1", 3);
+ add_stream_log(&no_bug, "dummy-2", 4);
+ add_stream_log(&no_bug2, "dummy-3", 5);
+ add_callback_log(&include_bug, dummy_cb_fn);
+ close_temp_logs();
+ tor_log_update_sigsafe_err_fds();
+
+ n = tor_log_get_sigsafe_err_fds(&fds);
+ tt_int_op(n, ==, 2);
+ tt_int_op(fds[0], ==, STDERR_FILENO);
+ tt_int_op(fds[1], ==, 3);
+
+ /* Allow STDOUT to replace STDERR. */
+ add_stream_log(&include_bug, "dummy-4", STDOUT_FILENO);
+ tor_log_update_sigsafe_err_fds();
+ n = tor_log_get_sigsafe_err_fds(&fds);
+ tt_int_op(n, ==, 2);
+ tt_int_op(fds[0], ==, 3);
+ tt_int_op(fds[1], ==, STDOUT_FILENO);
+
+ /* But don't allow it to replace explicit STDERR. */
+ add_stream_log(&include_bug, "dummy-5", STDERR_FILENO);
+ tor_log_update_sigsafe_err_fds();
+ n = tor_log_get_sigsafe_err_fds(&fds);
+ tt_int_op(n, ==, 3);
+ tt_int_op(fds[0], ==, STDERR_FILENO);
+ tt_int_op(fds[1], ==, STDOUT_FILENO);
+ tt_int_op(fds[2], ==, 3);
+
+ /* Don't overflow the array. */
+ {
+ int i;
+ for (i=5; i<20; ++i) {
+ add_stream_log(&include_bug, "x-dummy", i);
+ }
+ }
+ tor_log_update_sigsafe_err_fds();
+ n = tor_log_get_sigsafe_err_fds(&fds);
+ tt_int_op(n, ==, 8);
+
+ done:
+ ;
+}
+
+static void
+test_sigsafe_err(void *arg)
+{
+ const char *fn=get_fname("sigsafe_err_log");
+ char *content=NULL;
+ log_severity_list_t include_bug;
+ smartlist_t *lines = smartlist_new();
+ (void)arg;
+
+ set_log_severity_config(LOG_WARN, LOG_ERR, &include_bug);
+
+ init_logging();
+ mark_logs_temp();
+ add_file_log(&include_bug, fn);
+ tor_log_update_sigsafe_err_fds();
+ close_temp_logs();
+
+ close(STDERR_FILENO);
+ log_err(LD_BUG, "Say, this isn't too cool.");
+ tor_log_err_sigsafe("Minimal.\n", NULL);
+
+ set_log_time_granularity(100*1000);
+ tor_log_err_sigsafe("Testing any ",
+ "attempt to manually log ",
+ "from a signal.\n",
+ NULL);
+ mark_logs_temp();
+ close_temp_logs();
+ close(STDERR_FILENO);
+ content = read_file_to_str(fn, 0, NULL);
+
+ tt_assert(content != NULL);
+ tor_split_lines(lines, content, (int)strlen(content));
+ tt_int_op(smartlist_len(lines), >=, 5);
+
+ if (strstr(smartlist_get(lines, 0), "opening new log file"))
+ smartlist_del_keeporder(lines, 0);
+ tt_assert(strstr(smartlist_get(lines, 0), "Say, this isn't too cool"));
+ /* Next line is blank. */
+ tt_assert(!strcmpstart(smartlist_get(lines, 1), "=============="));
+ tt_assert(!strcmpstart(smartlist_get(lines, 2), "Minimal."));
+ /* Next line is blank. */
+ tt_assert(!strcmpstart(smartlist_get(lines, 3), "=============="));
+ tt_str_op(smartlist_get(lines, 4), ==,
+ "Testing any attempt to manually log from a signal.");
+
+ done:
+ tor_free(content);
+ smartlist_free(lines);
+}
+
+struct testcase_t logging_tests[] = {
+ { "sigsafe_err_fds", test_get_sigsafe_err_fds, TT_FORK, NULL, NULL },
+ { "sigsafe_err", test_sigsafe_err, TT_FORK, NULL, NULL },
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_microdesc.c b/src/test/test_microdesc.c
index 53a03a48a..78f4823b8 100644
--- a/src/test/test_microdesc.c
+++ b/src/test/test_microdesc.c
@@ -5,7 +5,10 @@
#include "or.h"
#include "config.h"
+#include "dirvote.h"
#include "microdesc.h"
+#include "routerlist.h"
+#include "routerparse.h"
#include "test.h"
@@ -261,6 +264,7 @@ test_md_cache_broken(void *data)
options = get_options_mutable();
tt_assert(options);
+ tor_free(options->DataDirectory);
options->DataDirectory = tor_strdup(get_fname("md_datadir_test2"));
#ifdef _WIN32
@@ -284,9 +288,113 @@ test_md_cache_broken(void *data)
microdesc_free_all();
}
+/* Generated by chutney. */
+static const char test_ri[] =
+ "router test005r 127.0.0.1 5005 0 7005\n"
+ "platform Tor 0.2.5.4-alpha-dev on Linux\n"
+ "protocols Link 1 2 Circuit 1\n"
+ "published 2014-05-06 22:57:55\n"
+ "fingerprint 09DE 3BA2 48C2 1C3F 3760 6CD3 8460 43A6 D5EC F59E\n"
+ "uptime 0\n"
+ "bandwidth 1073741824 1073741824 0\n"
+ "extra-info-digest 361F9428F9FA4DD854C03DDBCC159D0D9FA996C9\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBANBJz8Vldl12aFeSMPLiA4nOetLDN0oxU8bB1SDhO7Uu2zdWYVYAF5J0\n"
+ "st7WvrVy/jA9v/fsezNAPskBanecHRSkdMTpkcgRPMHE7CTGEwIy1Yp1X4bPgDlC\n"
+ "VCnbs5Pcts5HnWEYNK7qHDAUn+IlmjOO+pTUY8uyq+GQVz6H9wFlAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBANbGUC4802Ke6C3nOVxN0U0HhIRrs32cQFEL4v+UUMJPgjbistHBvOax\n"
+ "CWVR/sMXM2kKJeGThJ9ZUs2p9dDG4WHPUXgkMqzTTEeeFa7pQKU0brgbmLaJq0Pi\n"
+ "mxmqC5RkTHa5bQvq6QlSFprAEoovV27cWqBM9jVdV9hyc//6kwPzAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "hidden-service-dir\n"
+ "ntor-onion-key Gg73xH7+kTfT6bi1uNVx9gwQdQas9pROIfmc4NpAdC4=\n"
+ "reject *:25\n"
+ "reject *:119\n"
+ "reject *:135-139\n"
+ "reject *:445\n"
+ "reject *:563\n"
+ "reject *:1214\n"
+ "reject *:4661-4666\n"
+ "reject *:6346-6429\n"
+ "reject *:6699\n"
+ "reject *:6881-6999\n"
+ "accept *:*\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "ImzX5PF2vRCrG1YzGToyjoxYhgh1vtHEDjmP+tIS/iil1DSnHZNpHSuHp0L1jE9S\n"
+ "yZyrtKaqpBE/aecAM3j4CWCn/ipnAAQkHcyRLin1bYvqBtRzyopVCRlUhF+uWrLq\n"
+ "t0xkIE39ss/EwmQr7iIgkdVH4oRIMsjYnFFJBG26nYY=\n"
+ "-----END SIGNATURE-----\n";
+
+static const char test_md_8[] =
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBANBJz8Vldl12aFeSMPLiA4nOetLDN0oxU8bB1SDhO7Uu2zdWYVYAF5J0\n"
+ "st7WvrVy/jA9v/fsezNAPskBanecHRSkdMTpkcgRPMHE7CTGEwIy1Yp1X4bPgDlC\n"
+ "VCnbs5Pcts5HnWEYNK7qHDAUn+IlmjOO+pTUY8uyq+GQVz6H9wFlAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999\n";
+
+static const char test_md_16[] =
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBANBJz8Vldl12aFeSMPLiA4nOetLDN0oxU8bB1SDhO7Uu2zdWYVYAF5J0\n"
+ "st7WvrVy/jA9v/fsezNAPskBanecHRSkdMTpkcgRPMHE7CTGEwIy1Yp1X4bPgDlC\n"
+ "VCnbs5Pcts5HnWEYNK7qHDAUn+IlmjOO+pTUY8uyq+GQVz6H9wFlAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key Gg73xH7+kTfT6bi1uNVx9gwQdQas9pROIfmc4NpAdC4=\n"
+ "p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999\n";
+
+static const char test_md_18[] =
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBANBJz8Vldl12aFeSMPLiA4nOetLDN0oxU8bB1SDhO7Uu2zdWYVYAF5J0\n"
+ "st7WvrVy/jA9v/fsezNAPskBanecHRSkdMTpkcgRPMHE7CTGEwIy1Yp1X4bPgDlC\n"
+ "VCnbs5Pcts5HnWEYNK7qHDAUn+IlmjOO+pTUY8uyq+GQVz6H9wFlAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key Gg73xH7+kTfT6bi1uNVx9gwQdQas9pROIfmc4NpAdC4=\n"
+ "p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999\n"
+ "id rsa1024 Cd47okjCHD83YGzThGBDptXs9Z4\n";
+
+static void
+test_md_generate(void *arg)
+{
+ routerinfo_t *ri;
+ microdesc_t *md = NULL;
+ (void)arg;
+
+ ri = router_parse_entry_from_string(test_ri, NULL, 0, 0, NULL);
+ tt_assert(ri);
+ md = dirvote_create_microdescriptor(ri, 8);
+ tt_str_op(md->body, ==, test_md_8);
+
+ /* XXXX test family lines. */
+ /* XXXX test method 14 for A lines. */
+ /* XXXX test method 15 for P6 lines. */
+
+ microdesc_free(md);
+ md = NULL;
+ md = dirvote_create_microdescriptor(ri, 16);
+ tt_str_op(md->body, ==, test_md_16);
+
+ microdesc_free(md);
+ md = NULL;
+ md = dirvote_create_microdescriptor(ri, 18);
+ tt_str_op(md->body, ==, test_md_18);
+
+ done:
+ microdesc_free(md);
+ routerinfo_free(ri);
+}
+
struct testcase_t microdesc_tests[] = {
{ "cache", test_md_cache, TT_FORK, NULL, NULL },
{ "broken_cache", test_md_cache_broken, TT_FORK, NULL, NULL },
+ { "generate", test_md_generate, 0, NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_nodelist.c b/src/test/test_nodelist.c
new file mode 100644
index 000000000..600e6a89d
--- /dev/null
+++ b/src/test/test_nodelist.c
@@ -0,0 +1,71 @@
+/* Copyright (c) 2007-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file test_nodelist.c
+ * \brief Unit tests for nodelist related functions.
+ **/
+
+#include "or.h"
+#include "nodelist.h"
+#include "test.h"
+
+/** Tese the case when node_get_by_id() returns NULL,
+ * node_get_verbose_nickname_by_id should return the base 16 encoding
+ * of the id.
+ */
+static void
+test_nodelist_node_get_verbose_nickname_by_id_null_node(void *arg)
+{
+ char vname[MAX_VERBOSE_NICKNAME_LEN+1];
+ const char ID[] = "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+ "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA";
+ (void) arg;
+
+ /* make sure node_get_by_id returns NULL */
+ test_assert(!node_get_by_id(ID));
+ node_get_verbose_nickname_by_id(ID, vname);
+ test_streq(vname, "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
+ done:
+ return;
+}
+
+/** For routers without named flag, get_verbose_nickname should return
+ * "Fingerprint~Nickname"
+ */
+static void
+test_nodelist_node_get_verbose_nickname_not_named(void *arg)
+{
+ node_t mock_node;
+ routerstatus_t mock_rs;
+
+ char vname[MAX_VERBOSE_NICKNAME_LEN+1];
+
+ (void) arg;
+
+ memset(&mock_node, 0, sizeof(node_t));
+ memset(&mock_rs, 0, sizeof(routerstatus_t));
+
+ /* verbose nickname should use ~ instead of = for unnamed routers */
+ strlcpy(mock_rs.nickname, "TestOR", sizeof(mock_rs.nickname));
+ mock_node.rs = &mock_rs;
+ memcpy(mock_node.identity,
+ "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+ "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA",
+ DIGEST_LEN);
+ node_get_verbose_nickname(&mock_node, vname);
+ test_streq(vname, "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA~TestOR");
+
+ done:
+ return;
+}
+
+#define NODE(name, flags) \
+ { #name, test_nodelist_##name, (flags), NULL, NULL }
+
+struct testcase_t nodelist_tests[] = {
+ NODE(node_get_verbose_nickname_by_id_null_node, TT_FORK),
+ NODE(node_get_verbose_nickname_not_named, TT_FORK),
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_oom.c b/src/test/test_oom.c
new file mode 100644
index 000000000..32f4803bb
--- /dev/null
+++ b/src/test/test_oom.c
@@ -0,0 +1,372 @@
+/* Copyright (c) 2014, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/* Unit tests for OOM handling logic */
+
+#define RELAY_PRIVATE
+#define BUFFERS_PRIVATE
+#define CIRCUITLIST_PRIVATE
+#define CONNECTION_PRIVATE
+#include "or.h"
+#include "buffers.h"
+#include "circuitlist.h"
+#include "compat_libevent.h"
+#include "connection.h"
+#include "config.h"
+#ifdef ENABLE_MEMPOOLS
+#include "mempool.h"
+#endif
+#include "relay.h"
+#include "test.h"
+
+/* small replacement mock for circuit_mark_for_close_ to avoid doing all
+ * the other bookkeeping that comes with marking circuits. */
+static void
+circuit_mark_for_close_dummy_(circuit_t *circ, int reason, int line,
+ const char *file)
+{
+ (void) reason;
+ if (circ->marked_for_close) {
+ TT_FAIL(("Circuit already marked for close at %s:%d, but we are marking "
+ "it again at %s:%d",
+ circ->marked_for_close_file, (int)circ->marked_for_close,
+ file, line));
+ }
+
+ circ->marked_for_close = line;
+ circ->marked_for_close_file = file;
+}
+
+static circuit_t *
+dummy_or_circuit_new(int n_p_cells, int n_n_cells)
+{
+ or_circuit_t *circ = or_circuit_new(0, NULL);
+ int i;
+ cell_t cell;
+
+ for (i=0; i < n_p_cells; ++i) {
+ crypto_rand((void*)&cell, sizeof(cell));
+ cell_queue_append_packed_copy(TO_CIRCUIT(circ), &circ->p_chan_cells,
+ 0, &cell, 1, 0);
+ }
+
+ for (i=0; i < n_n_cells; ++i) {
+ crypto_rand((void*)&cell, sizeof(cell));
+ cell_queue_append_packed_copy(TO_CIRCUIT(circ),
+ &TO_CIRCUIT(circ)->n_chan_cells,
+ 1, &cell, 1, 0);
+ }
+
+ TO_CIRCUIT(circ)->purpose = CIRCUIT_PURPOSE_OR;
+ return TO_CIRCUIT(circ);
+}
+
+static circuit_t *
+dummy_origin_circuit_new(int n_cells)
+{
+ origin_circuit_t *circ = origin_circuit_new();
+ int i;
+ cell_t cell;
+
+ for (i=0; i < n_cells; ++i) {
+ crypto_rand((void*)&cell, sizeof(cell));
+ cell_queue_append_packed_copy(TO_CIRCUIT(circ),
+ &TO_CIRCUIT(circ)->n_chan_cells,
+ 1, &cell, 1, 0);
+ }
+
+ TO_CIRCUIT(circ)->purpose = CIRCUIT_PURPOSE_C_GENERAL;
+ return TO_CIRCUIT(circ);
+}
+
+static void
+add_bytes_to_buf(generic_buffer_t *buf, size_t n_bytes)
+{
+ char b[3000];
+
+ while (n_bytes) {
+ size_t this_add = n_bytes > sizeof(b) ? sizeof(b) : n_bytes;
+ crypto_rand(b, this_add);
+ generic_buffer_add(buf, b, this_add);
+ n_bytes -= this_add;
+ }
+}
+
+static edge_connection_t *
+dummy_edge_conn_new(circuit_t *circ,
+ int type, size_t in_bytes, size_t out_bytes)
+{
+ edge_connection_t *conn;
+
+ if (type == CONN_TYPE_EXIT)
+ conn = edge_connection_new(type, AF_INET);
+ else
+ conn = ENTRY_TO_EDGE_CONN(entry_connection_new(type, AF_INET));
+
+ /* We add these bytes directly to the buffers, to avoid all the
+ * edge connection read/write machinery. */
+ add_bytes_to_buf(TO_CONN(conn)->inbuf, in_bytes);
+ add_bytes_to_buf(TO_CONN(conn)->outbuf, out_bytes);
+
+ conn->on_circuit = circ;
+ if (type == CONN_TYPE_EXIT) {
+ or_circuit_t *oc = TO_OR_CIRCUIT(circ);
+ conn->next_stream = oc->n_streams;
+ oc->n_streams = conn;
+ } else {
+ origin_circuit_t *oc = TO_ORIGIN_CIRCUIT(circ);
+ conn->next_stream = oc->p_streams;
+ oc->p_streams = conn;
+ }
+
+ return conn;
+}
+
+/** Run unit tests for buffers.c */
+static void
+test_oom_circbuf(void *arg)
+{
+ or_options_t *options = get_options_mutable();
+ circuit_t *c1 = NULL, *c2 = NULL, *c3 = NULL, *c4 = NULL;
+ struct timeval tv = { 1389631048, 0 };
+
+ (void) arg;
+
+ MOCK(circuit_mark_for_close_, circuit_mark_for_close_dummy_);
+
+#ifdef ENABLE_MEMPOOLS
+ init_cell_pool();
+#endif /* ENABLE_MEMPOOLS */
+
+ /* Far too low for real life. */
+ options->MaxMemInQueues = 256*packed_cell_mem_cost();
+ options->CellStatistics = 0;
+
+ tt_int_op(cell_queues_check_size(), ==, 0); /* We don't start out OOM. */
+ tt_int_op(cell_queues_get_total_allocation(), ==, 0);
+ tt_int_op(buf_get_total_allocation(), ==, 0);
+
+ /* Now we're going to fake up some circuits and get them added to the global
+ circuit list. */
+ tv.tv_usec = 0;
+ tor_gettimeofday_cache_set(&tv);
+ c1 = dummy_origin_circuit_new(30);
+ tv.tv_usec = 10*1000;
+ tor_gettimeofday_cache_set(&tv);
+ c2 = dummy_or_circuit_new(20, 20);
+
+#ifdef ENABLE_MEMPOOLS
+ tt_int_op(packed_cell_mem_cost(), ==,
+ sizeof(packed_cell_t) + MP_POOL_ITEM_OVERHEAD);
+#else
+ tt_int_op(packed_cell_mem_cost(), ==,
+ sizeof(packed_cell_t));
+#endif /* ENABLE_MEMPOOLS */
+ tt_int_op(cell_queues_get_total_allocation(), ==,
+ packed_cell_mem_cost() * 70);
+ tt_int_op(cell_queues_check_size(), ==, 0); /* We are still not OOM */
+
+ tv.tv_usec = 20*1000;
+ tor_gettimeofday_cache_set(&tv);
+ c3 = dummy_or_circuit_new(100, 85);
+ tt_int_op(cell_queues_check_size(), ==, 0); /* We are still not OOM */
+ tt_int_op(cell_queues_get_total_allocation(), ==,
+ packed_cell_mem_cost() * 255);
+
+ tv.tv_usec = 30*1000;
+ tor_gettimeofday_cache_set(&tv);
+ /* Adding this cell will trigger our OOM handler. */
+ c4 = dummy_or_circuit_new(2, 0);
+
+ tt_int_op(cell_queues_get_total_allocation(), ==,
+ packed_cell_mem_cost() * 257);
+
+ tt_int_op(cell_queues_check_size(), ==, 1); /* We are now OOM */
+
+ tt_assert(c1->marked_for_close);
+ tt_assert(! c2->marked_for_close);
+ tt_assert(! c3->marked_for_close);
+ tt_assert(! c4->marked_for_close);
+
+ tt_int_op(cell_queues_get_total_allocation(), ==,
+ packed_cell_mem_cost() * (257 - 30));
+
+ circuit_free(c1);
+ tv.tv_usec = 0;
+ tor_gettimeofday_cache_set(&tv); /* go back in time */
+ c1 = dummy_or_circuit_new(90, 0);
+
+ tv.tv_usec = 40*1000; /* go back to the future */
+ tor_gettimeofday_cache_set(&tv);
+
+ tt_int_op(cell_queues_check_size(), ==, 1); /* We are now OOM */
+
+ tt_assert(c1->marked_for_close);
+ tt_assert(! c2->marked_for_close);
+ tt_assert(! c3->marked_for_close);
+ tt_assert(! c4->marked_for_close);
+
+ tt_int_op(cell_queues_get_total_allocation(), ==,
+ packed_cell_mem_cost() * (257 - 30));
+
+ done:
+ circuit_free(c1);
+ circuit_free(c2);
+ circuit_free(c3);
+ circuit_free(c4);
+
+ UNMOCK(circuit_mark_for_close_);
+}
+
+/** Run unit tests for buffers.c */
+static void
+test_oom_streambuf(void *arg)
+{
+ or_options_t *options = get_options_mutable();
+ circuit_t *c1 = NULL, *c2 = NULL, *c3 = NULL, *c4 = NULL, *c5 = NULL;
+ struct timeval tv = { 1389641159, 0 };
+ uint32_t tvms;
+ int i;
+ smartlist_t *edgeconns = smartlist_new();
+
+ (void) arg;
+
+ MOCK(circuit_mark_for_close_, circuit_mark_for_close_dummy_);
+
+#ifdef ENABLE_MEMPOOLS
+ init_cell_pool();
+#endif /* ENABLE_MEMPOOLS */
+
+ /* Far too low for real life. */
+ options->MaxMemInQueues = 81*packed_cell_mem_cost() + 4096 * 34;
+ options->CellStatistics = 0;
+
+ tt_int_op(cell_queues_check_size(), ==, 0); /* We don't start out OOM. */
+ tt_int_op(cell_queues_get_total_allocation(), ==, 0);
+ tt_int_op(buf_get_total_allocation(), ==, 0);
+
+ /* Start all circuits with a bit of data queued in cells */
+ tv.tv_usec = 500*1000; /* go halfway into the second. */
+ tor_gettimeofday_cache_set(&tv);
+ c1 = dummy_or_circuit_new(10,10);
+ tv.tv_usec = 510*1000;
+ tor_gettimeofday_cache_set(&tv);
+ c2 = dummy_origin_circuit_new(20);
+ tv.tv_usec = 520*1000;
+ tor_gettimeofday_cache_set(&tv);
+ c3 = dummy_or_circuit_new(20,20);
+ tv.tv_usec = 530*1000;
+ tor_gettimeofday_cache_set(&tv);
+ c4 = dummy_or_circuit_new(0,0);
+ tt_int_op(cell_queues_get_total_allocation(), ==,
+ packed_cell_mem_cost() * 80);
+
+ tv.tv_usec = 600*1000;
+ tor_gettimeofday_cache_set(&tv);
+
+ /* Add some connections to c1...c4. */
+ for (i = 0; i < 4; ++i) {
+ edge_connection_t *ec;
+ /* link it to a circuit */
+ tv.tv_usec += 10*1000;
+ tor_gettimeofday_cache_set(&tv);
+ ec = dummy_edge_conn_new(c1, CONN_TYPE_EXIT, 1000, 1000);
+ tt_assert(ec);
+ smartlist_add(edgeconns, ec);
+ tv.tv_usec += 10*1000;
+ tor_gettimeofday_cache_set(&tv);
+ ec = dummy_edge_conn_new(c2, CONN_TYPE_AP, 1000, 1000);
+ tt_assert(ec);
+ smartlist_add(edgeconns, ec);
+ tv.tv_usec += 10*1000;
+ tor_gettimeofday_cache_set(&tv);
+ ec = dummy_edge_conn_new(c4, CONN_TYPE_EXIT, 1000, 1000); /* Yes, 4 twice*/
+ tt_assert(ec);
+ smartlist_add(edgeconns, ec);
+ tv.tv_usec += 10*1000;
+ tor_gettimeofday_cache_set(&tv);
+ ec = dummy_edge_conn_new(c4, CONN_TYPE_EXIT, 1000, 1000);
+ smartlist_add(edgeconns, ec);
+ tt_assert(ec);
+ }
+
+ tv.tv_sec += 1;
+ tv.tv_usec = 0;
+ tvms = (uint32_t) tv_to_msec(&tv);
+
+ tt_int_op(circuit_max_queued_cell_age(c1, tvms), ==, 500);
+ tt_int_op(circuit_max_queued_cell_age(c2, tvms), ==, 490);
+ tt_int_op(circuit_max_queued_cell_age(c3, tvms), ==, 480);
+ tt_int_op(circuit_max_queued_cell_age(c4, tvms), ==, 0);
+
+ tt_int_op(circuit_max_queued_data_age(c1, tvms), ==, 390);
+ tt_int_op(circuit_max_queued_data_age(c2, tvms), ==, 380);
+ tt_int_op(circuit_max_queued_data_age(c3, tvms), ==, 0);
+ tt_int_op(circuit_max_queued_data_age(c4, tvms), ==, 370);
+
+ tt_int_op(circuit_max_queued_item_age(c1, tvms), ==, 500);
+ tt_int_op(circuit_max_queued_item_age(c2, tvms), ==, 490);
+ tt_int_op(circuit_max_queued_item_age(c3, tvms), ==, 480);
+ tt_int_op(circuit_max_queued_item_age(c4, tvms), ==, 370);
+
+ tt_int_op(cell_queues_get_total_allocation(), ==,
+ packed_cell_mem_cost() * 80);
+ tt_int_op(buf_get_total_allocation(), ==, 4096*16*2);
+
+ /* Now give c4 a very old buffer of modest size */
+ {
+ edge_connection_t *ec;
+ tv.tv_sec -= 1;
+ tv.tv_usec = 0;
+ tor_gettimeofday_cache_set(&tv);
+ ec = dummy_edge_conn_new(c4, CONN_TYPE_EXIT, 1000, 1000);
+ tt_assert(ec);
+ smartlist_add(edgeconns, ec);
+ }
+ tt_int_op(buf_get_total_allocation(), ==, 4096*17*2);
+ tt_int_op(circuit_max_queued_item_age(c4, tvms), ==, 1000);
+
+ tt_int_op(cell_queues_check_size(), ==, 0);
+
+ /* And run over the limit. */
+ tv.tv_usec = 800*1000;
+ tor_gettimeofday_cache_set(&tv);
+ c5 = dummy_or_circuit_new(0,5);
+
+ tt_int_op(cell_queues_get_total_allocation(), ==,
+ packed_cell_mem_cost() * 85);
+ tt_int_op(buf_get_total_allocation(), ==, 4096*17*2);
+
+ tt_int_op(cell_queues_check_size(), ==, 1); /* We are now OOM */
+
+ /* C4 should have died. */
+ tt_assert(! c1->marked_for_close);
+ tt_assert(! c2->marked_for_close);
+ tt_assert(! c3->marked_for_close);
+ tt_assert(c4->marked_for_close);
+ tt_assert(! c5->marked_for_close);
+
+ tt_int_op(cell_queues_get_total_allocation(), ==,
+ packed_cell_mem_cost() * 85);
+ tt_int_op(buf_get_total_allocation(), ==, 4096*8*2);
+
+ done:
+ circuit_free(c1);
+ circuit_free(c2);
+ circuit_free(c3);
+ circuit_free(c4);
+ circuit_free(c5);
+
+ SMARTLIST_FOREACH(edgeconns, edge_connection_t *, ec,
+ connection_free_(TO_CONN(ec)));
+ smartlist_free(edgeconns);
+
+ UNMOCK(circuit_mark_for_close_);
+}
+
+struct testcase_t oom_tests[] = {
+ { "circbuf", test_oom_circbuf, TT_FORK, NULL, NULL },
+ { "streambuf", test_oom_streambuf, TT_FORK, NULL, NULL },
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_options.c b/src/test/test_options.c
new file mode 100644
index 000000000..737f658e2
--- /dev/null
+++ b/src/test/test_options.c
@@ -0,0 +1,170 @@
+/* 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 */
+
+#define CONFIG_PRIVATE
+#include "or.h"
+#include "confparse.h"
+#include "config.h"
+#include "test.h"
+
+typedef struct {
+ int severity;
+ uint32_t domain;
+ char *msg;
+} logmsg_t;
+
+static smartlist_t *messages = NULL;
+
+static void
+log_cback(int severity, uint32_t domain, const char *msg)
+{
+ logmsg_t *x = tor_malloc(sizeof(*x));
+ x->severity = severity;
+ x->domain = domain;
+ x->msg = tor_strdup(msg);
+ if (!messages)
+ messages = smartlist_new();
+ smartlist_add(messages, x);
+}
+
+static void
+setup_log_callback(void)
+{
+ log_severity_list_t lst;
+ memset(&lst, 0, sizeof(lst));
+ lst.masks[LOG_ERR - LOG_ERR] = ~0;
+ lst.masks[LOG_WARN - LOG_ERR] = ~0;
+ lst.masks[LOG_NOTICE - LOG_ERR] = ~0;
+ add_callback_log(&lst, log_cback);
+}
+
+static char *
+dump_logs(void)
+{
+ smartlist_t *msgs;
+ char *out;
+ if (! messages)
+ return tor_strdup("");
+ msgs = smartlist_new();
+ SMARTLIST_FOREACH_BEGIN(messages, logmsg_t *, x) {
+ smartlist_add_asprintf(msgs, "[%s] %s",
+ log_level_to_string(x->severity), x->msg);
+ } SMARTLIST_FOREACH_END(x);
+ out = smartlist_join_strings(msgs, "", 0, NULL);
+ SMARTLIST_FOREACH(msgs, char *, cp, tor_free(cp));
+ smartlist_free(msgs);
+ return out;
+}
+
+static void
+clear_log_messages(void)
+{
+ if (!messages)
+ return;
+ SMARTLIST_FOREACH(messages, logmsg_t *, m,
+ { tor_free(m->msg); tor_free(m); });
+ smartlist_free(messages);
+ messages = NULL;
+}
+
+static void
+test_options_validate_impl(const char *configuration,
+ const char *expect_errmsg,
+ int expect_log_severity,
+ const char *expect_log)
+{
+ or_options_t *opt = options_new();
+ or_options_t *dflt;
+ config_line_t *cl=NULL;
+ char *msg=NULL;
+ int r;
+ opt->command = CMD_RUN_TOR;
+ options_init(opt);
+
+ dflt = config_dup(&options_format, opt);
+ clear_log_messages();
+
+ r = config_get_lines(configuration, &cl, 1);
+ tt_int_op(r, ==, 0);
+
+ r = config_assign(&options_format, opt, cl, 0, 0, &msg);
+ tt_int_op(r, ==, 0);
+
+ r = options_validate(NULL, opt, dflt, 0, &msg);
+ if (expect_errmsg && !msg) {
+ TT_DIE(("Expected error message <%s> from <%s>, but got none.",
+ expect_errmsg, configuration));
+ } else if (expect_errmsg && !strstr(msg, expect_errmsg)) {
+ TT_DIE(("Expected error message <%s> from <%s>, but got <%s>.",
+ expect_errmsg, configuration, msg));
+ } else if (!expect_errmsg && msg) {
+ TT_DIE(("Expected no error message from <%s> but got <%s>.",
+ configuration, msg));
+ }
+ tt_int_op((r == 0), ==, (msg == NULL));
+
+ if (expect_log) {
+ int found = 0;
+ if (messages) {
+ SMARTLIST_FOREACH_BEGIN(messages, logmsg_t *, m) {
+ if (m->severity == expect_log_severity &&
+ strstr(m->msg, expect_log)) {
+ found = 1;
+ break;
+ }
+ } SMARTLIST_FOREACH_END(m);
+ }
+ if (!found) {
+ tor_free(msg);
+ msg = dump_logs();
+ TT_DIE(("Expected log message [%s] %s from <%s>, but got <%s>.",
+ log_level_to_string(expect_log_severity), expect_log,
+ configuration, msg));
+ }
+ }
+
+ done:
+ config_free_lines(cl);
+ or_options_free(opt);
+ or_options_free(dflt);
+ tor_free(msg);
+ clear_log_messages();
+}
+
+#define WANT_ERR(config, msg) \
+ test_options_validate_impl((config), (msg), 0, NULL)
+#define WANT_LOG(config, severity, msg) \
+ test_options_validate_impl((config), NULL, (severity), (msg))
+#define WANT_ERR_LOG(config, msg, severity, logmsg) \
+ test_options_validate_impl((config), (msg), (severity), (logmsg))
+#define OK(config) \
+ test_options_validate_impl((config), NULL, 0, NULL)
+
+static void
+test_options_validate(void *arg)
+{
+ (void)arg;
+ setup_log_callback();
+
+ WANT_ERR("ExtORPort 500000", "Invalid ExtORPort");
+
+ WANT_ERR_LOG("ServerTransportOptions trebuchet",
+ "ServerTransportOptions did not parse",
+ LOG_WARN, "Too few arguments");
+ OK("ServerTransportOptions trebuchet sling=snappy");
+ OK("ServerTransportOptions trebuchet sling=");
+ WANT_ERR_LOG("ServerTransportOptions trebuchet slingsnappy",
+ "ServerTransportOptions did not parse",
+ LOG_WARN, "\"slingsnappy\" is not a k=v");
+
+ clear_log_messages();
+ return;
+}
+
+struct testcase_t options_tests[] = {
+ { "validate", test_options_validate, TT_FORK, NULL, NULL },
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_policy.c b/src/test/test_policy.c
new file mode 100644
index 000000000..4cdcd034b
--- /dev/null
+++ b/src/test/test_policy.c
@@ -0,0 +1,437 @@
+/* Copyright (c) 2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "or.h"
+#include "router.h"
+#include "routerparse.h"
+#include "policies.h"
+#include "test.h"
+
+/* Helper: assert that short_policy parses and writes back out as itself,
+ or as <b>expected</b> if that's provided. */
+static void
+test_short_policy_parse(const char *input,
+ const char *expected)
+{
+ short_policy_t *short_policy = NULL;
+ char *out = NULL;
+
+ if (expected == NULL)
+ expected = input;
+
+ short_policy = parse_short_policy(input);
+ tt_assert(short_policy);
+ out = write_short_policy(short_policy);
+ tt_str_op(out, ==, expected);
+
+ done:
+ tor_free(out);
+ short_policy_free(short_policy);
+}
+
+/** Helper: Parse the exit policy string in <b>policy_str</b>, and make sure
+ * that policies_summarize() produces the string <b>expected_summary</b> from
+ * it. */
+static void
+test_policy_summary_helper(const char *policy_str,
+ const char *expected_summary)
+{
+ config_line_t line;
+ smartlist_t *policy = smartlist_new();
+ char *summary = NULL;
+ char *summary_after = NULL;
+ int r;
+ short_policy_t *short_policy = NULL;
+
+ line.key = (char*)"foo";
+ line.value = (char *)policy_str;
+ line.next = NULL;
+
+ r = policies_parse_exit_policy(&line, &policy, 1, 0, 0, 1);
+ test_eq(r, 0);
+ summary = policy_summarize(policy, AF_INET);
+
+ test_assert(summary != NULL);
+ test_streq(summary, expected_summary);
+
+ short_policy = parse_short_policy(summary);
+ tt_assert(short_policy);
+ summary_after = write_short_policy(short_policy);
+ test_streq(summary, summary_after);
+
+ done:
+ tor_free(summary_after);
+ tor_free(summary);
+ if (policy)
+ addr_policy_list_free(policy);
+ short_policy_free(short_policy);
+}
+
+/** Run unit tests for generating summary lines of exit policies */
+static void
+test_policies_general(void *arg)
+{
+ int i;
+ smartlist_t *policy = NULL, *policy2 = NULL, *policy3 = NULL,
+ *policy4 = NULL, *policy5 = NULL, *policy6 = NULL,
+ *policy7 = NULL;
+ addr_policy_t *p;
+ tor_addr_t tar;
+ config_line_t line;
+ smartlist_t *sm = NULL;
+ char *policy_str = NULL;
+ short_policy_t *short_parsed = NULL;
+ (void)arg;
+
+ policy = smartlist_new();
+
+ p = router_parse_addr_policy_item_from_string("reject 192.168.0.0/16:*",-1);
+ test_assert(p != NULL);
+ test_eq(ADDR_POLICY_REJECT, p->policy_type);
+ tor_addr_from_ipv4h(&tar, 0xc0a80000u);
+ test_eq(0, tor_addr_compare(&p->addr, &tar, CMP_EXACT));
+ test_eq(16, p->maskbits);
+ test_eq(1, p->prt_min);
+ test_eq(65535, p->prt_max);
+
+ smartlist_add(policy, p);
+
+ tor_addr_from_ipv4h(&tar, 0x01020304u);
+ test_assert(ADDR_POLICY_ACCEPTED ==
+ compare_tor_addr_to_addr_policy(&tar, 2, policy));
+ tor_addr_make_unspec(&tar);
+ test_assert(ADDR_POLICY_PROBABLY_ACCEPTED ==
+ compare_tor_addr_to_addr_policy(&tar, 2, policy));
+ tor_addr_from_ipv4h(&tar, 0xc0a80102);
+ test_assert(ADDR_POLICY_REJECTED ==
+ compare_tor_addr_to_addr_policy(&tar, 2, policy));
+
+ test_assert(0 == policies_parse_exit_policy(NULL, &policy2, 1, 1, 0, 1));
+ test_assert(policy2);
+
+ policy3 = smartlist_new();
+ p = router_parse_addr_policy_item_from_string("reject *:*",-1);
+ test_assert(p != NULL);
+ smartlist_add(policy3, p);
+ p = router_parse_addr_policy_item_from_string("accept *:*",-1);
+ test_assert(p != NULL);
+ smartlist_add(policy3, p);
+
+ policy4 = smartlist_new();
+ p = router_parse_addr_policy_item_from_string("accept *:443",-1);
+ test_assert(p != NULL);
+ smartlist_add(policy4, p);
+ p = router_parse_addr_policy_item_from_string("accept *:443",-1);
+ test_assert(p != NULL);
+ smartlist_add(policy4, p);
+
+ policy5 = smartlist_new();
+ p = router_parse_addr_policy_item_from_string("reject 0.0.0.0/8:*",-1);
+ test_assert(p != NULL);
+ smartlist_add(policy5, p);
+ p = router_parse_addr_policy_item_from_string("reject 169.254.0.0/16:*",-1);
+ test_assert(p != NULL);
+ smartlist_add(policy5, p);
+ p = router_parse_addr_policy_item_from_string("reject 127.0.0.0/8:*",-1);
+ test_assert(p != NULL);
+ smartlist_add(policy5, p);
+ p = router_parse_addr_policy_item_from_string("reject 192.168.0.0/16:*",-1);
+ test_assert(p != NULL);
+ smartlist_add(policy5, p);
+ p = router_parse_addr_policy_item_from_string("reject 10.0.0.0/8:*",-1);
+ test_assert(p != NULL);
+ smartlist_add(policy5, p);
+ p = router_parse_addr_policy_item_from_string("reject 172.16.0.0/12:*",-1);
+ test_assert(p != NULL);
+ smartlist_add(policy5, p);
+ p = router_parse_addr_policy_item_from_string("reject 80.190.250.90:*",-1);
+ test_assert(p != NULL);
+ smartlist_add(policy5, p);
+ p = router_parse_addr_policy_item_from_string("reject *:1-65534",-1);
+ test_assert(p != NULL);
+ smartlist_add(policy5, p);
+ p = router_parse_addr_policy_item_from_string("reject *:65535",-1);
+ test_assert(p != NULL);
+ smartlist_add(policy5, p);
+ p = router_parse_addr_policy_item_from_string("accept *:1-65535",-1);
+ test_assert(p != NULL);
+ smartlist_add(policy5, p);
+
+ policy6 = smartlist_new();
+ p = router_parse_addr_policy_item_from_string("accept 43.3.0.0/9:*",-1);
+ test_assert(p != NULL);
+ smartlist_add(policy6, p);
+
+ policy7 = smartlist_new();
+ p = router_parse_addr_policy_item_from_string("accept 0.0.0.0/8:*",-1);
+ test_assert(p != NULL);
+ smartlist_add(policy7, p);
+
+ test_assert(!exit_policy_is_general_exit(policy));
+ test_assert(exit_policy_is_general_exit(policy2));
+ test_assert(!exit_policy_is_general_exit(NULL));
+ test_assert(!exit_policy_is_general_exit(policy3));
+ test_assert(!exit_policy_is_general_exit(policy4));
+ test_assert(!exit_policy_is_general_exit(policy5));
+ test_assert(!exit_policy_is_general_exit(policy6));
+ test_assert(!exit_policy_is_general_exit(policy7));
+
+ test_assert(cmp_addr_policies(policy, policy2));
+ test_assert(cmp_addr_policies(policy, NULL));
+ test_assert(!cmp_addr_policies(policy2, policy2));
+ test_assert(!cmp_addr_policies(NULL, NULL));
+
+ test_assert(!policy_is_reject_star(policy2, AF_INET));
+ test_assert(policy_is_reject_star(policy, AF_INET));
+ test_assert(policy_is_reject_star(NULL, AF_INET));
+
+ addr_policy_list_free(policy);
+ policy = NULL;
+
+ /* make sure compacting logic works. */
+ policy = NULL;
+ line.key = (char*)"foo";
+ line.value = (char*)"accept *:80,reject private:*,reject *:*";
+ line.next = NULL;
+ test_assert(0 == policies_parse_exit_policy(&line, &policy, 1, 0, 0, 1));
+ test_assert(policy);
+ //test_streq(policy->string, "accept *:80");
+ //test_streq(policy->next->string, "reject *:*");
+ test_eq(smartlist_len(policy), 4);
+
+ /* test policy summaries */
+ /* check if we properly ignore private IP addresses */
+ test_policy_summary_helper("reject 192.168.0.0/16:*,"
+ "reject 0.0.0.0/8:*,"
+ "reject 10.0.0.0/8:*,"
+ "accept *:10-30,"
+ "accept *:90,"
+ "reject *:*",
+ "accept 10-30,90");
+ /* check all accept policies, and proper counting of rejects */
+ test_policy_summary_helper("reject 11.0.0.0/9:80,"
+ "reject 12.0.0.0/9:80,"
+ "reject 13.0.0.0/9:80,"
+ "reject 14.0.0.0/9:80,"
+ "accept *:*", "accept 1-65535");
+ test_policy_summary_helper("reject 11.0.0.0/9:80,"
+ "reject 12.0.0.0/9:80,"
+ "reject 13.0.0.0/9:80,"
+ "reject 14.0.0.0/9:80,"
+ "reject 15.0.0.0:81,"
+ "accept *:*", "accept 1-65535");
+ test_policy_summary_helper("reject 11.0.0.0/9:80,"
+ "reject 12.0.0.0/9:80,"
+ "reject 13.0.0.0/9:80,"
+ "reject 14.0.0.0/9:80,"
+ "reject 15.0.0.0:80,"
+ "accept *:*",
+ "reject 80");
+ /* no exits */
+ test_policy_summary_helper("accept 11.0.0.0/9:80,"
+ "reject *:*",
+ "reject 1-65535");
+ /* port merging */
+ test_policy_summary_helper("accept *:80,"
+ "accept *:81,"
+ "accept *:100-110,"
+ "accept *:111,"
+ "reject *:*",
+ "accept 80-81,100-111");
+ /* border ports */
+ test_policy_summary_helper("accept *:1,"
+ "accept *:3,"
+ "accept *:65535,"
+ "reject *:*",
+ "accept 1,3,65535");
+ /* holes */
+ test_policy_summary_helper("accept *:1,"
+ "accept *:3,"
+ "accept *:5,"
+ "accept *:7,"
+ "reject *:*",
+ "accept 1,3,5,7");
+ test_policy_summary_helper("reject *:1,"
+ "reject *:3,"
+ "reject *:5,"
+ "reject *:7,"
+ "accept *:*",
+ "reject 1,3,5,7");
+
+ /* Short policies with unrecognized formats should get accepted. */
+ test_short_policy_parse("accept fred,2,3-5", "accept 2,3-5");
+ test_short_policy_parse("accept 2,fred,3", "accept 2,3");
+ test_short_policy_parse("accept 2,fred,3,bob", "accept 2,3");
+ test_short_policy_parse("accept 2,-3,500-600", "accept 2,500-600");
+ /* Short policies with nil entries are accepted too. */
+ test_short_policy_parse("accept 1,,3", "accept 1,3");
+ test_short_policy_parse("accept 100-200,,", "accept 100-200");
+ test_short_policy_parse("reject ,1-10,,,,30-40", "reject 1-10,30-40");
+
+ /* Try parsing various broken short policies */
+#define TT_BAD_SHORT_POLICY(s) \
+ do { \
+ tt_ptr_op(NULL, ==, (short_parsed = parse_short_policy((s)))); \
+ } while (0)
+ TT_BAD_SHORT_POLICY("accept 200-199");
+ TT_BAD_SHORT_POLICY("");
+ TT_BAD_SHORT_POLICY("rejekt 1,2,3");
+ TT_BAD_SHORT_POLICY("reject ");
+ TT_BAD_SHORT_POLICY("reject");
+ TT_BAD_SHORT_POLICY("rej");
+ TT_BAD_SHORT_POLICY("accept 2,3,100000");
+ TT_BAD_SHORT_POLICY("accept 2,3x,4");
+ TT_BAD_SHORT_POLICY("accept 2,3x,4");
+ TT_BAD_SHORT_POLICY("accept 2-");
+ TT_BAD_SHORT_POLICY("accept 2-x");
+ TT_BAD_SHORT_POLICY("accept 1-,3");
+ TT_BAD_SHORT_POLICY("accept 1-,3");
+
+ /* Test a too-long policy. */
+ {
+ int i;
+ char *policy = NULL;
+ smartlist_t *chunks = smartlist_new();
+ smartlist_add(chunks, tor_strdup("accept "));
+ for (i=1; i<10000; ++i)
+ smartlist_add_asprintf(chunks, "%d,", i);
+ smartlist_add(chunks, tor_strdup("20000"));
+ policy = smartlist_join_strings(chunks, "", 0, NULL);
+ SMARTLIST_FOREACH(chunks, char *, ch, tor_free(ch));
+ smartlist_free(chunks);
+ short_parsed = parse_short_policy(policy);/* shouldn't be accepted */
+ tor_free(policy);
+ tt_ptr_op(NULL, ==, short_parsed);
+ }
+
+ /* truncation ports */
+ sm = smartlist_new();
+ for (i=1; i<2000; i+=2) {
+ char buf[POLICY_BUF_LEN];
+ tor_snprintf(buf, sizeof(buf), "reject *:%d", i);
+ smartlist_add(sm, tor_strdup(buf));
+ }
+ smartlist_add(sm, tor_strdup("accept *:*"));
+ policy_str = smartlist_join_strings(sm, ",", 0, NULL);
+ test_policy_summary_helper( policy_str,
+ "accept 2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,"
+ "46,48,50,52,54,56,58,60,62,64,66,68,70,72,74,76,78,80,82,84,86,88,90,"
+ "92,94,96,98,100,102,104,106,108,110,112,114,116,118,120,122,124,126,128,"
+ "130,132,134,136,138,140,142,144,146,148,150,152,154,156,158,160,162,164,"
+ "166,168,170,172,174,176,178,180,182,184,186,188,190,192,194,196,198,200,"
+ "202,204,206,208,210,212,214,216,218,220,222,224,226,228,230,232,234,236,"
+ "238,240,242,244,246,248,250,252,254,256,258,260,262,264,266,268,270,272,"
+ "274,276,278,280,282,284,286,288,290,292,294,296,298,300,302,304,306,308,"
+ "310,312,314,316,318,320,322,324,326,328,330,332,334,336,338,340,342,344,"
+ "346,348,350,352,354,356,358,360,362,364,366,368,370,372,374,376,378,380,"
+ "382,384,386,388,390,392,394,396,398,400,402,404,406,408,410,412,414,416,"
+ "418,420,422,424,426,428,430,432,434,436,438,440,442,444,446,448,450,452,"
+ "454,456,458,460,462,464,466,468,470,472,474,476,478,480,482,484,486,488,"
+ "490,492,494,496,498,500,502,504,506,508,510,512,514,516,518,520,522");
+
+ done:
+ addr_policy_list_free(policy);
+ addr_policy_list_free(policy2);
+ addr_policy_list_free(policy3);
+ addr_policy_list_free(policy4);
+ addr_policy_list_free(policy5);
+ addr_policy_list_free(policy6);
+ addr_policy_list_free(policy7);
+ tor_free(policy_str);
+ if (sm) {
+ SMARTLIST_FOREACH(sm, char *, s, tor_free(s));
+ smartlist_free(sm);
+ }
+ short_policy_free(short_parsed);
+}
+
+static void
+test_dump_exit_policy_to_string(void *arg)
+{
+ char *ep;
+ addr_policy_t *policy_entry;
+
+ routerinfo_t *ri = tor_malloc_zero(sizeof(routerinfo_t));
+
+ (void)arg;
+
+ ri->policy_is_reject_star = 1;
+ ri->exit_policy = NULL; // expecting "reject *:*"
+ ep = router_dump_exit_policy_to_string(ri,1,1);
+
+ test_streq("reject *:*",ep);
+
+ tor_free(ep);
+
+ ri->exit_policy = smartlist_new();
+ ri->policy_is_reject_star = 0;
+
+ policy_entry = router_parse_addr_policy_item_from_string("accept *:*",-1);
+
+ smartlist_add(ri->exit_policy,policy_entry);
+
+ ep = router_dump_exit_policy_to_string(ri,1,1);
+
+ test_streq("accept *:*",ep);
+
+ tor_free(ep);
+
+ policy_entry = router_parse_addr_policy_item_from_string("reject *:25",-1);
+
+ smartlist_add(ri->exit_policy,policy_entry);
+
+ ep = router_dump_exit_policy_to_string(ri,1,1);
+
+ test_streq("accept *:*\nreject *:25",ep);
+
+ tor_free(ep);
+
+ policy_entry =
+ router_parse_addr_policy_item_from_string("reject 8.8.8.8:*",-1);
+
+ smartlist_add(ri->exit_policy,policy_entry);
+
+ ep = router_dump_exit_policy_to_string(ri,1,1);
+
+ test_streq("accept *:*\nreject *:25\nreject 8.8.8.8:*",ep);
+ tor_free(ep);
+
+ policy_entry =
+ router_parse_addr_policy_item_from_string("reject6 [FC00::]/7:*",-1);
+
+ smartlist_add(ri->exit_policy,policy_entry);
+
+ ep = router_dump_exit_policy_to_string(ri,1,1);
+
+ test_streq("accept *:*\nreject *:25\nreject 8.8.8.8:*\n"
+ "reject6 [fc00::]/7:*",ep);
+ tor_free(ep);
+
+ policy_entry =
+ router_parse_addr_policy_item_from_string("accept6 [c000::]/3:*",-1);
+
+ smartlist_add(ri->exit_policy,policy_entry);
+
+ ep = router_dump_exit_policy_to_string(ri,1,1);
+
+ test_streq("accept *:*\nreject *:25\nreject 8.8.8.8:*\n"
+ "reject6 [fc00::]/7:*\naccept6 [c000::]/3:*",ep);
+
+ done:
+
+ if (ri->exit_policy) {
+ SMARTLIST_FOREACH(ri->exit_policy, addr_policy_t *,
+ entry, addr_policy_free(entry));
+ smartlist_free(ri->exit_policy);
+ }
+ tor_free(ri);
+ tor_free(ep);
+}
+
+struct testcase_t policy_tests[] = {
+ { "router_dump_exit_policy_to_string", test_dump_exit_policy_to_string, 0,
+ NULL, NULL },
+ { "general", test_policies_general, 0, NULL, NULL },
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_pt.c b/src/test/test_pt.c
index 80707f437..f71627df1 100644
--- a/src/test/test_pt.c
+++ b/src/test/test_pt.c
@@ -5,9 +5,17 @@
#include "orconfig.h"
#define PT_PRIVATE
+#define UTIL_PRIVATE
+#define STATEFILE_PRIVATE
+#define CONTROL_PRIVATE
#include "or.h"
+#include "config.h"
+#include "confparse.h"
+#include "control.h"
#include "transports.h"
#include "circuitbuild.h"
+#include "util.h"
+#include "statefile.h"
#include "test.h"
static void
@@ -22,71 +30,163 @@ 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);
+ /* Include some arguments. Good ones. */
+ strlcpy(line,"SMETHOD trebuchet 127.0.0.1:9999 "
+ "ARGS:counterweight=3,sling=snappy",
+ sizeof(line));
+ test_assert(parse_smethod_line(line, mp) == 0);
+ tt_int_op(1, ==, smartlist_len(mp->transports));
+ {
+ const transport_t *transport = smartlist_get(mp->transports, 0);
+ tt_assert(transport);
+ tt_str_op(transport->name, ==, "trebuchet");
+ tt_int_op(transport->port, ==, 9999);
+ tt_str_op(fmt_addr(&transport->addr), ==, "127.0.0.1");
+ tt_str_op(transport->extra_info_args, ==,
+ "counterweight=3,sling=snappy");
+ }
+ 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:
+ reset_mp(mp);
+ smartlist_free(mp->transports);
tor_free(mp);
}
static void
+test_pt_get_transport_options(void *arg)
+{
+ char **execve_args;
+ smartlist_t *transport_list = smartlist_new();
+ managed_proxy_t *mp;
+ or_options_t *options = get_options_mutable();
+ char *opt_str = NULL;
+ config_line_t *cl = NULL;
+ (void)arg;
+
+ execve_args = tor_malloc(sizeof(char*)*2);
+ execve_args[0] = tor_strdup("cheeseshop");
+ execve_args[1] = NULL;
+
+ mp = managed_proxy_create(transport_list, execve_args, 1);
+ tt_ptr_op(mp, !=, NULL);
+ opt_str = get_transport_options_for_server_proxy(mp);
+ tt_ptr_op(opt_str, ==, NULL);
+
+ smartlist_add(mp->transports_to_launch, tor_strdup("gruyere"));
+ smartlist_add(mp->transports_to_launch, tor_strdup("roquefort"));
+ smartlist_add(mp->transports_to_launch, tor_strdup("stnectaire"));
+
+ tt_assert(options);
+
+ cl = tor_malloc_zero(sizeof(config_line_t));
+ cl->value = tor_strdup("gruyere melty=10 hardness=se;ven");
+ options->ServerTransportOptions = cl;
+
+ cl = tor_malloc_zero(sizeof(config_line_t));
+ cl->value = tor_strdup("stnectaire melty=4 hardness=three");
+ cl->next = options->ServerTransportOptions;
+ options->ServerTransportOptions = cl;
+
+ cl = tor_malloc_zero(sizeof(config_line_t));
+ cl->value = tor_strdup("pepperjack melty=12 hardness=five");
+ cl->next = options->ServerTransportOptions;
+ options->ServerTransportOptions = cl;
+
+ opt_str = get_transport_options_for_server_proxy(mp);
+ tt_str_op(opt_str, ==,
+ "gruyere:melty=10;gruyere:hardness=se\\;ven;"
+ "stnectaire:melty=4;stnectaire:hardness=three");
+
+ done:
+ tor_free(opt_str);
+ config_free_lines(cl);
+ managed_proxy_destroy(mp, 0);
+ smartlist_free(transport_list);
+}
+
+static void
test_pt_protocol(void)
{
char line[200];
@@ -99,36 +199,254 @@ 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);
done:
+ reset_mp(mp);
+ smartlist_free(mp->transports);
+ tor_free(mp->argv[0]);
+ tor_free(mp->argv);
+ tor_free(mp);
+}
+
+static void
+test_pt_get_extrainfo_string(void *arg)
+{
+ managed_proxy_t *mp1 = NULL, *mp2 = NULL;
+ char **argv1, **argv2;
+ smartlist_t *t1 = smartlist_new(), *t2 = smartlist_new();
+ int r;
+ char *s = NULL;
+ (void) arg;
+
+ argv1 = tor_malloc_zero(sizeof(char*)*3);
+ argv1[0] = tor_strdup("ewige");
+ argv1[1] = tor_strdup("Blumenkraft");
+ argv1[2] = NULL;
+ argv2 = tor_malloc_zero(sizeof(char*)*4);
+ argv2[0] = tor_strdup("und");
+ argv2[1] = tor_strdup("ewige");
+ argv2[2] = tor_strdup("Schlangenkraft");
+ argv2[3] = NULL;
+
+ mp1 = managed_proxy_create(t1, argv1, 1);
+ mp2 = managed_proxy_create(t2, argv2, 1);
+
+ r = parse_smethod_line("SMETHOD hagbard 127.0.0.1:5555", mp1);
+ tt_int_op(r, ==, 0);
+ r = parse_smethod_line("SMETHOD celine 127.0.0.1:1723 ARGS:card=no-enemy",
+ mp2);
+ tt_int_op(r, ==, 0);
+
+ /* Force these proxies to look "completed" or they won't generate output. */
+ mp1->conf_state = mp2->conf_state = PT_PROTO_COMPLETED;
+
+ s = pt_get_extra_info_descriptor_string();
+ tt_assert(s);
+ tt_str_op(s, ==,
+ "transport hagbard 127.0.0.1:5555\n"
+ "transport celine 127.0.0.1:1723 card=no-enemy\n");
+
+ done:
+ /* XXXX clean up better */
+ smartlist_free(t1);
+ smartlist_free(t2);
+ tor_free(s);
+}
+
+#ifdef _WIN32
+#define STDIN_HANDLE HANDLE
+#else
+#define STDIN_HANDLE FILE
+#endif
+
+static smartlist_t *
+tor_get_lines_from_handle_replacement(STDIN_HANDLE *handle,
+ enum stream_status *stream_status_out)
+{
+ static int times_called = 0;
+ smartlist_t *retval_sl = smartlist_new();
+
+ (void) handle;
+ (void) stream_status_out;
+
+ /* Generate some dummy CMETHOD lines the first 5 times. The 6th
+ time, send 'CMETHODS DONE' to finish configuring the proxy. */
+ if (times_called++ != 5) {
+ smartlist_add_asprintf(retval_sl, "SMETHOD mock%d 127.0.0.1:555%d",
+ times_called, times_called);
+ } else {
+ smartlist_add(retval_sl, tor_strdup("SMETHODS DONE"));
+ }
+
+ return retval_sl;
+}
+
+/* NOP mock */
+static void
+tor_process_handle_destroy_replacement(process_handle_t *process_handle,
+ int also_terminate_process)
+{
+ (void) process_handle;
+ (void) also_terminate_process;
+}
+
+static or_state_t *dummy_state = NULL;
+
+static or_state_t *
+get_or_state_replacement(void)
+{
+ return dummy_state;
+}
+
+static int controlevent_n = 0;
+static uint16_t controlevent_event = 0;
+static smartlist_t *controlevent_msgs = NULL;
+
+static void
+send_control_event_string_replacement(uint16_t event, event_format_t which,
+ const char *msg)
+{
+ (void) which;
+ ++controlevent_n;
+ controlevent_event = event;
+ if (!controlevent_msgs)
+ controlevent_msgs = smartlist_new();
+ smartlist_add(controlevent_msgs, tor_strdup(msg));
+}
+
+/* Test the configure_proxy() function. */
+static void
+test_pt_configure_proxy(void *arg)
+{
+ int i, retval;
+ managed_proxy_t *mp = NULL;
+ (void) arg;
+
+ dummy_state = tor_malloc_zero(sizeof(or_state_t));
+
+ MOCK(tor_get_lines_from_handle,
+ tor_get_lines_from_handle_replacement);
+ MOCK(tor_process_handle_destroy,
+ tor_process_handle_destroy_replacement);
+ MOCK(get_or_state,
+ get_or_state_replacement);
+ MOCK(send_control_event_string,
+ send_control_event_string_replacement);
+
+ control_testing_set_global_event_mask(EVENT_TRANSPORT_LAUNCHED);
+
+ mp = tor_malloc(sizeof(managed_proxy_t));
+ mp->conf_state = PT_PROTO_ACCEPTING_METHODS;
+ mp->transports = smartlist_new();
+ mp->transports_to_launch = smartlist_new();
+ mp->process_handle = tor_malloc_zero(sizeof(process_handle_t));
+ mp->argv = tor_malloc_zero(sizeof(char*)*2);
+ mp->argv[0] = tor_strdup("<testcase>");
+ mp->is_server = 1;
+
+ /* Test the return value of configure_proxy() by calling it some
+ times while it is uninitialized and then finally finalizing its
+ configuration. */
+ for (i = 0 ; i < 5 ; i++) {
+ retval = configure_proxy(mp);
+ /* retval should be zero because proxy hasn't finished configuring yet */
+ test_assert(retval == 0);
+ /* check the number of registered transports */
+ test_assert(smartlist_len(mp->transports) == i+1);
+ /* check that the mp is still waiting for transports */
+ test_assert(mp->conf_state == PT_PROTO_ACCEPTING_METHODS);
+ }
+
+ /* this last configure_proxy() should finalize the proxy configuration. */
+ retval = configure_proxy(mp);
+ /* retval should be 1 since the proxy finished configuring */
+ test_assert(retval == 1);
+ /* check the mp state */
+ test_assert(mp->conf_state == PT_PROTO_COMPLETED);
+
+ tt_int_op(controlevent_n, ==, 5);
+ tt_int_op(controlevent_event, ==, EVENT_TRANSPORT_LAUNCHED);
+ tt_int_op(smartlist_len(controlevent_msgs), ==, 5);
+ smartlist_sort_strings(controlevent_msgs);
+ tt_str_op(smartlist_get(controlevent_msgs, 0), ==,
+ "650 TRANSPORT_LAUNCHED server mock1 127.0.0.1 5551\r\n");
+ tt_str_op(smartlist_get(controlevent_msgs, 1), ==,
+ "650 TRANSPORT_LAUNCHED server mock2 127.0.0.1 5552\r\n");
+ tt_str_op(smartlist_get(controlevent_msgs, 2), ==,
+ "650 TRANSPORT_LAUNCHED server mock3 127.0.0.1 5553\r\n");
+ tt_str_op(smartlist_get(controlevent_msgs, 3), ==,
+ "650 TRANSPORT_LAUNCHED server mock4 127.0.0.1 5554\r\n");
+ tt_str_op(smartlist_get(controlevent_msgs, 4), ==,
+ "650 TRANSPORT_LAUNCHED server mock5 127.0.0.1 5555\r\n");
+
+ { /* check that the transport info were saved properly in the tor state */
+ config_line_t *transport_in_state = NULL;
+ smartlist_t *transport_info_sl = smartlist_new();
+ char *name_of_transport = NULL;
+ char *bindaddr = NULL;
+
+ /* Get the bindaddr for "mock1" and check it against the bindaddr
+ that the mocked tor_get_lines_from_handle() generated. */
+ transport_in_state = get_transport_in_state_by_name("mock1");
+ test_assert(transport_in_state);
+ smartlist_split_string(transport_info_sl, transport_in_state->value,
+ NULL, 0, 0);
+ name_of_transport = smartlist_get(transport_info_sl, 0);
+ bindaddr = smartlist_get(transport_info_sl, 1);
+ tt_str_op(name_of_transport, ==, "mock1");
+ tt_str_op(bindaddr, ==, "127.0.0.1:5551");
+
+ SMARTLIST_FOREACH(transport_info_sl, char *, cp, tor_free(cp));
+ smartlist_free(transport_info_sl);
+ }
+
+ done:
+ or_state_free(dummy_state);
+ UNMOCK(tor_get_lines_from_handle);
+ UNMOCK(tor_process_handle_destroy);
+ UNMOCK(get_or_state);
+ UNMOCK(send_control_event_string);
+ if (controlevent_msgs) {
+ SMARTLIST_FOREACH(controlevent_msgs, char *, cp, tor_free(cp));
+ smartlist_free(controlevent_msgs);
+ controlevent_msgs = NULL;
+ }
+ if (mp->transports) {
+ SMARTLIST_FOREACH(mp->transports, transport_t *, t, transport_free(t));
+ smartlist_free(mp->transports);
+ }
+ smartlist_free(mp->transports_to_launch);
+ tor_free(mp->process_handle);
+ tor_free(mp->argv[0]);
+ tor_free(mp->argv);
tor_free(mp);
}
@@ -138,6 +456,12 @@ test_pt_protocol(void)
struct testcase_t pt_tests[] = {
PT_LEGACY(parsing),
PT_LEGACY(protocol),
+ { "get_transport_options", test_pt_get_transport_options, TT_FORK,
+ NULL, NULL },
+ { "get_extrainfo_string", test_pt_get_extrainfo_string, TT_FORK,
+ NULL, NULL },
+ { "configure_proxy",test_pt_configure_proxy, TT_FORK,
+ NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_relaycell.c b/src/test/test_relaycell.c
new file mode 100644
index 000000000..5deb36260
--- /dev/null
+++ b/src/test/test_relaycell.c
@@ -0,0 +1,249 @@
+/* Copyright (c) 2014, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/* Unit tests for handling different kinds of relay cell */
+
+#define RELAY_PRIVATE
+#include "or.h"
+#include "config.h"
+#include "connection.h"
+#include "connection_edge.h"
+#include "relay.h"
+#include "test.h"
+
+static int srm_ncalls;
+static entry_connection_t *srm_conn;
+static int srm_atype;
+static size_t srm_alen;
+static int srm_answer_is_set;
+static uint8_t srm_answer[512];
+static int srm_ttl;
+static time_t srm_expires;
+
+/* Mock replacement for connection_ap_hannshake_socks_resolved() */
+static void
+socks_resolved_mock(entry_connection_t *conn,
+ int answer_type,
+ size_t answer_len,
+ const uint8_t *answer,
+ int ttl,
+ time_t expires)
+{
+ srm_ncalls++;
+ srm_conn = conn;
+ srm_atype = answer_type;
+ srm_alen = answer_len;
+ if (answer) {
+ memset(srm_answer, 0, sizeof(srm_answer));
+ memcpy(srm_answer, answer, answer_len < 512 ? answer_len : 512);
+ srm_answer_is_set = 1;
+ } else {
+ srm_answer_is_set = 0;
+ }
+ srm_ttl = ttl;
+ srm_expires = expires;
+}
+
+static int mum_ncalls;
+static entry_connection_t *mum_conn;
+static int mum_endreason;
+
+/* Mock replacement for connection_mark_unattached_ap_() */
+static void
+mark_unattached_mock(entry_connection_t *conn, int endreason,
+ int line, const char *file)
+{
+ ++mum_ncalls;
+ mum_conn = conn;
+ mum_endreason = endreason;
+ (void) line;
+ (void) file;
+}
+
+/* Tests for connection_edge_process_resolved_cell().
+
+ The point of ..process_resolved_cell() is to handle an incoming cell
+ on an entry connection, and call connection_mark_unattached_ap() and/or
+ connection_ap_handshake_socks_resolved().
+ */
+static void
+test_relaycell_resolved(void *arg)
+{
+ entry_connection_t *entryconn;
+ edge_connection_t *edgeconn;
+ cell_t cell;
+ relay_header_t rh;
+ int r;
+ or_options_t *options = get_options_mutable();
+
+#define SET_CELL(s) do { \
+ memset(&cell, 0, sizeof(cell)); \
+ memset(&rh, 0, sizeof(rh)); \
+ memcpy(cell.payload + RELAY_HEADER_SIZE, (s), sizeof((s))-1); \
+ rh.length = sizeof((s))-1; \
+ rh.command = RELAY_COMMAND_RESOLVED; \
+ } while (0)
+#define MOCK_RESET() do { \
+ srm_ncalls = mum_ncalls = 0; \
+ } while (0)
+#define ASSERT_MARK_CALLED(reason) do { \
+ tt_int_op(mum_ncalls, ==, 1); \
+ tt_ptr_op(mum_conn, ==, entryconn); \
+ tt_int_op(mum_endreason, ==, (reason)); \
+ } while (0)
+#define ASSERT_RESOLVED_CALLED(atype, answer, ttl, expires) do { \
+ tt_int_op(srm_ncalls, ==, 1); \
+ tt_ptr_op(srm_conn, ==, entryconn); \
+ tt_int_op(srm_atype, ==, (atype)); \
+ if (answer) { \
+ tt_int_op(srm_alen, ==, sizeof(answer)-1); \
+ tt_int_op(srm_alen, <, 512); \
+ tt_int_op(srm_answer_is_set, ==, 1); \
+ tt_mem_op(srm_answer, ==, answer, sizeof(answer)-1); \
+ } else { \
+ tt_int_op(srm_answer_is_set, ==, 0); \
+ } \
+ tt_int_op(srm_ttl, ==, ttl); \
+ tt_int_op(srm_expires, ==, expires); \
+ } while (0)
+
+ (void)arg;
+
+ MOCK(connection_mark_unattached_ap_, mark_unattached_mock);
+ MOCK(connection_ap_handshake_socks_resolved, socks_resolved_mock);
+
+ options->ClientDNSRejectInternalAddresses = 0;
+
+ SET_CELL(/* IPv4: 127.0.1.2, ttl 256 */
+ "\x04\x04\x7f\x00\x01\x02\x00\x00\x01\x00"
+ /* IPv4: 18.0.0.1, ttl 512 */
+ "\x04\x04\x12\x00\x00\x01\x00\x00\x02\x00"
+ /* IPv6: 2003::3, ttl 1024 */
+ "\x06\x10"
+ "\x20\x02\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x03"
+ "\x00\x00\x04\x00");
+
+ entryconn = entry_connection_new(CONN_TYPE_AP, AF_INET);
+ edgeconn = ENTRY_TO_EDGE_CONN(entryconn);
+
+ /* Try with connection in non-RESOLVE_WAIT state: cell gets ignored */
+ MOCK_RESET();
+ r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh);
+ tt_int_op(r, ==, 0);
+ tt_int_op(srm_ncalls, ==, 0);
+ tt_int_op(mum_ncalls, ==, 0);
+
+ /* Now put it in the right state. */
+ ENTRY_TO_CONN(entryconn)->state = AP_CONN_STATE_RESOLVE_WAIT;
+ entryconn->socks_request->command = SOCKS_COMMAND_RESOLVE;
+ entryconn->ipv4_traffic_ok = 1;
+ entryconn->ipv6_traffic_ok = 1;
+ entryconn->prefer_ipv6_traffic = 0;
+
+ /* We prefer ipv4, so we should get the first ipv4 answer */
+ MOCK_RESET();
+ r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh);
+ tt_int_op(r, ==, 0);
+ ASSERT_MARK_CALLED(END_STREAM_REASON_DONE|
+ END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
+ ASSERT_RESOLVED_CALLED(RESOLVED_TYPE_IPV4, "\x7f\x00\x01\x02", 256, -1);
+
+ /* But we may be discarding private answers. */
+ MOCK_RESET();
+ options->ClientDNSRejectInternalAddresses = 1;
+ r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh);
+ tt_int_op(r, ==, 0);
+ ASSERT_MARK_CALLED(END_STREAM_REASON_DONE|
+ END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
+ ASSERT_RESOLVED_CALLED(RESOLVED_TYPE_IPV4, "\x12\x00\x00\x01", 512, -1);
+
+ /* now prefer ipv6, and get the first ipv6 answer */
+ entryconn->prefer_ipv6_traffic = 1;
+ MOCK_RESET();
+ r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh);
+ tt_int_op(r, ==, 0);
+ ASSERT_MARK_CALLED(END_STREAM_REASON_DONE|
+ END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
+ ASSERT_RESOLVED_CALLED(RESOLVED_TYPE_IPV6,
+ "\x20\x02\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x03",
+ 1024, -1);
+
+ /* With a cell that only has IPv4, we report IPv4 even if we prefer IPv6 */
+ MOCK_RESET();
+ SET_CELL("\x04\x04\x12\x00\x00\x01\x00\x00\x02\x00");
+ r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh);
+ tt_int_op(r, ==, 0);
+ ASSERT_MARK_CALLED(END_STREAM_REASON_DONE|
+ END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
+ ASSERT_RESOLVED_CALLED(RESOLVED_TYPE_IPV4, "\x12\x00\x00\x01", 512, -1);
+
+ /* But if we don't allow IPv4, we report nothing if the cell contains only
+ * ipv4 */
+ MOCK_RESET();
+ entryconn->ipv4_traffic_ok = 0;
+ r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh);
+ tt_int_op(r, ==, 0);
+ ASSERT_MARK_CALLED(END_STREAM_REASON_DONE|
+ END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
+ ASSERT_RESOLVED_CALLED(RESOLVED_TYPE_ERROR, NULL, -1, -1);
+
+ /* If we wanted hostnames, we report nothing, since we only had IPs. */
+ MOCK_RESET();
+ entryconn->ipv4_traffic_ok = 1;
+ entryconn->socks_request->command = SOCKS_COMMAND_RESOLVE_PTR;
+ r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh);
+ tt_int_op(r, ==, 0);
+ ASSERT_MARK_CALLED(END_STREAM_REASON_DONE|
+ END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
+ ASSERT_RESOLVED_CALLED(RESOLVED_TYPE_ERROR, NULL, -1, -1);
+
+ /* A hostname cell is fine though. */
+ MOCK_RESET();
+ SET_CELL("\x00\x0fwww.example.com\x00\x01\x00\x00");
+ r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh);
+ tt_int_op(r, ==, 0);
+ ASSERT_MARK_CALLED(END_STREAM_REASON_DONE|
+ END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
+ ASSERT_RESOLVED_CALLED(RESOLVED_TYPE_HOSTNAME, "www.example.com", 65536, -1);
+
+ /* error on malformed cell */
+ MOCK_RESET();
+ entryconn->socks_request->command = SOCKS_COMMAND_RESOLVE;
+ SET_CELL("\x04\x04\x01\x02\x03\x04"); /* no ttl */
+ r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh);
+ tt_int_op(r, ==, 0);
+ ASSERT_MARK_CALLED(END_STREAM_REASON_TORPROTOCOL);
+ tt_int_op(srm_ncalls, ==, 0);
+
+ /* error on all addresses private */
+ MOCK_RESET();
+ SET_CELL(/* IPv4: 127.0.1.2, ttl 256 */
+ "\x04\x04\x7f\x00\x01\x02\x00\x00\x01\x00"
+ /* IPv4: 192.168.1.1, ttl 256 */
+ "\x04\x04\xc0\xa8\x01\x01\x00\x00\x01\x00");
+ r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh);
+ tt_int_op(r, ==, 0);
+ ASSERT_MARK_CALLED(END_STREAM_REASON_TORPROTOCOL);
+ ASSERT_RESOLVED_CALLED(RESOLVED_TYPE_ERROR_TRANSIENT, NULL, 0, TIME_MAX);
+
+ /* Legit error code */
+ MOCK_RESET();
+ SET_CELL("\xf0\x15" "quiet and meaningless" "\x00\x00\x0f\xff");
+ r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh);
+ tt_int_op(r, ==, 0);
+ ASSERT_MARK_CALLED(END_STREAM_REASON_DONE|
+ END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
+ ASSERT_RESOLVED_CALLED(RESOLVED_TYPE_ERROR_TRANSIENT, NULL, -1, -1);
+
+ done:
+ UNMOCK(connection_mark_unattached_ap_);
+ UNMOCK(connection_ap_handshake_socks_resolved);
+}
+
+struct testcase_t relaycell_tests[] = {
+ { "resolved", test_relaycell_resolved, TT_FORK, NULL, NULL },
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_replay.c b/src/test/test_replay.c
index de841ad59..b48f582f5 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;
@@ -42,7 +76,13 @@ test_replaycache_miss(void)
result =
replaycache_add_and_test_internal(1200, r, test_buffer,
- (int)strlen(test_buffer), NULL);
+ 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,
+ strlen(test_buffer), NULL);
test_eq(result, 0);
done:
@@ -62,12 +102,12 @@ test_replaycache_hit(void)
result =
replaycache_add_and_test_internal(1200, r, test_buffer,
- (int)strlen(test_buffer), NULL);
+ strlen(test_buffer), NULL);
test_eq(result, 0);
result =
replaycache_add_and_test_internal(1300, r, test_buffer,
- (int)strlen(test_buffer), NULL);
+ strlen(test_buffer), NULL);
test_eq(result, 1);
done:
@@ -87,17 +127,17 @@ test_replaycache_age(void)
result =
replaycache_add_and_test_internal(1200, r, test_buffer,
- (int)strlen(test_buffer), NULL);
+ strlen(test_buffer), NULL);
test_eq(result, 0);
result =
replaycache_add_and_test_internal(1300, r, test_buffer,
- (int)strlen(test_buffer), NULL);
+ strlen(test_buffer), NULL);
test_eq(result, 1);
result =
replaycache_add_and_test_internal(3000, r, test_buffer,
- (int)strlen(test_buffer), NULL);
+ strlen(test_buffer), NULL);
test_eq(result, 0);
done:
@@ -118,12 +158,12 @@ test_replaycache_elapsed(void)
result =
replaycache_add_and_test_internal(1200, r, test_buffer,
- (int)strlen(test_buffer), NULL);
+ strlen(test_buffer), NULL);
test_eq(result, 0);
result =
replaycache_add_and_test_internal(1300, r, test_buffer,
- (int)strlen(test_buffer), &elapsed);
+ strlen(test_buffer), &elapsed);
test_eq(result, 1);
test_eq(elapsed, 100);
@@ -144,18 +184,102 @@ test_replaycache_noexpire(void)
result =
replaycache_add_and_test_internal(1200, r, test_buffer,
- (int)strlen(test_buffer), NULL);
+ strlen(test_buffer), NULL);
test_eq(result, 0);
result =
replaycache_add_and_test_internal(1300, r, test_buffer,
- (int)strlen(test_buffer), NULL);
+ strlen(test_buffer), NULL);
test_eq(result, 1);
result =
replaycache_add_and_test_internal(3000, r, test_buffer,
- (int)strlen(test_buffer), NULL);
+ strlen(test_buffer), NULL);
+ test_eq(result, 1);
+
+ done:
+ if (r) replaycache_free(r);
+
+ 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,
+ strlen(test_buffer), NULL);
+ test_eq(result, 0);
+
+ result =
+ replaycache_add_and_test_internal(200, r, test_buffer,
+ 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,
+ 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,
+ 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,
+ 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);
@@ -163,16 +287,62 @@ test_replaycache_noexpire(void)
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, strlen(test_buffer));
+ test_eq(result, 0);
+
+ /* This should hit */
+ result =
+ replaycache_add_and_test(r, test_buffer, 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,
+ 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_routerkeys.c b/src/test/test_routerkeys.c
new file mode 100644
index 000000000..182e0f6f8
--- /dev/null
+++ b/src/test/test_routerkeys.c
@@ -0,0 +1,85 @@
+/* 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 */
+
+#include "orconfig.h"
+#define ROUTER_PRIVATE
+#include "or.h"
+#include "config.h"
+#include "router.h"
+#include "util.h"
+#include "crypto.h"
+
+#include "test.h"
+
+static void
+test_routerkeys_write_fingerprint(void *arg)
+{
+ crypto_pk_t *key = pk_generate(2);
+ or_options_t *options = get_options_mutable();
+ const char *ddir = get_fname("write_fingerprint");
+ char *cp = NULL, *cp2 = NULL;
+ char fp[FINGERPRINT_LEN+1];
+
+ (void)arg;
+
+ tt_assert(key);
+
+ options->ORPort_set = 1; /* So that we can get the server ID key */
+ tor_free(options->DataDirectory);
+ options->DataDirectory = tor_strdup(ddir);
+ options->Nickname = tor_strdup("haflinger");
+ set_server_identity_key(key);
+ set_client_identity_key(crypto_pk_dup_key(key));
+
+ tt_int_op(0, ==, check_private_dir(ddir, CPD_CREATE, NULL));
+ tt_int_op(crypto_pk_cmp_keys(get_server_identity_key(),key),==,0);
+
+ /* Write fingerprint file */
+ tt_int_op(0, ==, router_write_fingerprint(0));
+ cp = read_file_to_str(get_fname("write_fingerprint/fingerprint"),
+ 0, NULL);
+ crypto_pk_get_fingerprint(key, fp, 0);
+ tor_asprintf(&cp2, "haflinger %s\n", fp);
+ tt_str_op(cp, ==, cp2);
+ tor_free(cp);
+ tor_free(cp2);
+
+ /* Write hashed-fingerprint file */
+ tt_int_op(0, ==, router_write_fingerprint(1));
+ cp = read_file_to_str(get_fname("write_fingerprint/hashed-fingerprint"),
+ 0, NULL);
+ crypto_pk_get_hashed_fingerprint(key, fp);
+ tor_asprintf(&cp2, "haflinger %s\n", fp);
+ tt_str_op(cp, ==, cp2);
+ tor_free(cp);
+ tor_free(cp2);
+
+ /* Replace outdated file */
+ write_str_to_file(get_fname("write_fingerprint/hashed-fingerprint"),
+ "junk goes here", 0);
+ tt_int_op(0, ==, router_write_fingerprint(1));
+ cp = read_file_to_str(get_fname("write_fingerprint/hashed-fingerprint"),
+ 0, NULL);
+ crypto_pk_get_hashed_fingerprint(key, fp);
+ tor_asprintf(&cp2, "haflinger %s\n", fp);
+ tt_str_op(cp, ==, cp2);
+ tor_free(cp);
+ tor_free(cp2);
+
+ done:
+ crypto_pk_free(key);
+ set_client_identity_key(NULL);
+ tor_free(cp);
+ tor_free(cp2);
+}
+
+#define TEST(name, flags) \
+ { #name , test_routerkeys_ ## name, (flags), NULL, NULL }
+
+struct testcase_t routerkeys_tests[] = {
+ TEST(write_fingerprint, TT_FORK),
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_socks.c b/src/test/test_socks.c
new file mode 100644
index 000000000..4ce61e068
--- /dev/null
+++ b/src/test/test_socks.c
@@ -0,0 +1,393 @@
+/* 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 */
+
+#include "or.h"
+#include "buffers.h"
+#include "config.h"
+#include "test.h"
+
+typedef struct socks_test_data_t {
+ socks_request_t *req;
+ buf_t *buf;
+} socks_test_data_t;
+
+static void *
+socks_test_setup(const struct testcase_t *testcase)
+{
+ socks_test_data_t *data = tor_malloc(sizeof(socks_test_data_t));
+ (void)testcase;
+ data->buf = buf_new_with_capacity(256);
+ data->req = socks_request_new();
+ config_register_addressmaps(get_options());
+ return data;
+}
+static int
+socks_test_cleanup(const struct testcase_t *testcase, void *ptr)
+{
+ socks_test_data_t *data = ptr;
+ (void)testcase;
+ buf_free(data->buf);
+ socks_request_free(data->req);
+ tor_free(data);
+ return 1;
+}
+
+const struct testcase_setup_t socks_setup = {
+ socks_test_setup, socks_test_cleanup
+};
+
+#define SOCKS_TEST_INIT() \
+ socks_test_data_t *testdata = ptr; \
+ buf_t *buf = testdata->buf; \
+ socks_request_t *socks = testdata->req;
+#define ADD_DATA(buf, s) \
+ write_to_buf(s, sizeof(s)-1, buf)
+
+static void
+socks_request_clear(socks_request_t *socks)
+{
+ tor_free(socks->username);
+ tor_free(socks->password);
+ memset(socks, 0, sizeof(socks_request_t));
+}
+
+/** Perform unsupported SOCKS 4 commands */
+static void
+test_socks_4_unsupported_commands(void *ptr)
+{
+ SOCKS_TEST_INIT();
+
+ /* SOCKS 4 Send BIND [02] to IP address 2.2.2.2:4369 */
+ ADD_DATA(buf, "\x04\x02\x11\x11\x02\x02\x02\x02\x00");
+ test_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks) == -1);
+ test_eq(4, socks->socks_version);
+ test_eq(0, socks->replylen); /* XXX: shouldn't tor reply? */
+
+ done:
+ ;
+}
+
+/** Perform supported SOCKS 4 commands */
+static void
+test_socks_4_supported_commands(void *ptr)
+{
+ SOCKS_TEST_INIT();
+
+ test_eq(0, buf_datalen(buf));
+
+ /* SOCKS 4 Send CONNECT [01] to IP address 2.2.2.2:4370 */
+ ADD_DATA(buf, "\x04\x01\x11\x12\x02\x02\x02\x03\x00");
+ test_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks) == 1);
+ test_eq(4, socks->socks_version);
+ test_eq(0, socks->replylen); /* XXX: shouldn't tor reply? */
+ test_eq(SOCKS_COMMAND_CONNECT, socks->command);
+ test_streq("2.2.2.3", socks->address);
+ test_eq(4370, socks->port);
+ test_assert(socks->got_auth == 0);
+ test_assert(! socks->username);
+
+ test_eq(0, buf_datalen(buf));
+ socks_request_clear(socks);
+
+ /* SOCKS 4 Send CONNECT [01] to IP address 2.2.2.2:4369 with userid*/
+ ADD_DATA(buf, "\x04\x01\x11\x12\x02\x02\x02\x04me\x00");
+ test_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks) == 1);
+ test_eq(4, socks->socks_version);
+ test_eq(0, socks->replylen); /* XXX: shouldn't tor reply? */
+ test_eq(SOCKS_COMMAND_CONNECT, socks->command);
+ test_streq("2.2.2.4", socks->address);
+ test_eq(4370, socks->port);
+ test_assert(socks->got_auth == 1);
+ test_assert(socks->username);
+ test_eq(2, socks->usernamelen);
+ test_memeq("me", socks->username, 2);
+
+ test_eq(0, buf_datalen(buf));
+ socks_request_clear(socks);
+
+ /* SOCKS 4a Send RESOLVE [F0] request for torproject.org */
+ ADD_DATA(buf, "\x04\xF0\x01\x01\x00\x00\x00\x02me\x00torproject.org\x00");
+ test_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks) == 1);
+ test_eq(4, socks->socks_version);
+ test_eq(0, socks->replylen); /* XXX: shouldn't tor reply? */
+ test_streq("torproject.org", socks->address);
+
+ test_eq(0, buf_datalen(buf));
+
+ done:
+ ;
+}
+
+/** Perform unsupported SOCKS 5 commands */
+static void
+test_socks_5_unsupported_commands(void *ptr)
+{
+ SOCKS_TEST_INIT();
+
+ /* SOCKS 5 Send unsupported BIND [02] command */
+ ADD_DATA(buf, "\x05\x02\x00\x01");
+
+ test_eq(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks), 0);
+ test_eq(0, buf_datalen(buf));
+ test_eq(5, socks->socks_version);
+ test_eq(2, socks->replylen);
+ test_eq(5, socks->reply[0]);
+ test_eq(0, socks->reply[1]);
+ ADD_DATA(buf, "\x05\x02\x00\x01\x02\x02\x02\x01\x01\x01");
+ test_eq(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks), -1);
+ /* XXX: shouldn't tor reply 'command not supported' [07]? */
+
+ buf_clear(buf);
+ socks_request_clear(socks);
+
+ /* SOCKS 5 Send unsupported UDP_ASSOCIATE [03] command */
+ ADD_DATA(buf, "\x05\x03\x00\x01\x02");
+ test_eq(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks), 0);
+ test_eq(5, socks->socks_version);
+ test_eq(2, socks->replylen);
+ test_eq(5, socks->reply[0]);
+ test_eq(2, socks->reply[1]);
+ ADD_DATA(buf, "\x05\x03\x00\x01\x02\x02\x02\x01\x01\x01");
+ test_eq(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks), -1);
+ /* XXX: shouldn't tor reply 'command not supported' [07]? */
+
+ done:
+ ;
+}
+
+/** Perform supported SOCKS 5 commands */
+static void
+test_socks_5_supported_commands(void *ptr)
+{
+ SOCKS_TEST_INIT();
+
+ /* SOCKS 5 Send CONNECT [01] to IP address 2.2.2.2:4369 */
+ ADD_DATA(buf, "\x05\x01\x00");
+ test_eq(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks), 0);
+ test_eq(5, socks->socks_version);
+ test_eq(2, socks->replylen);
+ test_eq(5, socks->reply[0]);
+ test_eq(0, socks->reply[1]);
+
+ ADD_DATA(buf, "\x05\x01\x00\x01\x02\x02\x02\x02\x11\x11");
+ test_eq(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks), 1);
+ test_streq("2.2.2.2", socks->address);
+ test_eq(4369, socks->port);
+
+ test_eq(0, buf_datalen(buf));
+ socks_request_clear(socks);
+
+ /* SOCKS 5 Send CONNECT [01] to FQDN torproject.org:4369 */
+ ADD_DATA(buf, "\x05\x01\x00");
+ ADD_DATA(buf, "\x05\x01\x00\x03\x0Etorproject.org\x11\x11");
+ test_eq(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks), 1);
+
+ test_eq(5, socks->socks_version);
+ test_eq(2, socks->replylen);
+ test_eq(5, socks->reply[0]);
+ test_eq(0, socks->reply[1]);
+ test_streq("torproject.org", socks->address);
+ test_eq(4369, socks->port);
+
+ test_eq(0, buf_datalen(buf));
+ socks_request_clear(socks);
+
+ /* SOCKS 5 Send RESOLVE [F0] request for torproject.org:4369 */
+ ADD_DATA(buf, "\x05\x01\x00");
+ ADD_DATA(buf, "\x05\xF0\x00\x03\x0Etorproject.org\x01\x02");
+ test_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks) == 1);
+ test_eq(5, socks->socks_version);
+ test_eq(2, socks->replylen);
+ test_eq(5, socks->reply[0]);
+ test_eq(0, socks->reply[1]);
+ test_streq("torproject.org", socks->address);
+
+ test_eq(0, buf_datalen(buf));
+ socks_request_clear(socks);
+
+ /* SOCKS 5 Send RESOLVE_PTR [F1] for IP address 2.2.2.5 */
+ ADD_DATA(buf, "\x05\x01\x00");
+ ADD_DATA(buf, "\x05\xF1\x00\x01\x02\x02\x02\x05\x01\x03");
+ test_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks) == 1);
+ test_eq(5, socks->socks_version);
+ test_eq(2, socks->replylen);
+ test_eq(5, socks->reply[0]);
+ test_eq(0, socks->reply[1]);
+ test_streq("2.2.2.5", socks->address);
+
+ test_eq(0, buf_datalen(buf));
+
+ done:
+ ;
+}
+
+/** Perform SOCKS 5 authentication */
+static void
+test_socks_5_no_authenticate(void *ptr)
+{
+ SOCKS_TEST_INIT();
+
+ /*SOCKS 5 No Authentication */
+ ADD_DATA(buf,"\x05\x01\x00");
+ test_assert(!fetch_from_buf_socks(buf, socks,
+ get_options()->TestSocks,
+ get_options()->SafeSocks));
+ test_eq(2, socks->replylen);
+ test_eq(5, socks->reply[0]);
+ test_eq(SOCKS_NO_AUTH, socks->reply[1]);
+
+ test_eq(0, buf_datalen(buf));
+
+ /*SOCKS 5 Send username/password anyway - pretend to be broken */
+ ADD_DATA(buf,"\x01\x02\x01\x01\x02\x01\x01");
+ test_assert(!fetch_from_buf_socks(buf, socks,
+ get_options()->TestSocks,
+ get_options()->SafeSocks));
+ test_eq(5, socks->socks_version);
+ test_eq(2, socks->replylen);
+ test_eq(1, socks->reply[0]);
+ test_eq(0, socks->reply[1]);
+
+ test_eq(2, socks->usernamelen);
+ test_eq(2, socks->passwordlen);
+
+ test_memeq("\x01\x01", socks->username, 2);
+ test_memeq("\x01\x01", socks->password, 2);
+
+ done:
+ ;
+}
+
+/** Perform SOCKS 5 authentication */
+static void
+test_socks_5_authenticate(void *ptr)
+{
+ SOCKS_TEST_INIT();
+
+ /* SOCKS 5 Negotiate username/password authentication */
+ ADD_DATA(buf, "\x05\x01\x02");
+
+ test_assert(!fetch_from_buf_socks(buf, socks,
+ get_options()->TestSocks,
+ get_options()->SafeSocks));
+ test_eq(2, socks->replylen);
+ test_eq(5, socks->reply[0]);
+ test_eq(SOCKS_USER_PASS, socks->reply[1]);
+ test_eq(5, socks->socks_version);
+
+ test_eq(0, buf_datalen(buf));
+
+ /* SOCKS 5 Send username/password */
+ ADD_DATA(buf, "\x01\x02me\x08mypasswd");
+ test_assert(!fetch_from_buf_socks(buf, socks,
+ get_options()->TestSocks,
+ get_options()->SafeSocks));
+ test_eq(5, socks->socks_version);
+ test_eq(2, socks->replylen);
+ test_eq(1, socks->reply[0]);
+ test_eq(0, socks->reply[1]);
+
+ test_eq(2, socks->usernamelen);
+ test_eq(8, socks->passwordlen);
+
+ test_memeq("me", socks->username, 2);
+ test_memeq("mypasswd", socks->password, 8);
+
+ done:
+ ;
+}
+
+/** Perform SOCKS 5 authentication and send data all in one go */
+static void
+test_socks_5_authenticate_with_data(void *ptr)
+{
+ SOCKS_TEST_INIT();
+
+ /* SOCKS 5 Negotiate username/password authentication */
+ ADD_DATA(buf, "\x05\x01\x02");
+
+ test_assert(!fetch_from_buf_socks(buf, socks,
+ get_options()->TestSocks,
+ get_options()->SafeSocks));
+ test_eq(2, socks->replylen);
+ test_eq(5, socks->reply[0]);
+ test_eq(SOCKS_USER_PASS, socks->reply[1]);
+ test_eq(5, socks->socks_version);
+
+ test_eq(0, buf_datalen(buf));
+
+ /* SOCKS 5 Send username/password */
+ /* SOCKS 5 Send CONNECT [01] to IP address 2.2.2.2:4369 */
+ ADD_DATA(buf, "\x01\x02me\x03you\x05\x01\x00\x01\x02\x02\x02\x02\x11\x11");
+ test_assert(fetch_from_buf_socks(buf, socks,
+ get_options()->TestSocks,
+ get_options()->SafeSocks) == 1);
+ test_eq(5, socks->socks_version);
+ test_eq(2, socks->replylen);
+ test_eq(1, socks->reply[0]);
+ test_eq(0, socks->reply[1]);
+
+ test_streq("2.2.2.2", socks->address);
+ test_eq(4369, socks->port);
+
+ test_eq(2, socks->usernamelen);
+ test_eq(3, socks->passwordlen);
+ test_memeq("me", socks->username, 2);
+ test_memeq("you", socks->password, 3);
+
+ done:
+ ;
+}
+
+/** Perform SOCKS 5 authentication before method negotiated */
+static void
+test_socks_5_auth_before_negotiation(void *ptr)
+{
+ SOCKS_TEST_INIT();
+
+ /* SOCKS 5 Send username/password */
+ ADD_DATA(buf, "\x01\x02me\x02me");
+ test_assert(fetch_from_buf_socks(buf, socks,
+ get_options()->TestSocks,
+ get_options()->SafeSocks) == -1);
+ test_eq(0, socks->socks_version);
+ test_eq(0, socks->replylen);
+ test_eq(0, socks->reply[0]);
+ test_eq(0, socks->reply[1]);
+
+ done:
+ ;
+}
+
+#define SOCKSENT(name) \
+ { #name, test_socks_##name, TT_FORK, &socks_setup, NULL }
+
+struct testcase_t socks_tests[] = {
+ SOCKSENT(4_unsupported_commands),
+ SOCKSENT(4_supported_commands),
+
+ SOCKSENT(5_unsupported_commands),
+ SOCKSENT(5_supported_commands),
+ SOCKSENT(5_no_authenticate),
+ SOCKSENT(5_auth_before_negotiation),
+ SOCKSENT(5_authenticate),
+ SOCKSENT(5_authenticate_with_data),
+
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_status.c b/src/test/test_status.c
new file mode 100644
index 000000000..46dd47313
--- /dev/null
+++ b/src/test/test_status.c
@@ -0,0 +1,1114 @@
+#define STATUS_PRIVATE
+#define HIBERNATE_PRIVATE
+#define LOG_PRIVATE
+#define REPHIST_PRIVATE
+
+#include <float.h>
+#include <math.h>
+
+#include "or.h"
+#include "torlog.h"
+#include "tor_queue.h"
+#include "status.h"
+#include "circuitlist.h"
+#include "config.h"
+#include "hibernate.h"
+#include "rephist.h"
+#include "relay.h"
+#include "router.h"
+#include "main.h"
+#include "nodelist.h"
+#include "statefile.h"
+#include "test.h"
+
+#define NS_MODULE status
+
+#define NS_SUBMODULE count_circuits
+
+/*
+ * Test that count_circuits() is correctly counting the number of
+ * global circuits.
+ */
+
+struct global_circuitlist_s mock_global_circuitlist =
+ TOR_LIST_HEAD_INITIALIZER(global_circuitlist);
+
+NS_DECL(struct global_circuitlist_s *, circuit_get_global_list, (void));
+
+static void
+NS(test_main)(void *arg)
+{
+ /* Choose origin_circuit_t wlog. */
+ origin_circuit_t *mock_circuit1, *mock_circuit2;
+ circuit_t *circ, *tmp;
+ int expected_circuits = 2, actual_circuits;
+
+ (void)arg;
+
+ mock_circuit1 = tor_malloc_zero(sizeof(origin_circuit_t));
+ mock_circuit2 = tor_malloc_zero(sizeof(origin_circuit_t));
+ TOR_LIST_INSERT_HEAD(
+ &mock_global_circuitlist, TO_CIRCUIT(mock_circuit1), head);
+ TOR_LIST_INSERT_HEAD(
+ &mock_global_circuitlist, TO_CIRCUIT(mock_circuit2), head);
+
+ NS_MOCK(circuit_get_global_list);
+
+ actual_circuits = count_circuits();
+
+ tt_assert(expected_circuits == actual_circuits);
+
+ done:
+ TOR_LIST_FOREACH_SAFE(
+ circ, NS(circuit_get_global_list)(), head, tmp);
+ tor_free(circ);
+ NS_UNMOCK(circuit_get_global_list);
+}
+
+static struct global_circuitlist_s *
+NS(circuit_get_global_list)(void)
+{
+ return &mock_global_circuitlist;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE secs_to_uptime
+
+/*
+ * Test that secs_to_uptime() is converting the number of seconds that
+ * Tor is up for into the appropriate string form containing hours and minutes.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+ const char *expected;
+ char *actual;
+ (void)arg;
+
+ expected = "0:00 hours";
+ actual = secs_to_uptime(0);
+ tt_str_op(actual, ==, expected);
+ tor_free(actual);
+
+ expected = "0:00 hours";
+ actual = secs_to_uptime(1);
+ tt_str_op(actual, ==, expected);
+ tor_free(actual);
+
+ expected = "0:01 hours";
+ actual = secs_to_uptime(60);
+ tt_str_op(actual, ==, expected);
+ tor_free(actual);
+
+ expected = "0:59 hours";
+ actual = secs_to_uptime(60 * 59);
+ tt_str_op(actual, ==, expected);
+ tor_free(actual);
+
+ expected = "1:00 hours";
+ actual = secs_to_uptime(60 * 60);
+ tt_str_op(actual, ==, expected);
+ tor_free(actual);
+
+ expected = "23:59 hours";
+ actual = secs_to_uptime(60 * 60 * 23 + 60 * 59);
+ tt_str_op(actual, ==, expected);
+ tor_free(actual);
+
+ expected = "1 day 0:00 hours";
+ actual = secs_to_uptime(60 * 60 * 23 + 60 * 60);
+ tt_str_op(actual, ==, expected);
+ tor_free(actual);
+
+ expected = "1 day 0:00 hours";
+ actual = secs_to_uptime(86400 + 1);
+ tt_str_op(actual, ==, expected);
+ tor_free(actual);
+
+ expected = "1 day 0:01 hours";
+ actual = secs_to_uptime(86400 + 60);
+ tt_str_op(actual, ==, expected);
+ tor_free(actual);
+
+ expected = "10 days 0:00 hours";
+ actual = secs_to_uptime(86400 * 10);
+ tt_str_op(actual, ==, expected);
+ tor_free(actual);
+
+ expected = "10 days 0:00 hours";
+ actual = secs_to_uptime(864000 + 1);
+ tt_str_op(actual, ==, expected);
+ tor_free(actual);
+
+ expected = "10 days 0:01 hours";
+ actual = secs_to_uptime(864000 + 60);
+ tt_str_op(actual, ==, expected);
+ tor_free(actual);
+
+ done:
+ if (actual != NULL)
+ tor_free(actual);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE bytes_to_usage
+
+/*
+ * Test that bytes_to_usage() is correctly converting the number of bytes that
+ * Tor has read/written into the appropriate string form containing kilobytes,
+ * megabytes, or gigabytes.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+ const char *expected;
+ char *actual;
+ (void)arg;
+
+ expected = "0 kB";
+ actual = bytes_to_usage(0);
+ tt_str_op(actual, ==, expected);
+ tor_free(actual);
+
+ expected = "0 kB";
+ actual = bytes_to_usage(1);
+ tt_str_op(actual, ==, expected);
+ tor_free(actual);
+
+ expected = "1 kB";
+ actual = bytes_to_usage(1024);
+ tt_str_op(actual, ==, expected);
+ tor_free(actual);
+
+ expected = "1023 kB";
+ actual = bytes_to_usage((1 << 20) - 1);
+ tt_str_op(actual, ==, expected);
+ tor_free(actual);
+
+ expected = "1.00 MB";
+ actual = bytes_to_usage((1 << 20));
+ tt_str_op(actual, ==, expected);
+ tor_free(actual);
+
+ expected = "1.00 MB";
+ actual = bytes_to_usage((1 << 20) + 5242);
+ tt_str_op(actual, ==, expected);
+ tor_free(actual);
+
+ expected = "1.01 MB";
+ actual = bytes_to_usage((1 << 20) + 5243);
+ tt_str_op(actual, ==, expected);
+ tor_free(actual);
+
+ expected = "1024.00 MB";
+ actual = bytes_to_usage((1 << 30) - 1);
+ tt_str_op(actual, ==, expected);
+ tor_free(actual);
+
+ expected = "1.00 GB";
+ actual = bytes_to_usage((1 << 30));
+ tt_str_op(actual, ==, expected);
+ tor_free(actual);
+
+ expected = "1.00 GB";
+ actual = bytes_to_usage((1 << 30) + 5368709);
+ tt_str_op(actual, ==, expected);
+ tor_free(actual);
+
+ expected = "1.01 GB";
+ actual = bytes_to_usage((1 << 30) + 5368710);
+ tt_str_op(actual, ==, expected);
+ tor_free(actual);
+
+ expected = "10.00 GB";
+ actual = bytes_to_usage((U64_LITERAL(1) << 30) * 10L);
+ tt_str_op(actual, ==, expected);
+ tor_free(actual);
+
+ done:
+ if (actual != NULL)
+ tor_free(actual);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(log_heartbeat, fails)
+
+/*
+ * Tests that log_heartbeat() fails when in the public server mode,
+ * not hibernating, and we couldn't get the current routerinfo.
+ */
+
+NS_DECL(double, tls_get_write_overhead_ratio, (void));
+NS_DECL(int, we_are_hibernating, (void));
+NS_DECL(const or_options_t *, get_options, (void));
+NS_DECL(int, public_server_mode, (const or_options_t *options));
+NS_DECL(const routerinfo_t *, router_get_my_routerinfo, (void));
+
+static void
+NS(test_main)(void *arg)
+{
+ int expected, actual;
+ (void)arg;
+
+ NS_MOCK(tls_get_write_overhead_ratio);
+ NS_MOCK(we_are_hibernating);
+ NS_MOCK(get_options);
+ NS_MOCK(public_server_mode);
+ NS_MOCK(router_get_my_routerinfo);
+
+ expected = -1;
+ actual = log_heartbeat(0);
+
+ tt_int_op(actual, ==, expected);
+
+ done:
+ NS_UNMOCK(tls_get_write_overhead_ratio);
+ NS_UNMOCK(we_are_hibernating);
+ NS_UNMOCK(get_options);
+ NS_UNMOCK(public_server_mode);
+ NS_UNMOCK(router_get_my_routerinfo);
+}
+
+static double
+NS(tls_get_write_overhead_ratio)(void)
+{
+ return 2.0;
+}
+
+static int
+NS(we_are_hibernating)(void)
+{
+ return 0;
+}
+
+static const or_options_t *
+NS(get_options)(void)
+{
+ return NULL;
+}
+
+static int
+NS(public_server_mode)(const or_options_t *options)
+{
+ (void)options;
+
+ return 1;
+}
+
+static const routerinfo_t *
+NS(router_get_my_routerinfo)(void)
+{
+ return NULL;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(log_heartbeat, not_in_consensus)
+
+/*
+ * Tests that log_heartbeat() logs appropriately if we are not in the cached
+ * consensus.
+ */
+
+NS_DECL(double, tls_get_write_overhead_ratio, (void));
+NS_DECL(int, we_are_hibernating, (void));
+NS_DECL(const or_options_t *, get_options, (void));
+NS_DECL(int, public_server_mode, (const or_options_t *options));
+NS_DECL(const routerinfo_t *, router_get_my_routerinfo, (void));
+NS_DECL(const node_t *, node_get_by_id, (const char *identity_digest));
+NS_DECL(void, logv, (int severity, log_domain_mask_t domain,
+ const char *funcname, const char *suffix, const char *format, va_list ap));
+NS_DECL(int, server_mode, (const or_options_t *options));
+
+static routerinfo_t *mock_routerinfo;
+extern int onion_handshakes_requested[MAX_ONION_HANDSHAKE_TYPE+1];
+extern int onion_handshakes_assigned[MAX_ONION_HANDSHAKE_TYPE+1];
+
+static void
+NS(test_main)(void *arg)
+{
+ int expected, actual;
+ (void)arg;
+
+ NS_MOCK(tls_get_write_overhead_ratio);
+ NS_MOCK(we_are_hibernating);
+ NS_MOCK(get_options);
+ NS_MOCK(public_server_mode);
+ NS_MOCK(router_get_my_routerinfo);
+ NS_MOCK(node_get_by_id);
+ NS_MOCK(logv);
+ NS_MOCK(server_mode);
+
+ log_global_min_severity_ = LOG_DEBUG;
+ onion_handshakes_requested[ONION_HANDSHAKE_TYPE_TAP] = 1;
+ onion_handshakes_assigned[ONION_HANDSHAKE_TYPE_TAP] = 1;
+ onion_handshakes_requested[ONION_HANDSHAKE_TYPE_NTOR] = 1;
+ onion_handshakes_assigned[ONION_HANDSHAKE_TYPE_NTOR] = 1;
+
+ expected = 0;
+ actual = log_heartbeat(0);
+
+ tt_int_op(actual, ==, expected);
+ tt_int_op(CALLED(logv), ==, 3);
+
+ done:
+ NS_UNMOCK(tls_get_write_overhead_ratio);
+ NS_UNMOCK(we_are_hibernating);
+ NS_UNMOCK(get_options);
+ NS_UNMOCK(public_server_mode);
+ NS_UNMOCK(router_get_my_routerinfo);
+ NS_UNMOCK(node_get_by_id);
+ NS_UNMOCK(logv);
+ NS_UNMOCK(server_mode);
+ tor_free(mock_routerinfo);
+}
+
+static double
+NS(tls_get_write_overhead_ratio)(void)
+{
+ return 1.0;
+}
+
+static int
+NS(we_are_hibernating)(void)
+{
+ return 0;
+}
+
+static const or_options_t *
+NS(get_options)(void)
+{
+ return NULL;
+}
+
+static int
+NS(public_server_mode)(const or_options_t *options)
+{
+ (void)options;
+
+ return 1;
+}
+
+static const routerinfo_t *
+NS(router_get_my_routerinfo)(void)
+{
+ mock_routerinfo = tor_malloc(sizeof(routerinfo_t));
+
+ return mock_routerinfo;
+}
+
+static const node_t *
+NS(node_get_by_id)(const char *identity_digest)
+{
+ (void)identity_digest;
+
+ return NULL;
+}
+
+static void
+NS(logv)(int severity, log_domain_mask_t domain,
+ const char *funcname, const char *suffix, const char *format, va_list ap)
+{
+ switch (CALLED(logv))
+ {
+ case 0:
+ tt_int_op(severity, ==, LOG_NOTICE);
+ tt_int_op(domain, ==, LD_HEARTBEAT);
+ tt_ptr_op(strstr(funcname, "log_heartbeat"), !=, NULL);
+ tt_ptr_op(suffix, ==, NULL);
+ tt_str_op(format, ==,
+ "Heartbeat: It seems like we are not in the cached consensus.");
+ break;
+ case 1:
+ tt_int_op(severity, ==, LOG_NOTICE);
+ tt_int_op(domain, ==, LD_HEARTBEAT);
+ tt_ptr_op(strstr(funcname, "log_heartbeat"), !=, NULL);
+ tt_ptr_op(suffix, ==, NULL);
+ tt_str_op(format, ==,
+ "Heartbeat: Tor's uptime is %s, with %d circuits open. "
+ "I've sent %s and received %s.%s");
+ tt_str_op(va_arg(ap, char *), ==, "0:00 hours"); /* uptime */
+ tt_int_op(va_arg(ap, int), ==, 0); /* count_circuits() */
+ tt_str_op(va_arg(ap, char *), ==, "0 kB"); /* bw_sent */
+ tt_str_op(va_arg(ap, char *), ==, "0 kB"); /* bw_rcvd */
+ tt_str_op(va_arg(ap, char *), ==, ""); /* hibernating */
+ break;
+ case 2:
+ tt_int_op(severity, ==, LOG_NOTICE);
+ tt_int_op(domain, ==, LD_HEARTBEAT);
+ tt_ptr_op(
+ strstr(funcname, "rep_hist_log_circuit_handshake_stats"), !=, NULL);
+ tt_ptr_op(suffix, ==, NULL);
+ tt_str_op(format, ==,
+ "Circuit handshake stats since last time: %d/%d TAP, %d/%d NTor.");
+ tt_int_op(va_arg(ap, int), ==, 1); /* handshakes assigned (TAP) */
+ tt_int_op(va_arg(ap, int), ==, 1); /* handshakes requested (TAP) */
+ tt_int_op(va_arg(ap, int), ==, 1); /* handshakes assigned (NTOR) */
+ tt_int_op(va_arg(ap, int), ==, 1); /* handshakes requested (NTOR) */
+ break;
+ default:
+ tt_abort_msg("unexpected call to logv()"); // TODO: prettyprint args
+ break;
+ }
+
+ done:
+ CALLED(logv)++;
+}
+
+static int
+NS(server_mode)(const or_options_t *options)
+{
+ (void)options;
+
+ return 0;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(log_heartbeat, simple)
+
+/*
+ * Tests that log_heartbeat() correctly logs heartbeat information
+ * normally.
+ */
+
+NS_DECL(double, tls_get_write_overhead_ratio, (void));
+NS_DECL(int, we_are_hibernating, (void));
+NS_DECL(const or_options_t *, get_options, (void));
+NS_DECL(int, public_server_mode, (const or_options_t *options));
+NS_DECL(long, get_uptime, (void));
+NS_DECL(uint64_t, get_bytes_read, (void));
+NS_DECL(uint64_t, get_bytes_written, (void));
+NS_DECL(void, logv, (int severity, log_domain_mask_t domain,
+ const char *funcname, const char *suffix, const char *format, va_list ap));
+NS_DECL(int, server_mode, (const or_options_t *options));
+
+static void
+NS(test_main)(void *arg)
+{
+ int expected, actual;
+ (void)arg;
+
+ NS_MOCK(tls_get_write_overhead_ratio);
+ NS_MOCK(we_are_hibernating);
+ NS_MOCK(get_options);
+ NS_MOCK(public_server_mode);
+ NS_MOCK(get_uptime);
+ NS_MOCK(get_bytes_read);
+ NS_MOCK(get_bytes_written);
+ NS_MOCK(logv);
+ NS_MOCK(server_mode);
+
+ log_global_min_severity_ = LOG_DEBUG;
+
+ expected = 0;
+ actual = log_heartbeat(0);
+
+ tt_int_op(actual, ==, expected);
+
+ done:
+ NS_UNMOCK(tls_get_write_overhead_ratio);
+ NS_UNMOCK(we_are_hibernating);
+ NS_UNMOCK(get_options);
+ NS_UNMOCK(public_server_mode);
+ NS_UNMOCK(get_uptime);
+ NS_UNMOCK(get_bytes_read);
+ NS_UNMOCK(get_bytes_written);
+ NS_UNMOCK(logv);
+ NS_UNMOCK(server_mode);
+}
+
+static double
+NS(tls_get_write_overhead_ratio)(void)
+{
+ return 1.0;
+}
+
+static int
+NS(we_are_hibernating)(void)
+{
+ return 1;
+}
+
+static const or_options_t *
+NS(get_options)(void)
+{
+ return NULL;
+}
+
+static int
+NS(public_server_mode)(const or_options_t *options)
+{
+ (void)options;
+
+ return 0;
+}
+
+static long
+NS(get_uptime)(void)
+{
+ return 0;
+}
+
+static uint64_t
+NS(get_bytes_read)(void)
+{
+ return 0;
+}
+
+static uint64_t
+NS(get_bytes_written)(void)
+{
+ return 0;
+}
+
+static void
+NS(logv)(int severity, log_domain_mask_t domain, const char *funcname,
+ const char *suffix, const char *format, va_list ap)
+{
+ tt_int_op(severity, ==, LOG_NOTICE);
+ tt_int_op(domain, ==, LD_HEARTBEAT);
+ tt_ptr_op(strstr(funcname, "log_heartbeat"), !=, NULL);
+ tt_ptr_op(suffix, ==, NULL);
+ tt_str_op(format, ==,
+ "Heartbeat: Tor's uptime is %s, with %d circuits open. "
+ "I've sent %s and received %s.%s");
+ tt_str_op(va_arg(ap, char *), ==, "0:00 hours"); /* uptime */
+ tt_int_op(va_arg(ap, int), ==, 0); /* count_circuits() */
+ tt_str_op(va_arg(ap, char *), ==, "0 kB"); /* bw_sent */
+ tt_str_op(va_arg(ap, char *), ==, "0 kB"); /* bw_rcvd */
+ tt_str_op(va_arg(ap, char *), ==, " We are currently hibernating.");
+
+ done:
+ ;
+}
+
+static int
+NS(server_mode)(const or_options_t *options)
+{
+ (void)options;
+
+ return 0;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(log_heartbeat, calls_log_accounting)
+
+/*
+ * Tests that log_heartbeat() correctly logs heartbeat information
+ * and accounting information when configured.
+ */
+
+NS_DECL(double, tls_get_write_overhead_ratio, (void));
+NS_DECL(int, we_are_hibernating, (void));
+NS_DECL(const or_options_t *, get_options, (void));
+NS_DECL(int, public_server_mode, (const or_options_t *options));
+NS_DECL(long, get_uptime, (void));
+NS_DECL(uint64_t, get_bytes_read, (void));
+NS_DECL(uint64_t, get_bytes_written, (void));
+NS_DECL(void, logv, (int severity, log_domain_mask_t domain,
+ const char *funcname, const char *suffix, const char *format, va_list ap));
+NS_DECL(int, server_mode, (const or_options_t *options));
+NS_DECL(or_state_t *, get_or_state, (void));
+NS_DECL(int, accounting_is_enabled, (const or_options_t *options));
+NS_DECL(time_t, accounting_get_end_time, (void));
+
+static or_state_t * NS(mock_state) = NULL;
+static or_options_t * NS(mock_options) = NULL;
+
+static void
+NS(test_main)(void *arg)
+{
+ int expected, actual;
+ (void)arg;
+
+ NS_MOCK(tls_get_write_overhead_ratio);
+ NS_MOCK(we_are_hibernating);
+ NS_MOCK(get_options);
+ NS_MOCK(public_server_mode);
+ NS_MOCK(get_uptime);
+ NS_MOCK(get_bytes_read);
+ NS_MOCK(get_bytes_written);
+ NS_MOCK(logv);
+ NS_MOCK(server_mode);
+ NS_MOCK(get_or_state);
+ NS_MOCK(accounting_is_enabled);
+ NS_MOCK(accounting_get_end_time);
+
+ log_global_min_severity_ = LOG_DEBUG;
+
+ expected = 0;
+ actual = log_heartbeat(0);
+
+ tt_int_op(actual, ==, expected);
+ tt_int_op(CALLED(logv), ==, 2);
+
+ done:
+ NS_UNMOCK(tls_get_write_overhead_ratio);
+ NS_UNMOCK(we_are_hibernating);
+ NS_UNMOCK(get_options);
+ NS_UNMOCK(public_server_mode);
+ NS_UNMOCK(get_uptime);
+ NS_UNMOCK(get_bytes_read);
+ NS_UNMOCK(get_bytes_written);
+ NS_UNMOCK(logv);
+ NS_UNMOCK(server_mode);
+ NS_UNMOCK(accounting_is_enabled);
+ NS_UNMOCK(accounting_get_end_time);
+ tor_free_(NS(mock_state));
+ tor_free_(NS(mock_options));
+}
+
+static double
+NS(tls_get_write_overhead_ratio)(void)
+{
+ return 1.0;
+}
+
+static int
+NS(we_are_hibernating)(void)
+{
+ return 0;
+}
+
+static const or_options_t *
+NS(get_options)(void)
+{
+ NS(mock_options) = tor_malloc_zero(sizeof(or_options_t));
+ NS(mock_options)->AccountingMax = 0;
+
+ return NS(mock_options);
+}
+
+static int
+NS(public_server_mode)(const or_options_t *options)
+{
+ (void)options;
+
+ return 0;
+}
+
+static long
+NS(get_uptime)(void)
+{
+ return 0;
+}
+
+static uint64_t
+NS(get_bytes_read)(void)
+{
+ return 0;
+}
+
+static uint64_t
+NS(get_bytes_written)(void)
+{
+ return 0;
+}
+
+static void
+NS(logv)(int severity, log_domain_mask_t domain,
+ const char *funcname, const char *suffix, const char *format, va_list ap)
+{
+ switch (CALLED(logv))
+ {
+ case 0:
+ tt_int_op(severity, ==, LOG_NOTICE);
+ tt_int_op(domain, ==, LD_HEARTBEAT);
+ tt_ptr_op(strstr(funcname, "log_heartbeat"), !=, NULL);
+ tt_ptr_op(suffix, ==, NULL);
+ tt_str_op(format, ==,
+ "Heartbeat: Tor's uptime is %s, with %d circuits open. "
+ "I've sent %s and received %s.%s");
+ tt_str_op(va_arg(ap, char *), ==, "0:00 hours"); /* uptime */
+ tt_int_op(va_arg(ap, int), ==, 0); /* count_circuits() */
+ tt_str_op(va_arg(ap, char *), ==, "0 kB"); /* bw_sent */
+ tt_str_op(va_arg(ap, char *), ==, "0 kB"); /* bw_rcvd */
+ tt_str_op(va_arg(ap, char *), ==, ""); /* hibernating */
+ break;
+ case 1:
+ tt_int_op(severity, ==, LOG_NOTICE);
+ tt_int_op(domain, ==, LD_HEARTBEAT);
+ tt_ptr_op(strstr(funcname, "log_accounting"), !=, NULL);
+ tt_ptr_op(suffix, ==, NULL);
+ tt_str_op(format, ==,
+ "Heartbeat: Accounting enabled. Sent: %s / %s, Received: %s / %s. "
+ "The current accounting interval ends on %s, in %s.");
+ tt_str_op(va_arg(ap, char *), ==, "0 kB"); /* acc_sent */
+ tt_str_op(va_arg(ap, char *), ==, "0 kB"); /* acc_max */
+ tt_str_op(va_arg(ap, char *), ==, "0 kB"); /* acc_rcvd */
+ tt_str_op(va_arg(ap, char *), ==, "0 kB"); /* acc_max */
+ /* format_local_iso_time uses local tz, just check mins and secs. */
+ tt_ptr_op(strstr(va_arg(ap, char *), ":01:00"), !=, NULL); /* end_buf */
+ tt_str_op(va_arg(ap, char *), ==, "0:01 hours"); /* remaining */
+ break;
+ default:
+ tt_abort_msg("unexpected call to logv()"); // TODO: prettyprint args
+ break;
+ }
+
+ done:
+ CALLED(logv)++;
+}
+
+static int
+NS(server_mode)(const or_options_t *options)
+{
+ (void)options;
+
+ return 1;
+}
+
+static int
+NS(accounting_is_enabled)(const or_options_t *options)
+{
+ (void)options;
+
+ return 1;
+}
+
+static time_t
+NS(accounting_get_end_time)(void)
+{
+ return 60;
+}
+
+static or_state_t *
+NS(get_or_state)(void)
+{
+ NS(mock_state) = tor_malloc_zero(sizeof(or_state_t));
+ NS(mock_state)->AccountingBytesReadInInterval = 0;
+ NS(mock_state)->AccountingBytesWrittenInInterval = 0;
+
+ return NS(mock_state);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(log_heartbeat, packaged_cell_fullness)
+
+/*
+ * Tests that log_heartbeat() correctly logs packaged cell
+ * fullness information.
+ */
+
+NS_DECL(double, tls_get_write_overhead_ratio, (void));
+NS_DECL(int, we_are_hibernating, (void));
+NS_DECL(const or_options_t *, get_options, (void));
+NS_DECL(int, public_server_mode, (const or_options_t *options));
+NS_DECL(long, get_uptime, (void));
+NS_DECL(uint64_t, get_bytes_read, (void));
+NS_DECL(uint64_t, get_bytes_written, (void));
+NS_DECL(void, logv, (int severity, log_domain_mask_t domain,
+ const char *funcname, const char *suffix, const char *format, va_list ap));
+NS_DECL(int, server_mode, (const or_options_t *options));
+NS_DECL(int, accounting_is_enabled, (const or_options_t *options));
+
+static void
+NS(test_main)(void *arg)
+{
+ int expected, actual;
+ (void)arg;
+
+ NS_MOCK(tls_get_write_overhead_ratio);
+ NS_MOCK(we_are_hibernating);
+ NS_MOCK(get_options);
+ NS_MOCK(public_server_mode);
+ NS_MOCK(get_uptime);
+ NS_MOCK(get_bytes_read);
+ NS_MOCK(get_bytes_written);
+ NS_MOCK(logv);
+ NS_MOCK(server_mode);
+ NS_MOCK(accounting_is_enabled);
+ log_global_min_severity_ = LOG_DEBUG;
+
+ stats_n_data_bytes_packaged = RELAY_PAYLOAD_SIZE;
+ stats_n_data_cells_packaged = 1;
+ expected = 0;
+ actual = log_heartbeat(0);
+
+ tt_int_op(actual, ==, expected);
+ tt_int_op(CALLED(logv), ==, 2);
+
+ done:
+ stats_n_data_bytes_packaged = 0;
+ stats_n_data_cells_packaged = 0;
+ NS_UNMOCK(tls_get_write_overhead_ratio);
+ NS_UNMOCK(we_are_hibernating);
+ NS_UNMOCK(get_options);
+ NS_UNMOCK(public_server_mode);
+ NS_UNMOCK(get_uptime);
+ NS_UNMOCK(get_bytes_read);
+ NS_UNMOCK(get_bytes_written);
+ NS_UNMOCK(logv);
+ NS_UNMOCK(server_mode);
+ NS_UNMOCK(accounting_is_enabled);
+}
+
+static double
+NS(tls_get_write_overhead_ratio)(void)
+{
+ return 1.0;
+}
+
+static int
+NS(we_are_hibernating)(void)
+{
+ return 0;
+}
+
+static const or_options_t *
+NS(get_options)(void)
+{
+ return NULL;
+}
+
+static int
+NS(public_server_mode)(const or_options_t *options)
+{
+ (void)options;
+
+ return 0;
+}
+
+static long
+NS(get_uptime)(void)
+{
+ return 0;
+}
+
+static uint64_t
+NS(get_bytes_read)(void)
+{
+ return 0;
+}
+
+static uint64_t
+NS(get_bytes_written)(void)
+{
+ return 0;
+}
+
+static void
+NS(logv)(int severity, log_domain_mask_t domain, const char *funcname,
+ const char *suffix, const char *format, va_list ap)
+{
+ switch (CALLED(logv))
+ {
+ case 0:
+ tt_int_op(severity, ==, LOG_NOTICE);
+ tt_int_op(domain, ==, LD_HEARTBEAT);
+ tt_ptr_op(strstr(funcname, "log_heartbeat"), !=, NULL);
+ tt_ptr_op(suffix, ==, NULL);
+ tt_str_op(format, ==,
+ "Heartbeat: Tor's uptime is %s, with %d circuits open. "
+ "I've sent %s and received %s.%s");
+ tt_str_op(va_arg(ap, char *), ==, "0:00 hours"); /* uptime */
+ tt_int_op(va_arg(ap, int), ==, 0); /* count_circuits() */
+ tt_str_op(va_arg(ap, char *), ==, "0 kB"); /* bw_sent */
+ tt_str_op(va_arg(ap, char *), ==, "0 kB"); /* bw_rcvd */
+ tt_str_op(va_arg(ap, char *), ==, ""); /* hibernating */
+ break;
+ case 1:
+ tt_int_op(severity, ==, LOG_NOTICE);
+ tt_int_op(domain, ==, LD_HEARTBEAT);
+ tt_ptr_op(strstr(funcname, "log_heartbeat"), !=, NULL);
+ tt_ptr_op(suffix, ==, NULL);
+ tt_str_op(format, ==,
+ "Average packaged cell fullness: %2.3f%%");
+ tt_int_op(fabs(va_arg(ap, double) - 100.0) <= DBL_EPSILON, ==, 1);
+ break;
+ default:
+ tt_abort_msg("unexpected call to logv()"); // TODO: prettyprint args
+ break;
+ }
+
+ done:
+ CALLED(logv)++;
+}
+
+static int
+NS(server_mode)(const or_options_t *options)
+{
+ (void)options;
+
+ return 0;
+}
+
+static int
+NS(accounting_is_enabled)(const or_options_t *options)
+{
+ (void)options;
+
+ return 0;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(log_heartbeat, tls_write_overhead)
+
+/*
+ * Tests that log_heartbeat() correctly logs the TLS write overhead information
+ * when the TLS write overhead ratio exceeds 1.
+ */
+
+NS_DECL(double, tls_get_write_overhead_ratio, (void));
+NS_DECL(int, we_are_hibernating, (void));
+NS_DECL(const or_options_t *, get_options, (void));
+NS_DECL(int, public_server_mode, (const or_options_t *options));
+NS_DECL(long, get_uptime, (void));
+NS_DECL(uint64_t, get_bytes_read, (void));
+NS_DECL(uint64_t, get_bytes_written, (void));
+NS_DECL(void, logv, (int severity, log_domain_mask_t domain,
+ const char *funcname, const char *suffix, const char *format, va_list ap));
+NS_DECL(int, server_mode, (const or_options_t *options));
+NS_DECL(int, accounting_is_enabled, (const or_options_t *options));
+
+static void
+NS(test_main)(void *arg)
+{
+ int expected, actual;
+ (void)arg;
+
+ NS_MOCK(tls_get_write_overhead_ratio);
+ NS_MOCK(we_are_hibernating);
+ NS_MOCK(get_options);
+ NS_MOCK(public_server_mode);
+ NS_MOCK(get_uptime);
+ NS_MOCK(get_bytes_read);
+ NS_MOCK(get_bytes_written);
+ NS_MOCK(logv);
+ NS_MOCK(server_mode);
+ NS_MOCK(accounting_is_enabled);
+ stats_n_data_cells_packaged = 0;
+ log_global_min_severity_ = LOG_DEBUG;
+
+ expected = 0;
+ actual = log_heartbeat(0);
+
+ tt_int_op(actual, ==, expected);
+ tt_int_op(CALLED(logv), ==, 2);
+
+ done:
+ NS_UNMOCK(tls_get_write_overhead_ratio);
+ NS_UNMOCK(we_are_hibernating);
+ NS_UNMOCK(get_options);
+ NS_UNMOCK(public_server_mode);
+ NS_UNMOCK(get_uptime);
+ NS_UNMOCK(get_bytes_read);
+ NS_UNMOCK(get_bytes_written);
+ NS_UNMOCK(logv);
+ NS_UNMOCK(server_mode);
+ NS_UNMOCK(accounting_is_enabled);
+}
+
+static double
+NS(tls_get_write_overhead_ratio)(void)
+{
+ return 2.0;
+}
+
+static int
+NS(we_are_hibernating)(void)
+{
+ return 0;
+}
+
+static const or_options_t *
+NS(get_options)(void)
+{
+ return NULL;
+}
+
+static int
+NS(public_server_mode)(const or_options_t *options)
+{
+ (void)options;
+
+ return 0;
+}
+
+static long
+NS(get_uptime)(void)
+{
+ return 0;
+}
+
+static uint64_t
+NS(get_bytes_read)(void)
+{
+ return 0;
+}
+
+static uint64_t
+NS(get_bytes_written)(void)
+{
+ return 0;
+}
+
+static void
+NS(logv)(int severity, log_domain_mask_t domain,
+ const char *funcname, const char *suffix, const char *format, va_list ap)
+{
+ switch (CALLED(logv))
+ {
+ case 0:
+ tt_int_op(severity, ==, LOG_NOTICE);
+ tt_int_op(domain, ==, LD_HEARTBEAT);
+ tt_ptr_op(strstr(funcname, "log_heartbeat"), !=, NULL);
+ tt_ptr_op(suffix, ==, NULL);
+ tt_str_op(format, ==,
+ "Heartbeat: Tor's uptime is %s, with %d circuits open. "
+ "I've sent %s and received %s.%s");
+ tt_str_op(va_arg(ap, char *), ==, "0:00 hours"); /* uptime */
+ tt_int_op(va_arg(ap, int), ==, 0); /* count_circuits() */
+ tt_str_op(va_arg(ap, char *), ==, "0 kB"); /* bw_sent */
+ tt_str_op(va_arg(ap, char *), ==, "0 kB"); /* bw_rcvd */
+ tt_str_op(va_arg(ap, char *), ==, ""); /* hibernating */
+ break;
+ case 1:
+ tt_int_op(severity, ==, LOG_NOTICE);
+ tt_int_op(domain, ==, LD_HEARTBEAT);
+ tt_ptr_op(strstr(funcname, "log_heartbeat"), !=, NULL);
+ tt_ptr_op(suffix, ==, NULL);
+ tt_str_op(format, ==, "TLS write overhead: %.f%%");
+ tt_int_op(fabs(va_arg(ap, double) - 100.0) <= DBL_EPSILON, ==, 1);
+ break;
+ default:
+ tt_abort_msg("unexpected call to logv()"); // TODO: prettyprint args
+ break;
+ }
+
+ done:
+ CALLED(logv)++;
+}
+
+static int
+NS(server_mode)(const or_options_t *options)
+{
+ (void)options;
+
+ return 0;
+}
+
+static int
+NS(accounting_is_enabled)(const or_options_t *options)
+{
+ (void)options;
+
+ return 0;
+}
+
+#undef NS_SUBMODULE
+
+struct testcase_t status_tests[] = {
+ TEST_CASE(count_circuits),
+ TEST_CASE(secs_to_uptime),
+ TEST_CASE(bytes_to_usage),
+ TEST_CASE_ASPECT(log_heartbeat, fails),
+ TEST_CASE_ASPECT(log_heartbeat, simple),
+ TEST_CASE_ASPECT(log_heartbeat, not_in_consensus),
+ TEST_CASE_ASPECT(log_heartbeat, calls_log_accounting),
+ TEST_CASE_ASPECT(log_heartbeat, packaged_cell_fullness),
+ TEST_CASE_ASPECT(log_heartbeat, tls_write_overhead),
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_util.c b/src/test/test_util.c
index 65d9d2f87..c7fa14118 100644
--- a/src/test/test_util.c
+++ b/src/test/test_util.c
@@ -4,6 +4,7 @@
/* See LICENSE for licensing information */
#include "orconfig.h"
+#define COMPAT_PRIVATE
#define CONTROL_PRIVATE
#define MEMPOOL_PRIVATE
#define UTIL_PRIVATE
@@ -11,7 +12,9 @@
#include "config.h"
#include "control.h"
#include "test.h"
+#ifdef ENABLE_MEMPOOLS
#include "mempool.h"
+#endif /* ENABLE_MEMPOOLS */
#include "memarea.h"
#ifdef _WIN32
@@ -101,6 +104,107 @@ test_util_read_file_eof_zero_bytes(void *arg)
test_util_read_until_eof_impl("tor_test_fifo_empty", 0, 10000);
}
+/* Test the basic expected behaviour for write_chunks_to_file.
+ * NOTE: This will need to be updated if we ever change the tempfile location
+ * or extension */
+static void
+test_util_write_chunks_to_file(void *arg)
+{
+ char *fname = NULL;
+ char *tempname = NULL;
+ char *str = NULL;
+ int r;
+ struct stat st;
+
+ /* These should be two different sizes to ensure the data is different
+ * between the data file and the temp file's 'known string' */
+ int temp_str_len = 1024;
+ int data_str_len = 512;
+ char *data_str = tor_malloc(data_str_len);
+ char *temp_str = tor_malloc(temp_str_len);
+
+ smartlist_t *chunks = smartlist_new();
+ sized_chunk_t c = {data_str, data_str_len/2};
+ sized_chunk_t c2 = {data_str + data_str_len/2, data_str_len/2};
+ (void)arg;
+
+ crypto_rand(temp_str, temp_str_len);
+ crypto_rand(data_str, data_str_len);
+
+ // Ensure it can write multiple chunks
+
+ smartlist_add(chunks, &c);
+ smartlist_add(chunks, &c2);
+
+ /*
+ * Check if it writes using a tempfile
+ */
+ fname = tor_strdup(get_fname("write_chunks_with_tempfile"));
+ tor_asprintf(&tempname, "%s.tmp", fname);
+
+ // write a known string to a file where the tempfile will be
+ r = write_bytes_to_file(tempname, temp_str, temp_str_len, 1);
+ tt_int_op(r, ==, 0);
+
+ // call write_chunks_to_file
+ r = write_chunks_to_file(fname, chunks, 1, 0);
+ tt_int_op(r, ==, 0);
+
+ // assert the file has been written (expected size)
+ str = read_file_to_str(fname, RFTS_BIN, &st);
+ tt_assert(str != NULL);
+ tt_u64_op((uint64_t)st.st_size, ==, data_str_len);
+ test_mem_op(data_str, ==, str, data_str_len);
+ tor_free(str);
+
+ // assert that the tempfile is removed (should not leave artifacts)
+ str = read_file_to_str(tempname, RFTS_BIN|RFTS_IGNORE_MISSING, &st);
+ tt_assert(str == NULL);
+
+ // Remove old testfile for second test
+ r = unlink(fname);
+ tt_int_op(r, ==, 0);
+ tor_free(fname);
+ tor_free(tempname);
+
+ /*
+ * Check if it skips using a tempfile with flags
+ */
+ fname = tor_strdup(get_fname("write_chunks_with_no_tempfile"));
+ tor_asprintf(&tempname, "%s.tmp", fname);
+
+ // write a known string to a file where the tempfile will be
+ r = write_bytes_to_file(tempname, temp_str, temp_str_len, 1);
+ tt_int_op(r, ==, 0);
+
+ // call write_chunks_to_file with no_tempfile = true
+ r = write_chunks_to_file(fname, chunks, 1, 1);
+ tt_int_op(r, ==, 0);
+
+ // assert the file has been written (expected size)
+ str = read_file_to_str(fname, RFTS_BIN, &st);
+ tt_assert(str != NULL);
+ tt_u64_op((uint64_t)st.st_size, ==, data_str_len);
+ test_mem_op(data_str, ==, str, data_str_len);
+ tor_free(str);
+
+ // assert the tempfile still contains the known string
+ str = read_file_to_str(tempname, RFTS_BIN, &st);
+ tt_assert(str != NULL);
+ tt_u64_op((uint64_t)st.st_size, ==, temp_str_len);
+ test_mem_op(temp_str, ==, str, temp_str_len);
+
+ done:
+ unlink(fname);
+ unlink(tempname);
+ smartlist_free(chunks);
+ tor_free(fname);
+ tor_free(tempname);
+ tor_free(str);
+ tor_free(data_str);
+ tor_free(temp_str);
+}
+
static void
test_util_time(void)
{
@@ -242,7 +346,7 @@ test_util_time(void)
tv.tv_sec = (time_t)1326296338;
tv.tv_usec = 3060;
- format_iso_time(timestr, tv.tv_sec);
+ format_iso_time(timestr, (time_t)tv.tv_sec);
test_streq("2012-01-11 15:38:58", timestr);
/* The output of format_local_iso_time will vary by timezone, and setting
our timezone for testing purposes would be a nontrivial flaky pain.
@@ -250,7 +354,7 @@ test_util_time(void)
format_local_iso_time(timestr, tv.tv_sec);
test_streq("2012-01-11 10:38:58", timestr);
*/
- format_iso_time_nospace(timestr, tv.tv_sec);
+ format_iso_time_nospace(timestr, (time_t)tv.tv_sec);
test_streq("2012-01-11T15:38:58", timestr);
test_eq(strlen(timestr), ISO_TIME_LEN);
format_iso_time_nospace_usec(timestr, &tv);
@@ -796,6 +900,64 @@ test_util_expand_filename(void)
}
#endif
+/** Test tor_escape_str_for_pt_args(). */
+static void
+test_util_escape_string_socks(void)
+{
+ char *escaped_string = NULL;
+
+ /** Simple backslash escape. */
+ escaped_string = tor_escape_str_for_pt_args("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_pt_args("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_pt_args("", ";\\");
+ test_assert(escaped_string);
+ test_streq(escaped_string, "");
+ tor_free(escaped_string);
+
+ /** Escape all characters. */
+ escaped_string = tor_escape_str_for_pt_args(";\\;\\", ";\\");
+ test_assert(escaped_string);
+ test_streq(escaped_string, "\\;\\\\\\;\\\\");
+ tor_free(escaped_string);
+
+ escaped_string = tor_escape_str_for_pt_args(";", ";\\");
+ 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)
@@ -867,6 +1029,8 @@ test_util_strmisc(void)
test_eq(0L, tor_parse_long("10",-2,0,100,NULL,NULL));
test_eq(68284L, tor_parse_long("10abc",16,0,70000,NULL,NULL));
test_eq(68284L, tor_parse_long("10ABC",16,0,70000,NULL,NULL));
+ test_eq(0, tor_parse_long("10ABC",-1,0,70000,&i,NULL));
+ test_eq(i, 0);
/* Test parse_ulong */
test_eq(0UL, tor_parse_ulong("",10,0,100,NULL,NULL));
@@ -878,6 +1042,8 @@ test_util_strmisc(void)
test_eq(0UL, tor_parse_ulong("8",8,0,100,NULL,NULL));
test_eq(50UL, tor_parse_ulong("50",10,50,100,NULL,NULL));
test_eq(0UL, tor_parse_ulong("-50",10,-100,100,NULL,NULL));
+ test_eq(0UL, tor_parse_ulong("50",-1,50,100,&i,NULL));
+ test_eq(0, i);
/* Test parse_uint64 */
test_assert(U64_LITERAL(10) == tor_parse_uint64("10 x",10,0,100, &i, &cp));
@@ -890,6 +1056,9 @@ test_util_strmisc(void)
test_assert(U64_LITERAL(0) ==
tor_parse_uint64("12345678901",10,500,INT32_MAX, &i, &cp));
test_eq(0, i);
+ test_assert(U64_LITERAL(0) ==
+ tor_parse_uint64("123",-1,0,INT32_MAX, &i, &cp));
+ test_eq(0, i);
{
/* Test parse_double */
@@ -923,7 +1092,7 @@ test_util_strmisc(void)
test_eq(i, 0);
test_eq(0UL, tor_parse_ulong(TOOBIG, 10, 0, ULONG_MAX, &i, NULL));
test_eq(i, 0);
- test_eq(U64_LITERAL(0), tor_parse_uint64(TOOBIG, 10,
+ tt_u64_op(U64_LITERAL(0), ==, tor_parse_uint64(TOOBIG, 10,
0, UINT64_MAX, &i, NULL));
test_eq(i, 0);
}
@@ -1022,19 +1191,19 @@ test_util_strmisc(void)
}
/* Test str-foo functions */
- cp = tor_strdup("abcdef");
- test_assert(tor_strisnonupper(cp));
- cp[3] = 'D';
- test_assert(!tor_strisnonupper(cp));
- tor_strupper(cp);
- test_streq(cp, "ABCDEF");
- tor_strlower(cp);
- test_streq(cp, "abcdef");
- test_assert(tor_strisnonupper(cp));
- test_assert(tor_strisprint(cp));
- cp[3] = 3;
- test_assert(!tor_strisprint(cp));
- tor_free(cp);
+ cp_tmp = tor_strdup("abcdef");
+ test_assert(tor_strisnonupper(cp_tmp));
+ cp_tmp[3] = 'D';
+ test_assert(!tor_strisnonupper(cp_tmp));
+ tor_strupper(cp_tmp);
+ test_streq(cp_tmp, "ABCDEF");
+ tor_strlower(cp_tmp);
+ test_streq(cp_tmp, "abcdef");
+ test_assert(tor_strisnonupper(cp_tmp));
+ test_assert(tor_strisprint(cp_tmp));
+ cp_tmp[3] = 3;
+ test_assert(!tor_strisprint(cp_tmp));
+ tor_free(cp_tmp);
/* Test memmem and memstr */
{
@@ -1045,6 +1214,10 @@ test_util_strmisc(void)
test_assert(!tor_memmem(haystack, 4, "cde", 3));
haystack = "ababcad";
test_eq_ptr(tor_memmem(haystack, 7, "abc", 3), haystack + 2);
+ test_eq_ptr(tor_memmem(haystack, 7, "ad", 2), haystack + 5);
+ test_eq_ptr(tor_memmem(haystack, 7, "cad", 3), haystack + 4);
+ test_assert(!tor_memmem(haystack, 7, "dadad", 5));
+ test_assert(!tor_memmem(haystack, 7, "abcdefghij", 10));
/* memstr */
test_eq_ptr(tor_memstr(haystack, 7, "abc"), haystack + 2);
test_eq_ptr(tor_memstr(haystack, 7, "cad"), haystack + 4);
@@ -1117,21 +1290,21 @@ test_util_pow2(void)
test_eq(tor_log2(UINT64_MAX), 63);
/* Test round_to_power_of_2 */
- test_eq(round_to_power_of_2(120), 128);
- test_eq(round_to_power_of_2(128), 128);
- test_eq(round_to_power_of_2(130), 128);
- test_eq(round_to_power_of_2(U64_LITERAL(40000000000000000)),
- U64_LITERAL(1)<<55);
- test_eq(round_to_power_of_2(U64_LITERAL(0xffffffffffffffff)),
+ tt_u64_op(round_to_power_of_2(120), ==, 128);
+ tt_u64_op(round_to_power_of_2(128), ==, 128);
+ tt_u64_op(round_to_power_of_2(130), ==, 128);
+ tt_u64_op(round_to_power_of_2(U64_LITERAL(40000000000000000)), ==,
+ U64_LITERAL(1)<<55);
+ tt_u64_op(round_to_power_of_2(U64_LITERAL(0xffffffffffffffff)), ==,
U64_LITERAL(1)<<63);
- test_eq(round_to_power_of_2(0), 1);
- test_eq(round_to_power_of_2(1), 1);
- test_eq(round_to_power_of_2(2), 2);
- test_eq(round_to_power_of_2(3), 2);
- test_eq(round_to_power_of_2(4), 4);
- test_eq(round_to_power_of_2(5), 4);
- test_eq(round_to_power_of_2(6), 4);
- test_eq(round_to_power_of_2(7), 8);
+ tt_u64_op(round_to_power_of_2(0), ==, 1);
+ tt_u64_op(round_to_power_of_2(1), ==, 1);
+ tt_u64_op(round_to_power_of_2(2), ==, 2);
+ tt_u64_op(round_to_power_of_2(3), ==, 2);
+ tt_u64_op(round_to_power_of_2(4), ==, 4);
+ tt_u64_op(round_to_power_of_2(5), ==, 4);
+ tt_u64_op(round_to_power_of_2(6), ==, 4);
+ tt_u64_op(round_to_power_of_2(7), ==, 8);
done:
;
@@ -1410,14 +1583,14 @@ test_util_mmap(void)
test_eq(mapping->size, strlen("Short file."));
test_streq(mapping->data, "Short file.");
#ifdef _WIN32
- tor_munmap_file(mapping);
+ tt_int_op(0, ==, tor_munmap_file(mapping));
mapping = NULL;
test_assert(unlink(fname1) == 0);
#else
/* make sure we can unlink. */
test_assert(unlink(fname1) == 0);
test_streq(mapping->data, "Short file.");
- tor_munmap_file(mapping);
+ tt_int_op(0, ==, tor_munmap_file(mapping));
mapping = NULL;
#endif
@@ -1438,7 +1611,7 @@ test_util_mmap(void)
test_assert(mapping);
test_eq(mapping->size, buflen);
test_memeq(mapping->data, buf, buflen);
- tor_munmap_file(mapping);
+ tt_int_op(0, ==, tor_munmap_file(mapping));
mapping = NULL;
/* Now try a big aligned file. */
@@ -1447,7 +1620,7 @@ test_util_mmap(void)
test_assert(mapping);
test_eq(mapping->size, 16384);
test_memeq(mapping->data, buf, 16384);
- tor_munmap_file(mapping);
+ tt_int_op(0, ==, tor_munmap_file(mapping));
mapping = NULL;
done:
@@ -1460,8 +1633,7 @@ test_util_mmap(void)
tor_free(fname3);
tor_free(buf);
- if (mapping)
- tor_munmap_file(mapping);
+ tor_munmap_file(mapping);
}
/** Run unit tests for escaping/unescaping data for use by controllers. */
@@ -1729,6 +1901,8 @@ test_util_path_is_relative(void)
;
}
+#ifdef ENABLE_MEMPOOLS
+
/** Run unittests for memory pool allocator */
static void
test_util_mempool(void)
@@ -1787,6 +1961,8 @@ test_util_mempool(void)
mp_pool_destroy(pool);
}
+#endif /* ENABLE_MEMPOOLS */
+
/** Run unittests for memory area allocator */
static void
test_util_memarea(void)
@@ -2071,18 +2247,21 @@ test_util_asprintf(void *ptr)
test_assert(cp);
test_streq("simple string 100% safe", cp);
test_eq(strlen(cp), r);
+ tor_free(cp);
/* empty string */
r = tor_asprintf(&cp, "%s", "");
test_assert(cp);
test_streq("", cp);
test_eq(strlen(cp), r);
+ tor_free(cp);
/* numbers (%i) */
r = tor_asprintf(&cp, "I like numbers-%2i, %i, etc.", -1, 2);
test_assert(cp);
test_streq("I like numbers--1, 2, etc.", cp);
test_eq(strlen(cp), r);
+ /* don't free cp; next test uses it. */
/* numbers (%d) */
r = tor_asprintf(&cp2, "First=%d, Second=%d", 101, 202);
@@ -2155,6 +2334,8 @@ test_util_listdir(void *ptr)
done:
tor_free(fname1);
tor_free(fname2);
+ tor_free(fname3);
+ tor_free(dir1);
tor_free(dirname);
if (dir_contents) {
SMARTLIST_FOREACH(dir_contents, char *, cp, tor_free(cp));
@@ -2223,6 +2404,7 @@ test_util_load_win_lib(void *ptr)
}
#endif
+#ifndef _WIN32
static void
clear_hex_errno(char *hex_errno)
{
@@ -2267,6 +2449,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
@@ -2568,14 +2751,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;
@@ -2584,6 +2767,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},
@@ -2594,19 +2779,73 @@ 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);
+ 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 for format_hex_number_sigsafe()
+ */
+
+static void
+test_util_format_dec_number(void *ptr)
+{
+ int i, len;
+ char buf[33];
+ const struct {
+ const char *str;
+ unsigned int x;
+ } test_data[] = {
+ {"0", 0},
+ {"1", 1},
+ {"1234", 1234},
+ {"12345678", 12345678},
+ {"99999999", 99999999},
+ {"100000000", 100000000},
+ {"4294967295", 4294967295u},
+#if UINT_MAX > 0xffffffff
+ {"18446744073709551615", 18446744073709551615u },
+#endif
+ {NULL, 0}
+ };
+
+ (void)ptr;
+
+ for (i = 0; test_data[i].str != NULL; ++i) {
+ len = format_dec_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);
+
+ len = format_dec_number_sigsafe(test_data[i].x, buf,
+ (int)(strlen(test_data[i].str) + 1));
+ test_eq(len, strlen(buf));
test_streq(buf, test_data[i].str);
}
+ test_eq(4, format_dec_number_sigsafe(7331, buf, 5));
+ test_streq(buf, "7331");
+ test_eq(0, format_dec_number_sigsafe(7331, buf, 4));
+ test_eq(1, format_dec_number_sigsafe(0, buf, 2));
+ test_eq(0, format_dec_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)
@@ -2817,7 +3056,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));
@@ -2832,14 +3071,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,
@@ -2847,7 +3086,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)));
@@ -2856,7 +3095,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));
@@ -2866,28 +3105,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));
@@ -2913,6 +3152,8 @@ smartlist_new_from_text_lines(const char *lines)
last_line = smartlist_pop_last(sl);
if (last_line != NULL && *last_line != '\0') {
smartlist_add(sl, last_line);
+ } else {
+ tor_free(last_line);
}
return sl;
@@ -3212,12 +3453,204 @@ 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 }
#define UTIL_TEST(name, flags) \
{ #name, test_util_ ## name, flags, NULL, NULL }
+#ifdef FD_CLOEXEC
+#define CAN_CHECK_CLOEXEC
+static int
+fd_is_cloexec(tor_socket_t fd)
+{
+ int flags = fcntl(fd, F_GETFD, 0);
+ return (flags & FD_CLOEXEC) == FD_CLOEXEC;
+}
+#endif
+
+#ifndef _WIN32
+#define CAN_CHECK_NONBLOCK
+static int
+fd_is_nonblocking(tor_socket_t fd)
+{
+ int flags = fcntl(fd, F_GETFL, 0);
+ return (flags & O_NONBLOCK) == O_NONBLOCK;
+}
+#endif
+
+static void
+test_util_socket(void *arg)
+{
+ tor_socket_t fd1 = TOR_INVALID_SOCKET;
+ tor_socket_t fd2 = TOR_INVALID_SOCKET;
+ tor_socket_t fd3 = TOR_INVALID_SOCKET;
+ tor_socket_t fd4 = TOR_INVALID_SOCKET;
+ int n = get_n_open_sockets();
+
+ TT_BLATHER(("Starting with %d open sockets.", n));
+
+ (void)arg;
+
+ fd1 = tor_open_socket_with_extensions(AF_INET, SOCK_STREAM, 0, 0, 0);
+ fd2 = tor_open_socket_with_extensions(AF_INET, SOCK_STREAM, 0, 0, 1);
+ tt_assert(SOCKET_OK(fd1));
+ tt_assert(SOCKET_OK(fd2));
+ tt_int_op(get_n_open_sockets(), ==, n + 2);
+ //fd3 = tor_open_socket_with_extensions(AF_INET, SOCK_STREAM, 0, 1, 0);
+ //fd4 = tor_open_socket_with_extensions(AF_INET, SOCK_STREAM, 0, 1, 1);
+ fd3 = tor_open_socket(AF_INET, SOCK_STREAM, 0);
+ fd4 = tor_open_socket_nonblocking(AF_INET, SOCK_STREAM, 0);
+ tt_assert(SOCKET_OK(fd3));
+ tt_assert(SOCKET_OK(fd4));
+ tt_int_op(get_n_open_sockets(), ==, n + 4);
+
+#ifdef CAN_CHECK_CLOEXEC
+ tt_int_op(fd_is_cloexec(fd1), ==, 0);
+ tt_int_op(fd_is_cloexec(fd2), ==, 0);
+ tt_int_op(fd_is_cloexec(fd3), ==, 1);
+ tt_int_op(fd_is_cloexec(fd4), ==, 1);
+#endif
+#ifdef CAN_CHECK_NONBLOCK
+ tt_int_op(fd_is_nonblocking(fd1), ==, 0);
+ tt_int_op(fd_is_nonblocking(fd2), ==, 1);
+ tt_int_op(fd_is_nonblocking(fd3), ==, 0);
+ tt_int_op(fd_is_nonblocking(fd4), ==, 1);
+#endif
+
+ tor_close_socket(fd1);
+ tor_close_socket(fd2);
+ fd1 = fd2 = TOR_INVALID_SOCKET;
+ tt_int_op(get_n_open_sockets(), ==, n + 2);
+ tor_close_socket(fd3);
+ tor_close_socket(fd4);
+ fd3 = fd4 = TOR_INVALID_SOCKET;
+ tt_int_op(get_n_open_sockets(), ==, n);
+
+ done:
+ if (SOCKET_OK(fd1))
+ tor_close_socket(fd1);
+ if (SOCKET_OK(fd2))
+ tor_close_socket(fd2);
+ if (SOCKET_OK(fd3))
+ tor_close_socket(fd3);
+ if (SOCKET_OK(fd4))
+ tor_close_socket(fd4);
+}
+
+static void *
+socketpair_test_setup(const struct testcase_t *testcase)
+{
+ return testcase->setup_data;
+}
+static int
+socketpair_test_cleanup(const struct testcase_t *testcase, void *ptr)
+{
+ (void)testcase;
+ (void)ptr;
+ return 1;
+}
+
+static const struct testcase_setup_t socketpair_setup = {
+ socketpair_test_setup, socketpair_test_cleanup
+};
+
+/* Test for socketpair and ersatz_socketpair(). We test them both, since
+ * the latter is a tolerably good way to exersize tor_accept_socket(). */
+static void
+test_util_socketpair(void *arg)
+{
+ const int ersatz = !strcmp(arg, "1");
+ int (*const tor_socketpair_fn)(int, int, int, tor_socket_t[2]) =
+ ersatz ? tor_ersatz_socketpair : tor_socketpair;
+ int n = get_n_open_sockets();
+ tor_socket_t fds[2] = {TOR_INVALID_SOCKET, TOR_INVALID_SOCKET};
+ const int family = AF_UNIX;
+
+ tt_int_op(0, ==, tor_socketpair_fn(family, SOCK_STREAM, 0, fds));
+ tt_assert(SOCKET_OK(fds[0]));
+ tt_assert(SOCKET_OK(fds[1]));
+ tt_int_op(get_n_open_sockets(), ==, n + 2);
+#ifdef CAN_CHECK_CLOEXEC
+ tt_int_op(fd_is_cloexec(fds[0]), ==, 1);
+ tt_int_op(fd_is_cloexec(fds[1]), ==, 1);
+#endif
+#ifdef CAN_CHECK_NONBLOCK
+ tt_int_op(fd_is_nonblocking(fds[0]), ==, 0);
+ tt_int_op(fd_is_nonblocking(fds[1]), ==, 0);
+#endif
+
+ done:
+ if (SOCKET_OK(fds[0]))
+ tor_close_socket(fds[0]);
+ if (SOCKET_OK(fds[1]))
+ tor_close_socket(fds[1]);
+}
+
+static void
+test_util_max_mem(void *arg)
+{
+ size_t memory1, memory2;
+ int r, r2;
+ (void) arg;
+
+ r = get_total_system_memory(&memory1);
+ r2 = get_total_system_memory(&memory2);
+ tt_int_op(r, ==, r2);
+ tt_uint_op(memory2, ==, memory1);
+
+ TT_BLATHER(("System memory: "U64_FORMAT, U64_PRINTF_ARG(memory1)));
+
+ if (r==0) {
+ /* You have at least a megabyte. */
+ tt_uint_op(memory1, >, (1<<20));
+ } else {
+ /* You do not have a petabyte. */
+#if SIZEOF_SIZE_T == SIZEOF_UINT64_T
+ tt_uint_op(memory1, <, (U64_LITERAL(1)<<50));
+#endif
+ }
+
+ done:
+ ;
+}
+
struct testcase_t util_tests[] = {
UTIL_LEGACY(time),
UTIL_TEST(parse_http_time, 0),
@@ -3228,11 +3661,15 @@ 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),
UTIL_LEGACY(datadir),
+#ifdef ENABLE_MEMPOOLS
UTIL_LEGACY(mempool),
+#endif
UTIL_LEGACY(memarea),
UTIL_LEGACY(control_formats),
UTIL_LEGACY(mmap),
@@ -3241,6 +3678,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),
@@ -3249,14 +3688,15 @@ 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),
UTIL_TEST(spawn_background_fail, 0),
UTIL_TEST(spawn_background_partial_read, 0),
UTIL_TEST(format_hex_number, 0),
+ UTIL_TEST(format_dec_number, 0),
UTIL_TEST(join_win_cmdline, 0),
UTIL_TEST(split_lines, 0),
UTIL_TEST(n_bits_set, 0),
@@ -3268,8 +3708,15 @@ struct testcase_t util_tests[] = {
UTIL_TEST(read_file_eof_tiny_limit, 0),
UTIL_TEST(read_file_eof_two_loops, 0),
UTIL_TEST(read_file_eof_zero_bytes, 0),
+ UTIL_TEST(write_chunks_to_file, 0),
UTIL_TEST(mathlog, 0),
UTIL_TEST(weak_random, 0),
+ UTIL_TEST(socket, TT_FORK),
+ { "socketpair", test_util_socketpair, TT_FORK, &socketpair_setup,
+ (void*)"0" },
+ { "socketpair_ersatz", test_util_socketpair, TT_FORK,
+ &socketpair_setup, (void*)"1" },
+ UTIL_TEST(max_mem, 0),
END_OF_TESTCASES
};