aboutsummaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
Diffstat (limited to 'src/test')
-rw-r--r--src/test/Makefile.am49
-rw-r--r--src/test/Makefile.nmake24
-rw-r--r--src/test/bench.c264
-rw-r--r--src/test/include.am68
-rw-r--r--src/test/ntor_ref.py387
-rw-r--r--src/test/test-child.c2
-rw-r--r--src/test/test.c342
-rw-r--r--src/test/test.h10
-rw-r--r--src/test/test_addr.c260
-rw-r--r--src/test/test_cell_formats.c888
-rw-r--r--src/test/test_config.c11
-rw-r--r--src/test/test_containers.c241
-rw-r--r--src/test/test_crypto.c332
-rw-r--r--src/test/test_data.c2
-rw-r--r--src/test/test_dir.c1452
-rw-r--r--src/test/test_introduce.c528
-rw-r--r--src/test/test_microdesc.c63
-rw-r--r--src/test/test_ntor_cl.c170
-rw-r--r--src/test/test_pt.c2
-rw-r--r--src/test/test_replay.c178
-rw-r--r--src/test/test_util.c452
-rw-r--r--src/test/tinytest.c387
-rw-r--r--src/test/tinytest.h87
-rw-r--r--src/test/tinytest_demo.c215
-rw-r--r--src/test/tinytest_macros.h184
25 files changed, 5076 insertions, 1522 deletions
diff --git a/src/test/Makefile.am b/src/test/Makefile.am
deleted file mode 100644
index 31a464ee7..000000000
--- a/src/test/Makefile.am
+++ /dev/null
@@ -1,49 +0,0 @@
-TESTS = test
-
-noinst_PROGRAMS = test test-child bench
-
-AM_CPPFLAGS = -DSHARE_DATADIR="\"$(datadir)\"" \
- -DLOCALSTATEDIR="\"$(localstatedir)\"" \
- -DBINDIR="\"$(bindir)\"" \
- -I"$(top_srcdir)/src/or"
-
-# -L flags need to go in LDFLAGS. -l flags need to go in LDADD.
-# This seems to matter nowhere but on Windows, but I assure you that it
-# matters a lot there, and is quite hard to debug if you forget to do it.
-
-test_SOURCES = \
- test.c \
- test_addr.c \
- test_containers.c \
- test_crypto.c \
- test_data.c \
- test_dir.c \
- test_microdesc.c \
- test_pt.c \
- test_util.c \
- test_config.c \
- tinytest.c
-
-bench_SOURCES = \
- bench.c
-
-test_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \
- @TOR_LDFLAGS_libevent@
-test_LDADD = ../or/libtor.a ../common/libor.a ../common/libor-crypto.a \
- ../common/libor-event.a \
- @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
- @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@
-
-bench_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \
- @TOR_LDFLAGS_libevent@
-bench_LDADD = ../or/libtor.a ../common/libor.a ../common/libor-crypto.a \
- ../common/libor-event.a \
- @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
- @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@
-
-noinst_HEADERS = \
- tinytest.h \
- tinytest_macros.h \
- test.h
-
-
diff --git a/src/test/Makefile.nmake b/src/test/Makefile.nmake
index aec477cf9..562c8df8b 100644
--- a/src/test/Makefile.nmake
+++ b/src/test/Makefile.nmake
@@ -1,20 +1,32 @@
-all: test.exe
+all: test.exe test-child.exe bench.exe
-CFLAGS = /I ..\win32 /I ..\..\..\build-alpha\include /I ..\common /I ..\or
+CFLAGS = /I ..\win32 /I ..\..\..\build-alpha\include /I ..\common /I ..\or \
+ /I ..\ext
LIBS = ..\..\..\build-alpha\lib\libevent.lib \
..\..\..\build-alpha\lib\libcrypto.lib \
..\..\..\build-alpha\lib\libssl.lib \
..\..\..\build-alpha\lib\libz.lib \
..\or\libtor.lib \
- ws2_32.lib advapi32.lib shell32.lib
+ ws2_32.lib advapi32.lib shell32.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 tinytest.obj
+ test_pt.obj test_util.obj test_config.obj test_cell_formats.obj \
+ test_replay.obj test_introduce.obj tinytest.obj
+
+tinytest.obj: ..\ext\tinytest.c
+ $(CC) $(CFLAGS) /D snprintf=_snprintf /c ..\ext\tinytest.c
test.exe: $(TEST_OBJECTS)
- $(CC) $(CFLAGS) $(LIBS) ..\common\*.lib $(TEST_OBJECTS)
+ $(CC) $(CFLAGS) $(LIBS) ..\common\*.lib $(TEST_OBJECTS) /Fe$@
+
+bench.exe: bench.obj
+ $(CC) $(CFLAGS) bench.obj $(LIBS) ..\common\*.lib /Fe$@
+
+test-child.exe: test-child.obj
+ $(CC) $(CFLAGS) test-child.obj /Fe$@
clean:
- del $(TEST_OBJECTS) *.lib test.exe
+ del *.obj *.lib test.exe bench.exe test-child.exe
diff --git a/src/test/bench.c b/src/test/bench.c
index 3eae532d3..706b8bc7f 100644
--- a/src/test/bench.c
+++ b/src/test/bench.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/* Ordinarily defined in tor_main.c; this bit is just here to provide one
@@ -15,9 +15,24 @@ const char tor_git_revision[] = "";
#include "orconfig.h"
#define RELAY_PRIVATE
+#define CONFIG_PRIVATE
#include "or.h"
+#include "onion_tap.h"
#include "relay.h"
+#include <openssl/opensslv.h>
+#include <openssl/evp.h>
+#ifndef OPENSSL_NO_EC
+#include <openssl/ec.h>
+#include <openssl/ecdh.h>
+#include <openssl/obj_mac.h>
+#endif
+
+#include "config.h"
+#ifdef CURVE25519_ENABLED
+#include "crypto_curve25519.h"
+#include "onion_ntor.h"
+#endif
#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_PROCESS_CPUTIME_ID)
static uint64_t nanostart;
@@ -97,6 +112,131 @@ bench_aes(void)
}
static void
+bench_onion_TAP(void)
+{
+ const int iters = 1<<9;
+ int i;
+ crypto_pk_t *key, *key2;
+ uint64_t start, end;
+ char os[TAP_ONIONSKIN_CHALLENGE_LEN];
+ char or[TAP_ONIONSKIN_REPLY_LEN];
+ crypto_dh_t *dh_out;
+
+ key = crypto_pk_new();
+ key2 = crypto_pk_new();
+ if (crypto_pk_generate_key_with_bits(key, 1024) < 0)
+ goto done;
+ if (crypto_pk_generate_key_with_bits(key2, 1024) < 0)
+ goto done;
+
+ reset_perftime();
+ start = perftime();
+ for (i = 0; i < iters; ++i) {
+ onion_skin_TAP_create(key, &dh_out, os);
+ crypto_dh_free(dh_out);
+ }
+ end = perftime();
+ printf("Client-side, part 1: %f usec.\n", NANOCOUNT(start, end, iters)/1e3);
+
+ onion_skin_TAP_create(key, &dh_out, os);
+ start = perftime();
+ for (i = 0; i < iters; ++i) {
+ char key_out[CPATH_KEY_MATERIAL_LEN];
+ onion_skin_TAP_server_handshake(os, key, NULL, or,
+ key_out, sizeof(key_out));
+ }
+ end = perftime();
+ printf("Server-side, key guessed right: %f usec\n",
+ NANOCOUNT(start, end, iters)/1e3);
+
+ start = perftime();
+ for (i = 0; i < iters; ++i) {
+ char key_out[CPATH_KEY_MATERIAL_LEN];
+ onion_skin_TAP_server_handshake(os, key2, key, or,
+ key_out, sizeof(key_out));
+ }
+ end = perftime();
+ printf("Server-side, key guessed wrong: %f usec.\n",
+ NANOCOUNT(start, end, iters)/1e3);
+
+ start = perftime();
+ for (i = 0; i < iters; ++i) {
+ crypto_dh_t *dh;
+ char key_out[CPATH_KEY_MATERIAL_LEN];
+ int s;
+ dh = crypto_dh_dup(dh_out);
+ s = onion_skin_TAP_client_handshake(dh, or, key_out, sizeof(key_out));
+ crypto_dh_free(dh);
+ tor_assert(s == 0);
+ }
+ end = perftime();
+ printf("Client-side, part 2: %f usec.\n",
+ NANOCOUNT(start, end, iters)/1e3);
+
+ done:
+ crypto_pk_free(key);
+ crypto_pk_free(key2);
+}
+
+#ifdef CURVE25519_ENABLED
+static void
+bench_onion_ntor(void)
+{
+ const int iters = 1<<10;
+ int i;
+ curve25519_keypair_t keypair1, keypair2;
+ uint64_t start, end;
+ uint8_t os[NTOR_ONIONSKIN_LEN];
+ uint8_t or[NTOR_REPLY_LEN];
+ ntor_handshake_state_t *state = NULL;
+ uint8_t nodeid[DIGEST_LEN];
+ di_digest256_map_t *keymap = NULL;
+
+ curve25519_secret_key_generate(&keypair1.seckey, 0);
+ curve25519_public_key_generate(&keypair1.pubkey, &keypair1.seckey);
+ curve25519_secret_key_generate(&keypair2.seckey, 0);
+ curve25519_public_key_generate(&keypair2.pubkey, &keypair2.seckey);
+ dimap_add_entry(&keymap, keypair1.pubkey.public_key, &keypair1);
+ dimap_add_entry(&keymap, keypair2.pubkey.public_key, &keypair2);
+
+ reset_perftime();
+ start = perftime();
+ for (i = 0; i < iters; ++i) {
+ onion_skin_ntor_create(nodeid, &keypair1.pubkey, &state, os);
+ ntor_handshake_state_free(state);
+ }
+ end = perftime();
+ printf("Client-side, part 1: %f usec.\n", NANOCOUNT(start, end, iters)/1e3);
+
+ state = NULL;
+ onion_skin_ntor_create(nodeid, &keypair1.pubkey, &state, os);
+ start = perftime();
+ for (i = 0; i < iters; ++i) {
+ uint8_t key_out[CPATH_KEY_MATERIAL_LEN];
+ onion_skin_ntor_server_handshake(os, keymap, NULL, nodeid, or,
+ key_out, sizeof(key_out));
+ }
+ end = perftime();
+ printf("Server-side: %f usec\n",
+ NANOCOUNT(start, end, iters)/1e3);
+
+ start = perftime();
+ for (i = 0; i < iters; ++i) {
+ uint8_t key_out[CPATH_KEY_MATERIAL_LEN];
+ int s;
+ s = onion_skin_ntor_client_handshake(state, or, key_out, sizeof(key_out));
+ tor_assert(s == 0);
+ }
+ end = perftime();
+ printf("Client-side, part 2: %f usec.\n",
+ NANOCOUNT(start, end, iters)/1e3);
+
+ ntor_handshake_state_free(state);
+ dimap_free(keymap, NULL);
+}
+#endif
+
+static void
bench_cell_aes(void)
{
uint64_t start, end;
@@ -175,18 +315,18 @@ bench_dmap(void)
NANOCOUNT(pt3, pt4, iters*elts));
for (i = 0; i < iters; ++i) {
- SMARTLIST_FOREACH(sl, const char *, cp, n += digestset_isin(ds, cp));
- SMARTLIST_FOREACH(sl2, const char *, cp, n += digestset_isin(ds, cp));
+ SMARTLIST_FOREACH(sl, const char *, cp, n += digestset_contains(ds, cp));
+ SMARTLIST_FOREACH(sl2, const char *, cp, n += digestset_contains(ds, cp));
}
end = perftime();
- printf("digestset_isin: %.2f ns per element.\n",
+ printf("digestset_contains: %.2f ns per element.\n",
NANOCOUNT(pt4, end, iters*elts*2));
/* We need to use this, or else the whole loop gets optimized out. */
printf("Hits == %d\n", n);
for (i = 0; i < fpostests; ++i) {
crypto_rand(d, 20);
- if (digestset_isin(ds, d)) ++fp;
+ if (digestset_contains(ds, d)) ++fp;
}
printf("False positive rate on digestset: %.2f%%\n",
(fp/(double)fpostests)*100);
@@ -214,8 +354,8 @@ bench_cell_ops(void)
crypto_rand((char*)cell->payload, sizeof(cell->payload));
/* Mock-up or_circuit_t */
- or_circ->_base.magic = OR_CIRCUIT_MAGIC;
- or_circ->_base.purpose = CIRCUIT_PURPOSE_OR;
+ or_circ->base_.magic = OR_CIRCUIT_MAGIC;
+ or_circ->base_.purpose = CIRCUIT_PURPOSE_OR;
/* Initialize crypto */
or_circ->p_crypto = crypto_cipher_new(NULL);
@@ -248,6 +388,95 @@ bench_cell_ops(void)
tor_free(cell);
}
+static void
+bench_dh(void)
+{
+ const int iters = 1<<10;
+ int i;
+ uint64_t start, end;
+
+ reset_perftime();
+ start = perftime();
+ for (i = 0; i < iters; ++i) {
+ char dh_pubkey_a[DH_BYTES], dh_pubkey_b[DH_BYTES];
+ char secret_a[DH_BYTES], secret_b[DH_BYTES];
+ ssize_t slen_a, slen_b;
+ crypto_dh_t *dh_a = crypto_dh_new(DH_TYPE_TLS);
+ crypto_dh_t *dh_b = crypto_dh_new(DH_TYPE_TLS);
+ crypto_dh_generate_public(dh_a);
+ crypto_dh_generate_public(dh_b);
+ crypto_dh_get_public(dh_a, dh_pubkey_a, sizeof(dh_pubkey_a));
+ crypto_dh_get_public(dh_b, dh_pubkey_b, sizeof(dh_pubkey_b));
+ slen_a = crypto_dh_compute_secret(LOG_NOTICE,
+ dh_a, dh_pubkey_b, sizeof(dh_pubkey_b),
+ secret_a, sizeof(secret_a));
+ slen_b = crypto_dh_compute_secret(LOG_NOTICE,
+ dh_b, dh_pubkey_a, sizeof(dh_pubkey_a),
+ secret_b, sizeof(secret_b));
+ tor_assert(slen_a == slen_b);
+ tor_assert(!memcmp(secret_a, secret_b, slen_a));
+ crypto_dh_free(dh_a);
+ crypto_dh_free(dh_b);
+ }
+ end = perftime();
+ printf("Complete DH handshakes (1024 bit, public and private ops):\n"
+ " %f millisec each.\n", NANOCOUNT(start, end, iters)/1e6);
+}
+
+#if (!defined(OPENSSL_NO_EC) \
+ && OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,0))
+#define HAVE_EC_BENCHMARKS
+static void
+bench_ecdh_impl(int nid, const char *name)
+{
+ const int iters = 1<<10;
+ int i;
+ uint64_t start, end;
+
+ reset_perftime();
+ start = perftime();
+ for (i = 0; i < iters; ++i) {
+ char secret_a[DH_BYTES], secret_b[DH_BYTES];
+ ssize_t slen_a, slen_b;
+ EC_KEY *dh_a = EC_KEY_new_by_curve_name(nid);
+ EC_KEY *dh_b = EC_KEY_new_by_curve_name(nid);
+ if (!dh_a || !dh_b) {
+ puts("Skipping. (No implementation?)");
+ return;
+ }
+
+ EC_KEY_generate_key(dh_a);
+ EC_KEY_generate_key(dh_b);
+ slen_a = ECDH_compute_key(secret_a, DH_BYTES,
+ EC_KEY_get0_public_key(dh_b), dh_a,
+ NULL);
+ slen_b = ECDH_compute_key(secret_b, DH_BYTES,
+ EC_KEY_get0_public_key(dh_a), dh_b,
+ NULL);
+
+ tor_assert(slen_a == slen_b);
+ tor_assert(!memcmp(secret_a, secret_b, slen_a));
+ EC_KEY_free(dh_a);
+ EC_KEY_free(dh_b);
+ }
+ end = perftime();
+ printf("Complete ECDH %s handshakes (2 public and 2 private ops):\n"
+ " %f millisec each.\n", name, NANOCOUNT(start, end, iters)/1e6);
+}
+
+static void
+bench_ecdh_p256(void)
+{
+ bench_ecdh_impl(NID_X9_62_prime256v1, "P-256");
+}
+
+static void
+bench_ecdh_p224(void)
+{
+ bench_ecdh_impl(NID_secp224r1, "P-224");
+}
+#endif
+
typedef void (*bench_fn)(void);
typedef struct benchmark_t {
@@ -261,8 +490,17 @@ typedef struct benchmark_t {
static struct benchmark_t benchmarks[] = {
ENT(dmap),
ENT(aes),
+ ENT(onion_TAP),
+#ifdef CURVE25519_ENABLED
+ ENT(onion_ntor),
+#endif
ENT(cell_aes),
ENT(cell_ops),
+ ENT(dh),
+#ifdef HAVE_EC_BENCHMARKS
+ ENT(ecdh_p256),
+ ENT(ecdh_p224),
+#endif
{NULL,NULL,0}
};
@@ -286,6 +524,8 @@ main(int argc, const char **argv)
int i;
int list=0, n_enabled=0;
benchmark_t *b;
+ char *errmsg;
+ or_options_t *options;
tor_threads_init();
@@ -306,6 +546,16 @@ main(int argc, const char **argv)
reset_perftime();
crypto_seed_rng(1);
+ options = options_new();
+ init_logging();
+ options->command = CMD_RUN_UNITTESTS;
+ options->DataDirectory = tor_strdup("");
+ options_init(options);
+ if (set_options(options, &errmsg) < 0) {
+ printf("Failed to set initial options: %s\n", errmsg);
+ tor_free(errmsg);
+ return 1;
+ }
for (b = benchmarks; b->name; ++b) {
if (b->enabled || n_enabled == 0) {
diff --git a/src/test/include.am b/src/test/include.am
new file mode 100644
index 000000000..112d1a79d
--- /dev/null
+++ b/src/test/include.am
@@ -0,0 +1,68 @@
+TESTS+= src/test/test
+
+noinst_PROGRAMS+= src/test/test src/test/test-child src/test/bench
+
+src_test_AM_CPPFLAGS = -DSHARE_DATADIR="\"$(datadir)\"" \
+ -DLOCALSTATEDIR="\"$(localstatedir)\"" \
+ -DBINDIR="\"$(bindir)\"" \
+ -I"$(top_srcdir)/src/or" -I"$(top_srcdir)/src/ext"
+
+# -L flags need to go in LDFLAGS. -l flags need to go in LDADD.
+# This seems to matter nowhere but on Windows, but I assure you that it
+# matters a lot there, and is quite hard to debug if you forget to do it.
+
+src_test_test_SOURCES = \
+ src/test/test.c \
+ src/test/test_addr.c \
+ src/test/test_cell_formats.c \
+ src/test/test_containers.c \
+ src/test/test_crypto.c \
+ src/test/test_data.c \
+ src/test/test_dir.c \
+ src/test/test_introduce.c \
+ src/test/test_microdesc.c \
+ src/test/test_pt.c \
+ src/test/test_replay.c \
+ src/test/test_util.c \
+ src/test/test_config.c \
+ src/ext/tinytest.c
+
+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 \
+ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
+ @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
+
+src_test_bench_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \
+ @TOR_LDFLAGS_libevent@
+src_test_bench_LDADD = src/or/libtor.a src/common/libor.a \
+ src/common/libor-crypto.a $(LIBDONNA) \
+ src/common/libor-event.a \
+ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
+ @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
+
+noinst_HEADERS+= \
+ src/test/test.h
+
+if CURVE25519_ENABLED
+noinst_PROGRAMS+= src/test/test-ntor-cl
+src_test_test_ntor_cl_SOURCES = src/test/test_ntor_cl.c
+src_test_test_ntor_cl_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@
+src_test_test_ntor_cl_LDADD = src/or/libtor.a src/common/libor.a \
+ src/common/libor-crypto.a $(LIBDONNA) \
+ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \
+ @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
+src_test_test_ntor_cl_AM_CPPFLAGS = \
+ -I"$(top_srcdir)/src/or"
+
+endif
+
diff --git a/src/test/ntor_ref.py b/src/test/ntor_ref.py
new file mode 100644
index 000000000..ade468da7
--- /dev/null
+++ b/src/test/ntor_ref.py
@@ -0,0 +1,387 @@
+# Copyright 2012-2013, The Tor Project, Inc
+# See LICENSE for licensing information
+
+"""
+ntor_ref.py
+
+
+This module is a reference implementation for the "ntor" protocol
+s proposed by Goldberg, Stebila, and Ustaoglu and as instantiated in
+Tor Proposal 216.
+
+It's meant to be used to validate Tor's ntor implementation. It
+requirs the curve25519 python module from the curve25519-donna
+package.
+
+ *** DO NOT USE THIS IN PRODUCTION. ***
+
+commands:
+
+ gen_kdf_vectors: Print out some test vectors for the RFC5869 KDF.
+ timing: Print a little timing information about this implementation's
+ handshake.
+ self-test: Try handshaking with ourself; make sure we can.
+ test-tor: Handshake with tor's ntor implementation via the program
+ src/test/test-ntor-cl; make sure we can.
+
+"""
+
+import binascii
+import curve25519
+import hashlib
+import hmac
+import subprocess
+
+# **********************************************************************
+# Helpers and constants
+
+def HMAC(key,msg):
+ "Return the HMAC-SHA256 of 'msg' using the key 'key'."
+ H = hmac.new(key, "", hashlib.sha256)
+ H.update(msg)
+ return H.digest()
+
+def H(msg,tweak):
+ """Return the hash of 'msg' using tweak 'tweak'. (In this version of ntor,
+ the tweaked hash is just HMAC with the tweak as the key.)"""
+ return HMAC(key=tweak,
+ msg=msg)
+
+def keyid(k):
+ """Return the 32-byte key ID of a public key 'k'. (Since we're
+ using curve25519, we let k be its own keyid.)
+ """
+ return k.serialize()
+
+NODE_ID_LENGTH = 20
+KEYID_LENGTH = 32
+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"
+
+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
+ every time you ask for it.
+ """
+ def __init__(self):
+ curve25519.keys.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)
+
+ return self._memo_public
+
+# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+def kdf_rfc5869(key, salt, info, n):
+
+ prk = HMAC(key=salt, msg=key)
+
+ out = b""
+ last = b""
+ i = 1
+ while len(out) < n:
+ m = last + info + chr(i)
+ last = h = HMAC(key=prk, msg=m)
+ out += h
+ i = i + 1
+ return out[:n]
+
+def kdf_ntor(key, n):
+ return kdf_rfc5869(key, T_KEY, M_EXPAND, n)
+
+# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+def client_part1(node_id, pubkey_B):
+ """Initial handshake, client side.
+
+ From the specification:
+
+ <<To send a create cell, the client generates a keypair x,X =
+ KEYGEN(), and sends a CREATE cell with contents:
+
+ NODEID: ID -- ID_LENGTH bytes
+ KEYID: KEYID(B) -- H_LENGTH bytes
+ CLIENT_PK: X -- G_LENGTH bytes
+ >>
+
+ Takes node_id -- a digest of the server's identity key,
+ pubkey_B -- a public key for the server.
+ Returns a tuple of (client secret key x, client->server message)"""
+
+ assert len(node_id) == NODE_ID_LENGTH
+
+ key_id = keyid(pubkey_B)
+ seckey_x = PrivateKey()
+ pubkey_X = seckey_x.get_public().serialize()
+
+ message = node_id + key_id + pubkey_X
+
+ assert len(message) == NODE_ID_LENGTH + H_LENGTH + H_LENGTH
+ return seckey_x , message
+
+def hash_nil(x):
+ """Identity function: if we don't pass a hash function that does nothing,
+ the curve25519 python lib will try to sha256 it for us."""
+ return x
+
+def bad_result(r):
+ """Helper: given a result of multiplying a public key by a private key,
+ return True iff one of the inputs was broken"""
+ assert len(r) == 32
+ return r == '\x00'*32
+
+def server(seckey_b, my_node_id, message, keyBytes=72):
+ """Handshake step 2, server side.
+
+ From the spec:
+
+ <<
+ The server generates a keypair of y,Y = KEYGEN(), and computes
+
+ secret_input = EXP(X,y) | EXP(X,b) | ID | B | X | Y | PROTOID
+ KEY_SEED = H(secret_input, t_key)
+ verify = H(secret_input, t_verify)
+ auth_input = verify | ID | B | Y | X | PROTOID | "Server"
+
+ The server sends a CREATED cell containing:
+
+ SERVER_PK: Y -- G_LENGTH bytes
+ AUTH: H(auth_input, t_mac) -- H_LENGTH byets
+ >>
+
+ Takes seckey_b -- the server's secret key
+ my_node_id -- the servers's public key digest,
+ message -- a message from a client
+ keybytes -- amount of key material to generate
+
+ Returns a tuple of (key material, sever->client reply), or None on
+ error.
+ """
+
+ assert len(message) == NODE_ID_LENGTH + H_LENGTH + H_LENGTH
+
+ if my_node_id != message[:NODE_ID_LENGTH]:
+ return None
+
+ 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:])
+ seckey_y = PrivateKey()
+ pubkey_Y = seckey_y.get_public()
+ pubkey_B = seckey_b.get_public()
+ xy = seckey_y.get_shared_key(pubkey_X, hash_nil)
+ xb = seckey_b.get_shared_key(pubkey_X, hash_nil)
+
+ # secret_input = EXP(X,y) | EXP(X,b) | ID | B | X | Y | PROTOID
+ secret_input = (xy + xb + my_node_id +
+ pubkey_B.serialize() +
+ pubkey_X.serialize() +
+ pubkey_Y.serialize() +
+ PROTOID)
+
+ verify = H_verify(secret_input)
+
+ # auth_input = verify | ID | B | Y | X | PROTOID | "Server"
+ auth_input = (verify +
+ my_node_id +
+ pubkey_B.serialize() +
+ pubkey_Y.serialize() +
+ pubkey_X.serialize() +
+ PROTOID +
+ "Server")
+
+ msg = pubkey_Y.serialize() + H_mac(auth_input)
+
+ badness += bad_result(xb)
+ badness += bad_result(xy)
+
+ if badness:
+ return None
+
+ keys = kdf_ntor(secret_input, keyBytes)
+
+ return keys, msg
+
+def client_part2(seckey_x, msg, node_id, pubkey_B, keyBytes=72):
+ """Handshake step 3: client side again.
+
+ From the spec:
+
+ <<
+ The client then checks Y is in G^* [see NOTE below], and computes
+
+ secret_input = EXP(Y,x) | EXP(B,x) | ID | B | X | Y | PROTOID
+ KEY_SEED = H(secret_input, t_key)
+ verify = H(secret_input, t_verify)
+ auth_input = verify | ID | B | Y | X | PROTOID | "Server"
+
+ The client verifies that AUTH == H(auth_input, t_mac).
+ >>
+
+ Takes seckey_x -- the secret key we generated in step 1.
+ msg -- the message from the server.
+ node_id -- the node_id we used in step 1.
+ server_key -- the same public key we used in step 1.
+ keyBytes -- the number of bytes we want to generate
+ Returns key material, or None on error
+
+ """
+ assert len(msg) == G_LENGTH + H_LENGTH
+
+ pubkey_Y = curve25519.keys.Public(msg[:G_LENGTH])
+ their_auth = msg[G_LENGTH:]
+
+ pubkey_X = seckey_x.get_public()
+
+ yx = seckey_x.get_shared_key(pubkey_Y, hash_nil)
+ bx = seckey_x.get_shared_key(pubkey_B, hash_nil)
+
+
+ # secret_input = EXP(Y,x) | EXP(B,x) | ID | B | X | Y | PROTOID
+ secret_input = (yx + bx + node_id +
+ pubkey_B.serialize() +
+ pubkey_X.serialize() +
+ pubkey_Y.serialize() + PROTOID)
+
+ verify = H_verify(secret_input)
+
+ # auth_input = verify | ID | B | Y | X | PROTOID | "Server"
+ auth_input = (verify + node_id +
+ pubkey_B.serialize() +
+ pubkey_Y.serialize() +
+ pubkey_X.serialize() + PROTOID +
+ "Server")
+
+ my_auth = H_mac(auth_input)
+
+ badness = my_auth != their_auth
+ badness = bad_result(yx) + bad_result(bx)
+
+ if badness:
+ return None
+
+ return kdf_ntor(secret_input, keyBytes)
+
+# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+def demo(node_id="iToldYouAboutStairs.", server_key=PrivateKey()):
+ """
+ Try to handshake with ourself.
+ """
+ x, create = client_part1(node_id, server_key.get_public())
+ skeys, created = server(server_key, node_id, create)
+ ckeys = client_part2(x, created, node_id, server_key.get_public())
+ assert len(skeys) == 72
+ assert len(ckeys) == 72
+ assert skeys == ckeys
+
+# ======================================================================
+def timing():
+ """
+ Use Python's timeit module to see how fast this nonsense is
+ """
+ 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)
+
+# ======================================================================
+
+def kdf_vectors():
+ """
+ Generate some vectors to check our KDF.
+ """
+ import binascii
+ def kdf_vec(inp):
+ k = kdf(inp, T_KEY, M_EXPAND, 100)
+ 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")
+
+# ======================================================================
+
+
+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
+ dehex=lambda s: binascii.a2b_hex(s.strip())
+
+ PROG = "./src/test/test-ntor-cl"
+ def tor_client1(node_id, pubkey_B):
+ " returns (msg, state) "
+ p = subprocess.Popen([PROG, "client1", enhex(node_id),
+ enhex(pubkey_B.serialize())],
+ stdout=subprocess.PIPE)
+ return map(dehex, p.stdout.readlines())
+ def tor_server1(seckey_b, node_id, msg, n):
+ " returns (msg, keys) "
+ p = subprocess.Popen([PROG, "server1", enhex(seckey_b.serialize()),
+ enhex(node_id), enhex(msg), str(n)],
+ stdout=subprocess.PIPE)
+ return map(dehex, p.stdout.readlines())
+ def tor_client2(state, msg, n):
+ " returns (keys,) "
+ p = subprocess.Popen([PROG, "client2", enhex(state),
+ enhex(msg), str(n)],
+ stdout=subprocess.PIPE)
+ return map(dehex, p.stdout.readlines())
+
+
+ node_id = "thisisatornodeid$#%^"
+ seckey_b = PrivateKey()
+ pubkey_B = seckey_b.get_public()
+
+ # Do a pure-Tor handshake
+ c2s_msg, c_state = tor_client1(node_id, pubkey_B)
+ s2c_msg, s_keys = tor_server1(seckey_b, node_id, c2s_msg, 90)
+ c_keys, = tor_client2(c_state, s2c_msg, 90)
+ assert c_keys == s_keys
+ assert len(c_keys) == 90
+
+ # Try a mixed handshake with Tor as the client
+ c2s_msg, c_state = tor_client1(node_id, pubkey_B)
+ s_keys, s2c_msg = server(seckey_b, node_id, c2s_msg, 90)
+ c_keys, = tor_client2(c_state, s2c_msg, 90)
+ assert c_keys == s_keys
+ assert len(c_keys) == 90
+
+ # Now do a mixed handshake with Tor as the server
+ c_x, c2s_msg = client_part1(node_id, pubkey_B)
+ s2c_msg, s_keys = tor_server1(seckey_b, node_id, c2s_msg, 90)
+ c_keys = client_part2(c_x, s2c_msg, node_id, pubkey_B, 90)
+ assert c_keys == s_keys
+ assert len(c_keys) == 90
+
+ print "We just interoperated."
+
+# ======================================================================
+
+if __name__ == '__main__':
+ import sys
+ if sys.argv[1] == 'gen_kdf_vectors':
+ kdf_vectors()
+ elif sys.argv[1] == 'timing':
+ timing()
+ elif sys.argv[1] == 'self-test':
+ demo()
+ elif sys.argv[1] == 'test-tor':
+ test_tor()
+
+ else:
+ print __doc__
diff --git a/src/test/test-child.c b/src/test/test-child.c
index c5725f1c5..ef10fbb92 100644
--- a/src/test/test-child.c
+++ b/src/test/test-child.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Tor Project, Inc. */
+/* Copyright (c) 2011-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include <stdio.h>
diff --git a/src/test/test.c b/src/test/test.c
index ae423948e..c2911d842 100644
--- a/src/test/test.c
+++ b/src/test/test.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/* Ordinarily defined in tor_main.c; this bit is just here to provide one
@@ -32,7 +32,7 @@ const char tor_git_revision[] = "";
#define CONFIG_PRIVATE
#define GEOIP_PRIVATE
#define ROUTER_PRIVATE
-#define CIRCUIT_PRIVATE
+#define CIRCUITSTATS_PRIVATE
/*
* Linux doesn't provide lround in math.h by default, but mac os does...
@@ -44,7 +44,8 @@ double fabs(double x);
#include "or.h"
#include "buffers.h"
-#include "circuitbuild.h"
+#include "circuitlist.h"
+#include "circuitstats.h"
#include "config.h"
#include "connection_edge.h"
#include "geoip.h"
@@ -54,9 +55,14 @@ double fabs(double x);
#include "mempool.h"
#include "memarea.h"
#include "onion.h"
+#include "onion_tap.h"
+#include "onion_ntor.h"
#include "policies.h"
#include "rephist.h"
#include "routerparse.h"
+#ifdef CURVE25519_ENABLED
+#include "crypto_curve25519.h"
+#endif
#ifdef USE_DMALLOC
#include <dmalloc.h>
@@ -84,8 +90,14 @@ setup_directory(void)
{
static int is_setup = 0;
int r;
+ char rnd[256], rnd32[256];
if (is_setup) return;
+/* Due to base32 limitation needs to be a multiple of 5. */
+#define RAND_PATH_BYTES 5
+ crypto_rand(rnd, RAND_PATH_BYTES);
+ base32_encode(rnd32, sizeof(rnd32), rnd, RAND_PATH_BYTES);
+
#ifdef _WIN32
{
char buf[MAX_PATH];
@@ -94,11 +106,12 @@ setup_directory(void)
if (!GetTempPathA(sizeof(buf),buf))
tmp = "c:\\windows\\temp";
tor_snprintf(temp_dir, sizeof(temp_dir),
- "%s\\tor_test_%d", tmp, (int)getpid());
+ "%s\\tor_test_%d_%s", tmp, (int)getpid(), rnd32);
r = mkdir(temp_dir);
}
#else
- tor_snprintf(temp_dir, sizeof(temp_dir), "/tmp/tor_test_%d", (int) getpid());
+ tor_snprintf(temp_dir, sizeof(temp_dir), "/tmp/tor_test_%d_%s",
+ (int) getpid(), rnd32);
r = mkdir(temp_dir, 0700);
#endif
if (r) {
@@ -352,7 +365,7 @@ test_socks_5_unsupported_commands(void *ptr)
test_eq(5, socks->socks_version);
test_eq(2, socks->replylen);
test_eq(5, socks->reply[0]);
- test_eq(0, socks->reply[1]);
+ 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);
@@ -457,7 +470,7 @@ test_socks_5_no_authenticate(void *ptr)
get_options()->SafeSocks));
test_eq(5, socks->socks_version);
test_eq(2, socks->replylen);
- test_eq(5, socks->reply[0]);
+ test_eq(1, socks->reply[0]);
test_eq(0, socks->reply[1]);
test_eq(2, socks->usernamelen);
@@ -496,7 +509,7 @@ test_socks_5_authenticate(void *ptr)
get_options()->SafeSocks));
test_eq(5, socks->socks_version);
test_eq(2, socks->replylen);
- test_eq(5, socks->reply[0]);
+ test_eq(1, socks->reply[0]);
test_eq(0, socks->reply[1]);
test_eq(2, socks->usernamelen);
@@ -536,7 +549,7 @@ test_socks_5_authenticate_with_data(void *ptr)
get_options()->SafeSocks) == 1);
test_eq(5, socks->socks_version);
test_eq(2, socks->replylen);
- test_eq(5, socks->reply[0]);
+ test_eq(1, socks->reply[0]);
test_eq(0, socks->reply[1]);
test_streq("2.2.2.2", socks->address);
@@ -827,11 +840,11 @@ test_onion_handshake(void)
{
/* client-side */
crypto_dh_t *c_dh = NULL;
- char c_buf[ONIONSKIN_CHALLENGE_LEN];
+ char c_buf[TAP_ONIONSKIN_CHALLENGE_LEN];
char c_keys[40];
/* server-side */
- char s_buf[ONIONSKIN_REPLY_LEN];
+ char s_buf[TAP_ONIONSKIN_REPLY_LEN];
char s_keys[40];
/* shared */
@@ -840,18 +853,18 @@ test_onion_handshake(void)
pk = pk_generate(0);
/* client handshake 1. */
- memset(c_buf, 0, ONIONSKIN_CHALLENGE_LEN);
- test_assert(! onion_skin_create(pk, &c_dh, c_buf));
+ 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, ONIONSKIN_REPLY_LEN);
+ memset(s_buf, 0, TAP_ONIONSKIN_REPLY_LEN);
memset(s_keys, 0, 40);
- test_assert(! onion_skin_server_handshake(c_buf, pk, NULL,
+ test_assert(! onion_skin_TAP_server_handshake(c_buf, pk, NULL,
s_buf, s_keys, 40));
/* client handshake 2 */
memset(c_keys, 0, 40);
- test_assert(! onion_skin_client_handshake(c_dh, s_buf, c_keys, 40));
+ test_assert(! onion_skin_TAP_client_handshake(c_dh, s_buf, c_keys, 40));
if (memcmp(c_keys, s_keys, 40)) {
puts("Aiiiie");
@@ -868,6 +881,103 @@ test_onion_handshake(void)
crypto_pk_free(pk);
}
+#ifdef CURVE25519_ENABLED
+static void
+test_ntor_handshake(void *arg)
+{
+ /* client-side */
+ ntor_handshake_state_t *c_state = NULL;
+ uint8_t c_buf[NTOR_ONIONSKIN_LEN];
+ uint8_t c_keys[400];
+
+ /* server-side */
+ di_digest256_map_t *s_keymap=NULL;
+ curve25519_keypair_t s_keypair;
+ uint8_t s_buf[NTOR_REPLY_LEN];
+ uint8_t s_keys[400];
+
+ /* shared */
+ const curve25519_public_key_t *server_pubkey;
+ uint8_t node_id[20] = "abcdefghijklmnopqrst";
+
+ (void) arg;
+
+ /* Make the server some keys */
+ curve25519_secret_key_generate(&s_keypair.seckey, 0);
+ curve25519_public_key_generate(&s_keypair.pubkey, &s_keypair.seckey);
+ dimap_add_entry(&s_keymap, s_keypair.pubkey.public_key, &s_keypair);
+ server_pubkey = &s_keypair.pubkey;
+
+ /* client handshake 1. */
+ memset(c_buf, 0, NTOR_ONIONSKIN_LEN);
+ tt_int_op(0, ==, onion_skin_ntor_create(node_id, server_pubkey,
+ &c_state, c_buf));
+
+ /* server handshake */
+ memset(s_buf, 0, NTOR_REPLY_LEN);
+ memset(s_keys, 0, 40);
+ tt_int_op(0, ==, onion_skin_ntor_server_handshake(c_buf, s_keymap, NULL,
+ node_id,
+ s_buf, s_keys, 400));
+
+ /* client handshake 2 */
+ memset(c_keys, 0, 40);
+ tt_int_op(0, ==, onion_skin_ntor_client_handshake(c_state, s_buf,
+ c_keys, 400));
+
+ test_memeq(c_keys, s_keys, 400);
+ memset(s_buf, 0, 40);
+ test_memneq(c_keys, s_buf, 40);
+
+ done:
+ ntor_handshake_state_free(c_state);
+ dimap_free(s_keymap, NULL);
+}
+#endif
+
+/** Run unit tests for the onion queues. */
+static void
+test_onion_queues(void)
+{
+ uint8_t buf1[TAP_ONIONSKIN_CHALLENGE_LEN] = {0};
+ uint8_t buf2[NTOR_ONIONSKIN_LEN] = {0};
+
+ 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 *create1 = tor_malloc_zero(sizeof(create_cell_t));
+ create_cell_t *create2 = tor_malloc_zero(sizeof(create_cell_t));
+
+ create_cell_init(create1, CELL_CREATE, ONION_HANDSHAKE_TYPE_TAP,
+ TAP_ONIONSKIN_CHALLENGE_LEN, buf1);
+ create_cell_init(create2, CELL_CREATE, ONION_HANDSHAKE_TYPE_NTOR,
+ NTOR_ONIONSKIN_LEN, buf2);
+
+ test_eq(0, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
+ test_eq(0, onion_pending_add(circ1, create1));
+ 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));
+ 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));
+
+ 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 */
+}
+
static void
test_circuit_timeout(void)
{
@@ -1056,9 +1166,9 @@ test_policy_summary_helper(const char *policy_str,
line.value = (char *)policy_str;
line.next = NULL;
- r = policies_parse_exit_policy(&line, &policy, 0, NULL, 1);
+ r = policies_parse_exit_policy(&line, &policy, 1, 0, NULL, 1);
test_eq(r, 0);
- summary = policy_summarize(policy);
+ summary = policy_summarize(policy, AF_INET);
test_assert(summary != NULL);
test_streq(summary, expected_summary);
@@ -1113,7 +1223,7 @@ test_policies(void)
test_assert(ADDR_POLICY_REJECTED ==
compare_tor_addr_to_addr_policy(&tar, 2, policy));
- test_assert(0 == policies_parse_exit_policy(NULL, &policy2, 1, NULL, 1));
+ test_assert(0 == policies_parse_exit_policy(NULL, &policy2, 1, 1, NULL, 1));
test_assert(policy2);
policy3 = smartlist_new();
@@ -1188,9 +1298,9 @@ test_policies(void)
test_assert(!cmp_addr_policies(policy2, policy2));
test_assert(!cmp_addr_policies(NULL, NULL));
- test_assert(!policy_is_reject_star(policy2));
- test_assert(policy_is_reject_star(policy));
- test_assert(policy_is_reject_star(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;
@@ -1200,11 +1310,11 @@ test_policies(void)
line.key = (char*)"foo";
line.value = (char*)"accept *:80,reject private:*,reject *:*";
line.next = NULL;
- test_assert(0 == policies_parse_exit_policy(&line, &policy, 0, NULL, 1));
+ 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), 2);
+ test_eq(smartlist_len(policy), 4);
/* test policy summaries */
/* check if we properly ignore private IP addresses */
@@ -1366,11 +1476,20 @@ test_rend_fns(void)
char address2[] = "aaaaaaaaaaaaaaaa.onion";
char address3[] = "fooaddress.exit";
char address4[] = "www.torproject.org";
+ char address5[] = "foo.abcdefghijklmnop.onion";
+ char address6[] = "foo.bar.abcdefghijklmnop.onion";
+ char address7[] = ".abcdefghijklmnop.onion";
test_assert(BAD_HOSTNAME == parse_extended_hostname(address1));
test_assert(ONION_HOSTNAME == parse_extended_hostname(address2));
+ test_streq(address2, "aaaaaaaaaaaaaaaa");
test_assert(EXIT_HOSTNAME == parse_extended_hostname(address3));
test_assert(NORMAL_HOSTNAME == parse_extended_hostname(address4));
+ test_assert(ONION_HOSTNAME == parse_extended_hostname(address5));
+ test_streq(address5, "abcdefghijklmnop");
+ test_assert(ONION_HOSTNAME == parse_extended_hostname(address6));
+ test_streq(address6, "abcdefghijklmnop");
+ test_assert(BAD_HOSTNAME == parse_extended_hostname(address7));
pk1 = pk_generate(0);
pk2 = pk_generate(1);
@@ -1466,66 +1585,43 @@ test_geoip(void)
{
int i, j;
time_t now = 1281533250; /* 2010-08-11 13:27:30 UTC */
- char *s = NULL;
+ char *s = NULL, *v = NULL;
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-ips zz=24,xy=8\n"
+ "bridge-ip-versions v4=16,v6=16\n",
*dirreq_stats_1 =
"dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n"
"dirreq-v3-ips ab=8\n"
- "dirreq-v2-ips \n"
"dirreq-v3-reqs ab=8\n"
- "dirreq-v2-reqs \n"
"dirreq-v3-resp ok=0,not-enough-sigs=0,unavailable=0,not-found=0,"
"not-modified=0,busy=0\n"
- "dirreq-v2-resp ok=0,unavailable=0,not-found=0,not-modified=0,"
- "busy=0\n"
"dirreq-v3-direct-dl complete=0,timeout=0,running=0\n"
- "dirreq-v2-direct-dl complete=0,timeout=0,running=0\n"
- "dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n"
- "dirreq-v2-tunneled-dl complete=0,timeout=0,running=0\n",
+ "dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n",
*dirreq_stats_2 =
"dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n"
"dirreq-v3-ips \n"
- "dirreq-v2-ips \n"
"dirreq-v3-reqs \n"
- "dirreq-v2-reqs \n"
"dirreq-v3-resp ok=0,not-enough-sigs=0,unavailable=0,not-found=0,"
"not-modified=0,busy=0\n"
- "dirreq-v2-resp ok=0,unavailable=0,not-found=0,not-modified=0,"
- "busy=0\n"
"dirreq-v3-direct-dl complete=0,timeout=0,running=0\n"
- "dirreq-v2-direct-dl complete=0,timeout=0,running=0\n"
- "dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n"
- "dirreq-v2-tunneled-dl complete=0,timeout=0,running=0\n",
+ "dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n",
*dirreq_stats_3 =
"dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n"
"dirreq-v3-ips \n"
- "dirreq-v2-ips \n"
"dirreq-v3-reqs \n"
- "dirreq-v2-reqs \n"
"dirreq-v3-resp ok=8,not-enough-sigs=0,unavailable=0,not-found=0,"
"not-modified=0,busy=0\n"
- "dirreq-v2-resp ok=0,unavailable=0,not-found=0,not-modified=0,"
- "busy=0\n"
"dirreq-v3-direct-dl complete=0,timeout=0,running=0\n"
- "dirreq-v2-direct-dl complete=0,timeout=0,running=0\n"
- "dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n"
- "dirreq-v2-tunneled-dl complete=0,timeout=0,running=0\n",
+ "dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n",
*dirreq_stats_4 =
"dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n"
"dirreq-v3-ips \n"
- "dirreq-v2-ips \n"
"dirreq-v3-reqs \n"
- "dirreq-v2-reqs \n"
"dirreq-v3-resp ok=8,not-enough-sigs=0,unavailable=0,not-found=0,"
"not-modified=0,busy=0\n"
- "dirreq-v2-resp ok=0,unavailable=0,not-found=0,not-modified=0,"
- "busy=0\n"
"dirreq-v3-direct-dl complete=0,timeout=0,running=0\n"
- "dirreq-v2-direct-dl complete=0,timeout=0,running=0\n"
- "dirreq-v3-tunneled-dl complete=0,timeout=0,running=4\n"
- "dirreq-v2-tunneled-dl complete=0,timeout=0,running=0\n",
+ "dirreq-v3-tunneled-dl complete=0,timeout=0,running=4\n",
*entry_stats_1 =
"entry-stats-end 2010-08-12 13:27:30 (86400 s)\n"
"entry-ips ab=8\n",
@@ -1533,61 +1629,109 @@ test_geoip(void)
"entry-stats-end 2010-08-12 13:27:30 (86400 s)\n"
"entry-ips \n";
tor_addr_t addr;
+ struct in6_addr in6;
/* Populate the DB a bit. Add these in order, since we can't do the final
* 'sort' step. These aren't very good IP addresses, but they're perfectly
* fine uint32_t values. */
- test_eq(0, geoip_parse_entry("10,50,AB"));
- test_eq(0, geoip_parse_entry("52,90,XY"));
- test_eq(0, geoip_parse_entry("95,100,AB"));
- test_eq(0, geoip_parse_entry("\"105\",\"140\",\"ZZ\""));
- test_eq(0, geoip_parse_entry("\"150\",\"190\",\"XY\""));
- test_eq(0, geoip_parse_entry("\"200\",\"250\",\"AB\""));
+ test_eq(0, geoip_parse_entry("10,50,AB", AF_INET));
+ test_eq(0, geoip_parse_entry("52,90,XY", AF_INET));
+ test_eq(0, geoip_parse_entry("95,100,AB", AF_INET));
+ test_eq(0, geoip_parse_entry("\"105\",\"140\",\"ZZ\"", AF_INET));
+ test_eq(0, geoip_parse_entry("\"150\",\"190\",\"XY\"", AF_INET));
+ test_eq(0, geoip_parse_entry("\"200\",\"250\",\"AB\"", AF_INET));
+
+ /* Populate the IPv6 DB equivalently with fake IPs in the same range */
+ test_eq(0, geoip_parse_entry("::a,::32,AB", AF_INET6));
+ test_eq(0, geoip_parse_entry("::34,::5a,XY", AF_INET6));
+ test_eq(0, geoip_parse_entry("::5f,::64,AB", AF_INET6));
+ test_eq(0, geoip_parse_entry("::69,::8c,ZZ", AF_INET6));
+ test_eq(0, geoip_parse_entry("::96,::be,XY", AF_INET6));
+ test_eq(0, geoip_parse_entry("::c8,::fa,AB", AF_INET6));
/* We should have 4 countries: ??, ab, xy, zz. */
test_eq(4, geoip_get_n_countries());
+ memset(&in6, 0, sizeof(in6));
+
/* Make sure that country ID actually works. */
-#define NAMEFOR(x) geoip_get_country_name(geoip_get_country_by_ip(x))
- test_streq("??", NAMEFOR(3));
- test_eq(0, geoip_get_country_by_ip(3));
- test_streq("ab", NAMEFOR(32));
- test_streq("??", NAMEFOR(5));
- test_streq("??", NAMEFOR(51));
- test_streq("xy", NAMEFOR(150));
- test_streq("xy", NAMEFOR(190));
- test_streq("??", NAMEFOR(2000));
-#undef NAMEFOR
+#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);
+ CHECK_COUNTRY("??", 51);
+ CHECK_COUNTRY("xy", 150);
+ CHECK_COUNTRY("xy", 190);
+ CHECK_COUNTRY("??", 2000);
+
+ test_eq(0, geoip_get_country_by_ipv4(3));
+ 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) {
- tor_addr_from_ipv4h(&addr, (uint32_t) i);
+ SET_TEST_ADDRESS(i);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now-7200);
}
- tor_addr_from_ipv4h(&addr, (uint32_t) 225);
+ SET_TEST_ADDRESS(225);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now-7200);
/* and 3 observations in XY, several times. */
for (j=0; j < 10; ++j)
for (i=52; i < 55; ++i) {
- tor_addr_from_ipv4h(&addr, (uint32_t) i);
+ SET_TEST_ADDRESS(i);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now-3600);
}
/* and 17 observations in ZZ... */
for (i=110; i < 127; ++i) {
- tor_addr_from_ipv4h(&addr, (uint32_t) i);
+ SET_TEST_ADDRESS(i);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now);
}
- s = geoip_get_client_history(GEOIP_CLIENT_CONNECT);
+ geoip_get_client_history(GEOIP_CLIENT_CONNECT, &s, &v);
test_assert(s);
+ test_assert(v);
test_streq("zz=24,ab=16,xy=8", s);
+ test_streq("v4=16,v6=16", v);
tor_free(s);
+ tor_free(v);
/* Now clear out all the AB observations. */
geoip_remove_old_clients(now-6000);
- s = geoip_get_client_history(GEOIP_CLIENT_CONNECT);
+ geoip_get_client_history(GEOIP_CLIENT_CONNECT, &s, &v);
test_assert(s);
+ test_assert(v);
test_streq("zz=24,xy=8", s);
+ test_streq("v4=16,v6=16", v);
+ tor_free(s);
+ tor_free(v);
/* Start testing bridge statistics by making sure that we don't output
* bridge stats without initializing them. */
@@ -1598,6 +1742,7 @@ test_geoip(void)
* the connecting clients added above. */
geoip_bridge_stats_init(now);
s = geoip_format_bridge_stats(now + 86400);
+ test_assert(s);
test_streq(bridge_stats_1, s);
tor_free(s);
@@ -1616,7 +1761,7 @@ test_geoip(void)
/* Start testing dirreq statistics by making sure that we don't collect
* dirreq stats without initializing them. */
- tor_addr_from_ipv4h(&addr, (uint32_t) 100);
+ SET_TEST_ADDRESS(100);
geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, now);
s = geoip_format_dirreq_stats(now + 86400);
test_assert(!s);
@@ -1624,7 +1769,7 @@ test_geoip(void)
/* Initialize stats, note one connecting client, and generate the
* dirreq-stats history string. */
geoip_dirreq_stats_init(now);
- tor_addr_from_ipv4h(&addr, (uint32_t) 100);
+ SET_TEST_ADDRESS(100);
geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, now);
s = geoip_format_dirreq_stats(now + 86400);
test_streq(dirreq_stats_1, s);
@@ -1633,7 +1778,7 @@ test_geoip(void)
/* Stop collecting stats, add another connecting client, and ensure we
* don't generate a history string. */
geoip_dirreq_stats_term();
- tor_addr_from_ipv4h(&addr, (uint32_t) 101);
+ SET_TEST_ADDRESS(101);
geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, now);
s = geoip_format_dirreq_stats(now + 86400);
test_assert(!s);
@@ -1641,7 +1786,7 @@ test_geoip(void)
/* Re-start stats, add a connecting client, reset stats, and make sure
* that we get an all empty history string. */
geoip_dirreq_stats_init(now);
- tor_addr_from_ipv4h(&addr, (uint32_t) 100);
+ SET_TEST_ADDRESS(100);
geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, now);
geoip_reset_dirreq_stats(now);
s = geoip_format_dirreq_stats(now + 86400);
@@ -1650,14 +1795,13 @@ test_geoip(void)
/* Note a successful network status response and make sure that it
* appears in the history string. */
- geoip_note_ns_response(GEOIP_CLIENT_NETWORKSTATUS, GEOIP_SUCCESS);
+ geoip_note_ns_response(GEOIP_SUCCESS);
s = geoip_format_dirreq_stats(now + 86400);
test_streq(dirreq_stats_3, s);
tor_free(s);
/* Start a tunneled directory request. */
- geoip_start_dirreq((uint64_t) 1, 1024, GEOIP_CLIENT_NETWORKSTATUS,
- DIRREQ_TUNNELED);
+ geoip_start_dirreq((uint64_t) 1, 1024, DIRREQ_TUNNELED);
s = geoip_format_dirreq_stats(now + 86400);
test_streq(dirreq_stats_4, s);
@@ -1669,7 +1813,7 @@ test_geoip(void)
/* Start testing entry statistics by making sure that we don't collect
* anything without initializing entry stats. */
- tor_addr_from_ipv4h(&addr, (uint32_t) 100);
+ SET_TEST_ADDRESS(100);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now);
s = geoip_format_entry_stats(now + 86400);
test_assert(!s);
@@ -1677,7 +1821,7 @@ test_geoip(void)
/* Initialize stats, note one connecting client, and generate the
* entry-stats history string. */
geoip_entry_stats_init(now);
- tor_addr_from_ipv4h(&addr, (uint32_t) 100);
+ SET_TEST_ADDRESS(100);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now);
s = geoip_format_entry_stats(now + 86400);
test_streq(entry_stats_1, s);
@@ -1686,7 +1830,7 @@ test_geoip(void)
/* Stop collecting stats, add another connecting client, and ensure we
* don't generate a history string. */
geoip_entry_stats_term();
- tor_addr_from_ipv4h(&addr, (uint32_t) 101);
+ SET_TEST_ADDRESS(101);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, now);
s = geoip_format_entry_stats(now + 86400);
test_assert(!s);
@@ -1694,19 +1838,23 @@ test_geoip(void)
/* Re-start stats, add a connecting client, reset stats, and make sure
* that we get an all empty history string. */
geoip_entry_stats_init(now);
- tor_addr_from_ipv4h(&addr, (uint32_t) 100);
+ SET_TEST_ADDRESS(100);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, 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;
done:
tor_free(s);
+ tor_free(v);
}
/** Run unit tests for stats code. */
@@ -1895,11 +2043,6 @@ const struct testcase_setup_t legacy_setup = {
#define ENT(name) \
{ #name, legacy_test_helper, 0, &legacy_setup, test_ ## name }
-#define SUBENT(group, name) \
- { #group "_" #name, legacy_test_helper, 0, &legacy_setup, \
- test_ ## group ## _ ## name }
-#define DISABLED(name) \
- { #name, legacy_test_helper, TT_SKIP, &legacy_setup, test_ ## name }
#define FORK(name) \
{ #name, legacy_test_helper, TT_FORK, &legacy_setup, test_ ## name }
@@ -1907,6 +2050,10 @@ static struct testcase_t test_array[] = {
ENT(buffers),
{ "buffer_copy", test_buffer_copy, 0, NULL, NULL },
ENT(onion_handshake),
+ ENT(onion_queues),
+#ifdef CURVE25519_ENABLED
+ { "ntor_handshake", test_ntor_handshake, 0, NULL, NULL },
+#endif
ENT(circuit_timeout),
ENT(policies),
ENT(rend_fns),
@@ -1941,6 +2088,9 @@ extern struct testcase_t dir_tests[];
extern struct testcase_t microdesc_tests[];
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 cell_format_tests[];
static struct testgroup_t testgroups[] = {
{ "", test_array },
@@ -1949,10 +2099,13 @@ static struct testgroup_t testgroups[] = {
{ "crypto/", crypto_tests },
{ "container/", container_tests },
{ "util/", util_tests },
+ { "cellfmt/", cell_format_tests },
{ "dir/", dir_tests },
{ "dir/md/", microdesc_tests },
{ "pt/", pt_tests },
{ "config/", config_tests },
+ { "replaycache/", replaycache_tests },
+ { "introduce/", introduce_tests },
END_OF_GROUPS
};
@@ -1968,7 +2121,7 @@ main(int c, const char **v)
#ifdef USE_DMALLOC
{
- int r = CRYPTO_set_mem_ex_functions(_tor_malloc, _tor_realloc, _tor_free);
+ int r = CRYPTO_set_mem_ex_functions(tor_malloc_, tor_realloc_, tor_free_);
tor_assert(r);
}
#endif
@@ -2006,6 +2159,7 @@ main(int c, const char **v)
return 1;
}
crypto_set_tls_dh_prime(NULL);
+ crypto_seed_rng(1);
rep_hist_init();
network_init();
setup_directory();
@@ -2018,8 +2172,6 @@ main(int c, const char **v)
return 1;
}
- crypto_seed_rng(1);
-
atexit(remove_directory);
have_failed = (tinytest_main(c, v, testgroups) != 0);
diff --git a/src/test/test.h b/src/test/test.h
index 0b6e6c60c..a89b558e5 100644
--- a/src/test/test.h
+++ b/src/test/test.h
@@ -1,10 +1,10 @@
/* Copyright (c) 2001-2003, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-#ifndef _TOR_TEST_H
-#define _TOR_TEST_H
+#ifndef TOR_TEST_H
+#define TOR_TEST_H
/**
* \file test.h
@@ -65,6 +65,10 @@
#define test_memeq_hex(expr1, hex) test_mem_op_hex(expr1, ==, hex)
+#define tt_double_op(a,op,b) \
+ tt_assert_test_type(a,b,#a" "#op" "#b,double,(val1_ op val2_),"%f", \
+ TT_EXIT_TEST_FUNCTION)
+
const char *get_fname(const char *name);
crypto_pk_t *pk_generate(int idx);
diff --git a/src/test/test_addr.c b/src/test/test_addr.c
index e3f38073e..fec85a469 100644
--- a/src/test/test_addr.c
+++ b/src/test/test_addr.c
@@ -1,11 +1,13 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+#define ADDRESSMAP_PRIVATE
#include "orconfig.h"
#include "or.h"
#include "test.h"
+#include "addressmap.h"
static void
test_addr_basic(void)
@@ -38,7 +40,7 @@ test_addr_basic(void)
tor_free(cp);
u32 = 3;
test_assert(!addr_port_lookup(LOG_WARN, "localhost", NULL, &u32, &u16));
- test_eq(cp, NULL);
+ test_eq_ptr(cp, NULL);
test_eq(u32, 0x7f000001u);
test_eq(u16, 0);
tor_free(cp);
@@ -70,7 +72,7 @@ test_addr_basic(void)
;
}
-#define _test_op_ip6(a,op,b,e1,e2) \
+#define test_op_ip6_(a,op,b,e1,e2) \
STMT_BEGIN \
tt_assert_test_fmt_type(a,b,e1" "#op" "e2,struct in6_addr*, \
(memcmp(val1_->s6_addr, val2_->s6_addr, 16) op 0), \
@@ -93,7 +95,7 @@ test_addr_basic(void)
#define test_pton6_same(a,b) STMT_BEGIN \
test_eq(tor_inet_pton(AF_INET6, a, &a1), 1); \
test_eq(tor_inet_pton(AF_INET6, b, &a2), 1); \
- _test_op_ip6(&a1,==,&a2,#a,#b); \
+ test_op_ip6_(&a1,==,&a2,#a,#b); \
STMT_END
/** Helper: Assert that <b>a</b> is recognized as a bad IPv6 address by
@@ -108,7 +110,7 @@ test_addr_basic(void)
test_eq(tor_inet_pton(AF_INET6, a, &a1), 1); \
test_streq(tor_inet_ntop(AF_INET6, &a1, buf, sizeof(buf)), b); \
test_eq(tor_inet_pton(AF_INET6, b, &a2), 1); \
- _test_op_ip6(&a1, ==, &a2, a, b); \
+ test_op_ip6_(&a1, ==, &a2, a, b); \
STMT_END
/** Helper: assert that <b>a</b> parses by tor_inet_pton() into a address that
@@ -159,7 +161,8 @@ test_addr_basic(void)
* as <b>pt1..pt2</b>. */
#define test_addr_mask_ports_parse(xx, f, ip1, ip2, ip3, ip4, mm, pt1, pt2) \
STMT_BEGIN \
- test_eq(tor_addr_parse_mask_ports(xx, &t1, &mask, &port1, &port2), f); \
+ test_eq(tor_addr_parse_mask_ports(xx, 0, &t1, &mask, &port1, &port2), \
+ f); \
p1=tor_inet_ntop(AF_INET6, &t1.addr.in6_addr, bug, sizeof(bug)); \
test_eq(htonl(ip1), tor_addr_to_in6_addr32(&t1)[0]); \
test_eq(htonl(ip2), tor_addr_to_in6_addr32(&t1)[1]); \
@@ -401,11 +404,11 @@ test_addr_ip6_helpers(void)
test_addr_compare("0::2:2:1", <, "0::ffff:0.3.2.1");
test_addr_compare("0::ffff:0.3.2.1", >, "0::0:0:0");
test_addr_compare("0::ffff:5.2.2.1", <, "::ffff:6.0.0.0"); /* XXXX wrong. */
- tor_addr_parse_mask_ports("[::ffff:2.3.4.5]", &t1, NULL, NULL, NULL);
- tor_addr_parse_mask_ports("2.3.4.5", &t2, NULL, NULL, NULL);
+ tor_addr_parse_mask_ports("[::ffff:2.3.4.5]", 0, &t1, NULL, NULL, NULL);
+ tor_addr_parse_mask_ports("2.3.4.5", 0, &t2, NULL, NULL, NULL);
test_assert(tor_addr_compare(&t1, &t2, CMP_SEMANTIC) == 0);
- tor_addr_parse_mask_ports("[::ffff:2.3.4.4]", &t1, NULL, NULL, NULL);
- tor_addr_parse_mask_ports("2.3.4.5", &t2, NULL, NULL, NULL);
+ tor_addr_parse_mask_ports("[::ffff:2.3.4.4]", 0, &t1, NULL, NULL, NULL);
+ tor_addr_parse_mask_ports("2.3.4.5", 0, &t2, NULL, NULL, NULL);
test_assert(tor_addr_compare(&t1, &t2, CMP_SEMANTIC) < 0);
/* test compare_masked */
@@ -568,6 +571,7 @@ test_addr_ip6_helpers(void)
test_streq(rbuf, addr_PTR);
}
+ /* XXXX turn this into a separate function; it's not all IPv6. */
/* test tor_addr_parse_mask_ports */
test_addr_mask_ports_parse("[::f]/17:47-95", AF_INET6,
0, 0, 0, 0x0000000f, 17, 47, 95);
@@ -581,27 +585,123 @@ test_addr_ip6_helpers(void)
0xabcd0002, 0, 0, 0x044a0000, 128, 2, 65000);
test_streq(p1, "abcd:2::44a:0");
- r=tor_addr_parse_mask_ports("[fefef::]/112", &t1, NULL, NULL, NULL);
+ /* Try some long addresses. */
+ r=tor_addr_parse_mask_ports("[ffff:1111:1111:1111:1111:1111:1111:1111]",
+ 0, &t1, NULL, NULL, NULL);
+ test_assert(r == AF_INET6);
+ r=tor_addr_parse_mask_ports("[ffff:1111:1111:1111:1111:1111:1111:11111]",
+ 0, &t1, NULL, NULL, NULL);
+ test_assert(r == -1);
+ r=tor_addr_parse_mask_ports("[ffff:1111:1111:1111:1111:1111:1111:1111:1]",
+ 0, &t1, NULL, NULL, NULL);
+ test_assert(r == -1);
+ r=tor_addr_parse_mask_ports(
+ "[ffff:1111:1111:1111:1111:1111:1111:ffff:"
+ "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:"
+ "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:"
+ "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]",
+ 0, &t1, NULL, NULL, NULL);
+ test_assert(r == -1);
+ /* Try some failing cases. */
+ r=tor_addr_parse_mask_ports("[fefef::]/112", 0, &t1, NULL, NULL, NULL);
+ test_assert(r == -1);
+ r=tor_addr_parse_mask_ports("[fefe::/112", 0, &t1, NULL, NULL, NULL);
+ test_assert(r == -1);
+ r=tor_addr_parse_mask_ports("[fefe::", 0, &t1, NULL, NULL, NULL);
+ test_assert(r == -1);
+ r=tor_addr_parse_mask_ports("[fefe::X]", 0, &t1, NULL, NULL, NULL);
test_assert(r == -1);
- r=tor_addr_parse_mask_ports("efef::/112", &t1, NULL, NULL, NULL);
+ r=tor_addr_parse_mask_ports("efef::/112", 0, &t1, NULL, NULL, NULL);
test_assert(r == -1);
- r=tor_addr_parse_mask_ports("[f:f:f:f:f:f:f:f::]", &t1, NULL, NULL, NULL);
+ r=tor_addr_parse_mask_ports("[f:f:f:f:f:f:f:f::]",0,&t1, NULL, NULL, NULL);
test_assert(r == -1);
- r=tor_addr_parse_mask_ports("[::f:f:f:f:f:f:f:f]", &t1, NULL, NULL, NULL);
+ r=tor_addr_parse_mask_ports("[::f:f:f:f:f:f:f:f]",0,&t1, NULL, NULL, NULL);
test_assert(r == -1);
- r=tor_addr_parse_mask_ports("[f:f:f:f:f:f:f:f:f]", &t1, NULL, NULL, NULL);
+ r=tor_addr_parse_mask_ports("[f:f:f:f:f:f:f:f:f]",0,&t1, NULL, NULL, NULL);
+ test_assert(r == -1);
+ r=tor_addr_parse_mask_ports("[f:f:f:f:f::]/fred",0,&t1,&mask, NULL, NULL);
+ test_assert(r == -1);
+ r=tor_addr_parse_mask_ports("[f:f:f:f:f::]/255.255.0.0",
+ 0,&t1, NULL, NULL, NULL);
+ test_assert(r == -1);
+ /* This one will get rejected because it isn't a pure prefix. */
+ r=tor_addr_parse_mask_ports("1.1.2.3/255.255.64.0",0,&t1, &mask,NULL,NULL);
test_assert(r == -1);
/* Test for V4-mapped address with mask < 96. (arguably not valid) */
- r=tor_addr_parse_mask_ports("[::ffff:1.1.2.2/33]", &t1, &mask, NULL, NULL);
+ r=tor_addr_parse_mask_ports("[::ffff:1.1.2.2/33]",0,&t1, &mask, NULL, NULL);
+ test_assert(r == -1);
+ r=tor_addr_parse_mask_ports("1.1.2.2/33",0,&t1, &mask, NULL, NULL);
+ test_assert(r == -1);
+ /* Try extended wildcard addresses with out TAPMP_EXTENDED_STAR*/
+ r=tor_addr_parse_mask_ports("*4",0,&t1, &mask, NULL, NULL);
+ test_assert(r == -1);
+ r=tor_addr_parse_mask_ports("*6",0,&t1, &mask, NULL, NULL);
+ test_assert(r == -1);
+#if 0
+ /* Try a mask with a wildcard. */
+ r=tor_addr_parse_mask_ports("*/16",0,&t1, &mask, NULL, NULL);
test_assert(r == -1);
- r=tor_addr_parse_mask_ports("1.1.2.2/33", &t1, &mask, NULL, NULL);
+ r=tor_addr_parse_mask_ports("*4/16",TAPMP_EXTENDED_STAR,
+ &t1, &mask, NULL, NULL);
test_assert(r == -1);
- r=tor_addr_parse_mask_ports("1.1.2.2/31", &t1, &mask, NULL, NULL);
+ r=tor_addr_parse_mask_ports("*6/30",TAPMP_EXTENDED_STAR,
+ &t1, &mask, NULL, NULL);
+ test_assert(r == -1);
+#endif
+ /* Basic mask tests*/
+ r=tor_addr_parse_mask_ports("1.1.2.2/31",0,&t1, &mask, NULL, NULL);
+ test_assert(r == AF_INET);
+ tt_int_op(mask,==,31);
+ tt_int_op(tor_addr_family(&t1),==,AF_INET);
+ tt_int_op(tor_addr_to_ipv4h(&t1),==,0x01010202);
+ r=tor_addr_parse_mask_ports("3.4.16.032:1-2",0,&t1, &mask, &port1, &port2);
+ test_assert(r == AF_INET);
+ tt_int_op(mask,==,32);
+ tt_int_op(tor_addr_family(&t1),==,AF_INET);
+ tt_int_op(tor_addr_to_ipv4h(&t1),==,0x03041020);
+ test_assert(port1 == 1);
+ test_assert(port2 == 2);
+ r=tor_addr_parse_mask_ports("1.1.2.3/255.255.128.0",0,&t1, &mask,NULL,NULL);
test_assert(r == AF_INET);
- r=tor_addr_parse_mask_ports("[efef::]/112", &t1, &mask, &port1, &port2);
+ tt_int_op(mask,==,17);
+ tt_int_op(tor_addr_family(&t1),==,AF_INET);
+ tt_int_op(tor_addr_to_ipv4h(&t1),==,0x01010203);
+ r=tor_addr_parse_mask_ports("[efef::]/112",0,&t1, &mask, &port1, &port2);
test_assert(r == AF_INET6);
test_assert(port1 == 1);
test_assert(port2 == 65535);
+ /* Try regular wildcard behavior without TAPMP_EXTENDED_STAR */
+ r=tor_addr_parse_mask_ports("*:80-443",0,&t1,&mask,&port1,&port2);
+ tt_int_op(r,==,AF_INET); /* Old users of this always get inet */
+ tt_int_op(tor_addr_family(&t1),==,AF_INET);
+ tt_int_op(tor_addr_to_ipv4h(&t1),==,0);
+ tt_int_op(mask,==,0);
+ tt_int_op(port1,==,80);
+ tt_int_op(port2,==,443);
+ /* Now try wildcards *with* TAPMP_EXTENDED_STAR */
+ r=tor_addr_parse_mask_ports("*:8000-9000",TAPMP_EXTENDED_STAR,
+ &t1,&mask,&port1,&port2);
+ tt_int_op(r,==,AF_UNSPEC);
+ tt_int_op(tor_addr_family(&t1),==,AF_UNSPEC);
+ tt_int_op(mask,==,0);
+ tt_int_op(port1,==,8000);
+ tt_int_op(port2,==,9000);
+ r=tor_addr_parse_mask_ports("*4:6667",TAPMP_EXTENDED_STAR,
+ &t1,&mask,&port1,&port2);
+ tt_int_op(r,==,AF_INET);
+ tt_int_op(tor_addr_family(&t1),==,AF_INET);
+ tt_int_op(tor_addr_to_ipv4h(&t1),==,0);
+ tt_int_op(mask,==,0);
+ tt_int_op(port1,==,6667);
+ tt_int_op(port2,==,6667);
+ r=tor_addr_parse_mask_ports("*6",TAPMP_EXTENDED_STAR,
+ &t1,&mask,&port1,&port2);
+ tt_int_op(r,==,AF_INET6);
+ tt_int_op(tor_addr_family(&t1),==,AF_INET6);
+ tt_assert(tor_mem_is_zero((const char*)tor_addr_to_in6_addr32(&t1), 16));
+ tt_int_op(mask,==,0);
+ tt_int_op(port1,==,1);
+ tt_int_op(port2,==,65535);
/* make sure inet address lengths >= max */
test_assert(INET_NTOA_BUF_LEN >= sizeof("255.255.255.255"));
@@ -623,6 +723,126 @@ test_addr_ip6_helpers(void)
;
}
+/** Test tor_addr_port_parse(). */
+static void
+test_addr_parse(void)
+{
+ int r;
+ tor_addr_t addr;
+ char buf[TOR_ADDR_BUF_LEN];
+ uint16_t port = 0;
+
+ /* Correct call. */
+ r= tor_addr_port_parse(LOG_DEBUG,
+ "192.0.2.1:1234",
+ &addr, &port);
+ test_assert(r == 0);
+ tor_addr_to_str(buf, &addr, sizeof(buf), 0);
+ test_streq(buf, "192.0.2.1");
+ test_eq(port, 1234);
+
+ /* Domain name. */
+ r= tor_addr_port_parse(LOG_DEBUG,
+ "torproject.org:1234",
+ &addr, &port);
+ test_assert(r == -1);
+
+ /* Only IP. */
+ r= tor_addr_port_parse(LOG_DEBUG,
+ "192.0.2.2",
+ &addr, &port);
+ test_assert(r == -1);
+
+ /* Bad port. */
+ r= tor_addr_port_parse(LOG_DEBUG,
+ "192.0.2.2:66666",
+ &addr, &port);
+ test_assert(r == -1);
+
+ /* Only domain name */
+ r= tor_addr_port_parse(LOG_DEBUG,
+ "torproject.org",
+ &addr, &port);
+ test_assert(r == -1);
+
+ /* Bad IP address */
+ r= tor_addr_port_parse(LOG_DEBUG,
+ "192.0.2:1234",
+ &addr, &port);
+ test_assert(r == -1);
+
+ done:
+ ;
+}
+
+static void
+update_difference(int ipv6, uint8_t *d,
+ const tor_addr_t *a, const tor_addr_t *b)
+{
+ const int n_bytes = ipv6 ? 16 : 4;
+ uint8_t a_tmp[4], b_tmp[4];
+ const uint8_t *ba, *bb;
+ int i;
+
+ if (ipv6) {
+ ba = tor_addr_to_in6_addr8(a);
+ bb = tor_addr_to_in6_addr8(b);
+ } else {
+ set_uint32(a_tmp, tor_addr_to_ipv4n(a));
+ set_uint32(b_tmp, tor_addr_to_ipv4n(b));
+ ba = a_tmp; bb = b_tmp;
+ }
+
+ for (i = 0; i < n_bytes; ++i) {
+ d[i] |= ba[i] ^ bb[i];
+ }
+}
+
+static void
+test_virtaddrmap(void *data)
+{
+ /* Let's start with a bunch of random addresses. */
+ int ipv6, bits, iter, b;
+ virtual_addr_conf_t cfg[2];
+ uint8_t bytes[16];
+
+ (void)data;
+
+ tor_addr_parse(&cfg[0].addr, "64.65.0.0");
+ tor_addr_parse(&cfg[1].addr, "3491:c0c0::");
+
+ for (ipv6 = 0; ipv6 <= 1; ++ipv6) {
+ for (bits = 0; bits < 18; ++bits) {
+ tor_addr_t last_a;
+ cfg[ipv6].bits = bits;
+ memset(bytes, 0, sizeof(bytes));
+ tor_addr_copy(&last_a, &cfg[ipv6].addr);
+ /* Generate 128 addresses with each addr/bits combination. */
+ for (iter = 0; iter < 128; ++iter) {
+ tor_addr_t a;
+
+ get_random_virtual_addr(&cfg[ipv6], &a);
+ //printf("%s\n", fmt_addr(&a));
+ /* Make sure that the first b bits match the configured network */
+ tt_int_op(0, ==, tor_addr_compare_masked(&a, &cfg[ipv6].addr,
+ bits, CMP_EXACT));
+
+ /* And track which bits have been different between pairs of
+ * addresses */
+ update_difference(ipv6, bytes, &last_a, &a);
+ }
+
+ /* Now make sure all but the first 'bits' bits of bytes are true */
+ for (b = bits+1; b < (ipv6?128:32); ++b) {
+ tt_assert(1 & (bytes[b/8] >> (7-(b&7))));
+ }
+ }
+ }
+
+ done:
+ ;
+}
+
static void
test_addr_is_loopback(void *data)
{
@@ -664,6 +884,8 @@ test_addr_is_loopback(void *data)
struct testcase_t addr_tests[] = {
ADDR_LEGACY(basic),
ADDR_LEGACY(ip6_helpers),
+ ADDR_LEGACY(parse),
+ { "virtaddr", test_virtaddrmap, 0, NULL, NULL },
{ "is_loopback", test_addr_is_loopback, 0, NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_cell_formats.c b/src/test/test_cell_formats.c
new file mode 100644
index 000000000..55d8d0f00
--- /dev/null
+++ b/src/test/test_cell_formats.c
@@ -0,0 +1,888 @@
+/* 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 CONNECTION_EDGE_PRIVATE
+#define RELAY_PRIVATE
+#include "or.h"
+#include "connection_edge.h"
+#include "onion.h"
+#include "onion_tap.h"
+#include "onion_fast.h"
+#include "onion_ntor.h"
+#include "relay.h"
+#include "test.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+static void
+test_cfmt_relay_header(void *arg)
+{
+ relay_header_t rh;
+ const uint8_t hdr_1[RELAY_HEADER_SIZE] =
+ "\x03" "\x00\x00" "\x21\x22" "ABCD" "\x01\x03";
+ uint8_t hdr_out[RELAY_HEADER_SIZE];
+ (void)arg;
+
+ tt_int_op(sizeof(hdr_1), ==, RELAY_HEADER_SIZE);
+ relay_header_unpack(&rh, hdr_1);
+ tt_int_op(rh.command, ==, 3);
+ tt_int_op(rh.recognized, ==, 0);
+ tt_int_op(rh.stream_id, ==, 0x2122);
+ test_mem_op(rh.integrity, ==, "ABCD", 4);
+ tt_int_op(rh.length, ==, 0x103);
+
+ relay_header_pack(hdr_out, &rh);
+ test_mem_op(hdr_out, ==, hdr_1, RELAY_HEADER_SIZE);
+
+ done:
+ ;
+}
+
+static void
+make_relay_cell(cell_t *out, uint8_t command,
+ const void *body, size_t bodylen)
+{
+ relay_header_t rh;
+
+ memset(&rh, 0, sizeof(rh));
+ rh.stream_id = 5;
+ rh.command = command;
+ rh.length = bodylen;
+
+ out->command = CELL_RELAY;
+ out->circ_id = 10;
+ relay_header_pack(out->payload, &rh);
+
+ memcpy(out->payload + RELAY_HEADER_SIZE, body, bodylen);
+}
+
+static void
+test_cfmt_begin_cells(void *arg)
+{
+ cell_t cell;
+ begin_cell_t bcell;
+ uint8_t end_reason;
+ (void)arg;
+
+ /* Try begindir. */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN_DIR, "", 0);
+ tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+ tt_ptr_op(NULL, ==, bcell.address);
+ tt_int_op(0, ==, bcell.flags);
+ tt_int_op(0, ==, bcell.port);
+ tt_int_op(5, ==, bcell.stream_id);
+ tt_int_op(1, ==, bcell.is_begindir);
+
+ /* A Begindir with extra stuff. */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN_DIR, "12345", 5);
+ tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+ tt_ptr_op(NULL, ==, bcell.address);
+ tt_int_op(0, ==, bcell.flags);
+ tt_int_op(0, ==, bcell.port);
+ tt_int_op(5, ==, bcell.stream_id);
+ tt_int_op(1, ==, bcell.is_begindir);
+
+ /* A short but valid begin cell */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:9", 6);
+ tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+ tt_str_op("a.b", ==, bcell.address);
+ tt_int_op(0, ==, bcell.flags);
+ tt_int_op(9, ==, bcell.port);
+ tt_int_op(5, ==, bcell.stream_id);
+ tt_int_op(0, ==, bcell.is_begindir);
+ tor_free(bcell.address);
+
+ /* A significantly loner begin cell */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ {
+ const char c[] = "here-is-a-nice-long.hostname.com:65535";
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN, c, strlen(c)+1);
+ }
+ tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+ tt_str_op("here-is-a-nice-long.hostname.com", ==, bcell.address);
+ tt_int_op(0, ==, bcell.flags);
+ tt_int_op(65535, ==, bcell.port);
+ tt_int_op(5, ==, bcell.stream_id);
+ tt_int_op(0, ==, bcell.is_begindir);
+ tor_free(bcell.address);
+
+ /* An IPv4 begin cell. */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "18.9.22.169:80", 15);
+ tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+ tt_str_op("18.9.22.169", ==, bcell.address);
+ tt_int_op(0, ==, bcell.flags);
+ tt_int_op(80, ==, bcell.port);
+ tt_int_op(5, ==, bcell.stream_id);
+ tt_int_op(0, ==, bcell.is_begindir);
+ tor_free(bcell.address);
+
+ /* An IPv6 begin cell. Let's make sure we handle colons*/
+ memset(&bcell, 0x7f, sizeof(bcell));
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN,
+ "[2620::6b0:b:1a1a:0:26e5:480e]:80", 34);
+ tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+ tt_str_op("[2620::6b0:b:1a1a:0:26e5:480e]", ==, bcell.address);
+ tt_int_op(0, ==, bcell.flags);
+ tt_int_op(80, ==, bcell.port);
+ tt_int_op(5, ==, bcell.stream_id);
+ tt_int_op(0, ==, bcell.is_begindir);
+ tor_free(bcell.address);
+
+ /* a begin cell with extra junk but not enough for flags. */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ {
+ const char c[] = "another.example.com:80\x00\x01\x02";
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN, c, sizeof(c)-1);
+ }
+ tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+ tt_str_op("another.example.com", ==, bcell.address);
+ tt_int_op(0, ==, bcell.flags);
+ tt_int_op(80, ==, bcell.port);
+ tt_int_op(5, ==, bcell.stream_id);
+ tt_int_op(0, ==, bcell.is_begindir);
+ tor_free(bcell.address);
+
+ /* a begin cell with flags. */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ {
+ const char c[] = "another.example.com:443\x00\x01\x02\x03\x04";
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN, c, sizeof(c)-1);
+ }
+ tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+ tt_str_op("another.example.com", ==, bcell.address);
+ tt_int_op(0x1020304, ==, bcell.flags);
+ tt_int_op(443, ==, bcell.port);
+ tt_int_op(5, ==, bcell.stream_id);
+ tt_int_op(0, ==, bcell.is_begindir);
+ tor_free(bcell.address);
+
+ /* a begin cell with flags and even more cruft after that. */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ {
+ const char c[] = "a-further.example.com:22\x00\xee\xaa\x00\xffHi mom";
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN, c, sizeof(c)-1);
+ }
+ tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+ tt_str_op("a-further.example.com", ==, bcell.address);
+ tt_int_op(0xeeaa00ff, ==, bcell.flags);
+ tt_int_op(22, ==, bcell.port);
+ tt_int_op(5, ==, bcell.stream_id);
+ tt_int_op(0, ==, bcell.is_begindir);
+ tor_free(bcell.address);
+
+ /* bad begin cell: impossible length. */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:80", 7);
+ cell.payload[9] = 0x01; /* Set length to 510 */
+ cell.payload[10] = 0xfe;
+ {
+ relay_header_t rh;
+ relay_header_unpack(&rh, cell.payload);
+ tt_int_op(rh.length, ==, 510);
+ }
+ tt_int_op(-2, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+
+ /* Bad begin cell: no body. */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "", 0);
+ tt_int_op(-1, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+
+ /* bad begin cell: no body. */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "", 0);
+ tt_int_op(-1, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+
+ /* bad begin cell: no colon */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b", 4);
+ tt_int_op(-1, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+
+ /* bad begin cell: no ports */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:", 5);
+ tt_int_op(-1, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+
+ /* bad begin cell: bad port */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:xyz", 8);
+ tt_int_op(-1, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+ memset(&bcell, 0x7f, sizeof(bcell));
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:100000", 11);
+ tt_int_op(-1, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+
+ /* bad begin cell: no nul */
+ memset(&bcell, 0x7f, sizeof(bcell));
+ make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:80", 6);
+ tt_int_op(-1, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+
+ done:
+ tor_free(bcell.address);
+}
+
+static void
+test_cfmt_connected_cells(void *arg)
+{
+ relay_header_t rh;
+ cell_t cell;
+ tor_addr_t addr;
+ int ttl, r;
+ char *mem_op_hex_tmp = NULL;
+ (void)arg;
+
+ /* Let's try an oldschool one with nothing in it. */
+ make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, "", 0);
+ relay_header_unpack(&rh, cell.payload);
+ r = connected_cell_parse(&rh, &cell, &addr, &ttl);
+ tt_int_op(r, ==, 0);
+ tt_int_op(tor_addr_family(&addr), ==, AF_UNSPEC);
+ tt_int_op(ttl, ==, -1);
+
+ /* A slightly less oldschool one: only an IPv4 address */
+ make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, "\x20\x30\x40\x50", 4);
+ relay_header_unpack(&rh, cell.payload);
+ r = connected_cell_parse(&rh, &cell, &addr, &ttl);
+ tt_int_op(r, ==, 0);
+ tt_int_op(tor_addr_family(&addr), ==, AF_INET);
+ tt_str_op(fmt_addr(&addr), ==, "32.48.64.80");
+ tt_int_op(ttl, ==, -1);
+
+ /* Bogus but understandable: truncated TTL */
+ make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, "\x11\x12\x13\x14\x15", 5);
+ relay_header_unpack(&rh, cell.payload);
+ r = connected_cell_parse(&rh, &cell, &addr, &ttl);
+ tt_int_op(r, ==, 0);
+ tt_int_op(tor_addr_family(&addr), ==, AF_INET);
+ tt_str_op(fmt_addr(&addr), ==, "17.18.19.20");
+ tt_int_op(ttl, ==, -1);
+
+ /* Regular IPv4 one: address and TTL */
+ make_relay_cell(&cell, RELAY_COMMAND_CONNECTED,
+ "\x02\x03\x04\x05\x00\x00\x0e\x10", 8);
+ relay_header_unpack(&rh, cell.payload);
+ r = connected_cell_parse(&rh, &cell, &addr, &ttl);
+ tt_int_op(r, ==, 0);
+ tt_int_op(tor_addr_family(&addr), ==, AF_INET);
+ tt_str_op(fmt_addr(&addr), ==, "2.3.4.5");
+ tt_int_op(ttl, ==, 3600);
+
+ /* IPv4 with too-big TTL */
+ make_relay_cell(&cell, RELAY_COMMAND_CONNECTED,
+ "\x02\x03\x04\x05\xf0\x00\x00\x00", 8);
+ relay_header_unpack(&rh, cell.payload);
+ r = connected_cell_parse(&rh, &cell, &addr, &ttl);
+ tt_int_op(r, ==, 0);
+ tt_int_op(tor_addr_family(&addr), ==, AF_INET);
+ tt_str_op(fmt_addr(&addr), ==, "2.3.4.5");
+ tt_int_op(ttl, ==, -1);
+
+ /* IPv6 (ttl is mandatory) */
+ make_relay_cell(&cell, RELAY_COMMAND_CONNECTED,
+ "\x00\x00\x00\x00\x06"
+ "\x26\x07\xf8\xb0\x40\x0c\x0c\x02"
+ "\x00\x00\x00\x00\x00\x00\x00\x68"
+ "\x00\x00\x02\x58", 25);
+ relay_header_unpack(&rh, cell.payload);
+ r = connected_cell_parse(&rh, &cell, &addr, &ttl);
+ tt_int_op(r, ==, 0);
+ tt_int_op(tor_addr_family(&addr), ==, AF_INET6);
+ tt_str_op(fmt_addr(&addr), ==, "2607:f8b0:400c:c02::68");
+ tt_int_op(ttl, ==, 600);
+
+ /* IPv6 (ttl too big) */
+ make_relay_cell(&cell, RELAY_COMMAND_CONNECTED,
+ "\x00\x00\x00\x00\x06"
+ "\x26\x07\xf8\xb0\x40\x0c\x0c\x02"
+ "\x00\x00\x00\x00\x00\x00\x00\x68"
+ "\x90\x00\x02\x58", 25);
+ relay_header_unpack(&rh, cell.payload);
+ r = connected_cell_parse(&rh, &cell, &addr, &ttl);
+ tt_int_op(r, ==, 0);
+ tt_int_op(tor_addr_family(&addr), ==, AF_INET6);
+ tt_str_op(fmt_addr(&addr), ==, "2607:f8b0:400c:c02::68");
+ tt_int_op(ttl, ==, -1);
+
+ /* Bogus size: 3. */
+ make_relay_cell(&cell, RELAY_COMMAND_CONNECTED,
+ "\x00\x01\x02", 3);
+ relay_header_unpack(&rh, cell.payload);
+ r = connected_cell_parse(&rh, &cell, &addr, &ttl);
+ tt_int_op(r, ==, -1);
+
+ /* Bogus family: 7. */
+ make_relay_cell(&cell, RELAY_COMMAND_CONNECTED,
+ "\x00\x00\x00\x00\x07"
+ "\x26\x07\xf8\xb0\x40\x0c\x0c\x02"
+ "\x00\x00\x00\x00\x00\x00\x00\x68"
+ "\x90\x00\x02\x58", 25);
+ relay_header_unpack(&rh, cell.payload);
+ r = connected_cell_parse(&rh, &cell, &addr, &ttl);
+ tt_int_op(r, ==, -1);
+
+ /* Truncated IPv6. */
+ make_relay_cell(&cell, RELAY_COMMAND_CONNECTED,
+ "\x00\x00\x00\x00\x06"
+ "\x26\x07\xf8\xb0\x40\x0c\x0c\x02"
+ "\x00\x00\x00\x00\x00\x00\x00\x68"
+ "\x00\x00\x02", 24);
+ relay_header_unpack(&rh, cell.payload);
+ r = connected_cell_parse(&rh, &cell, &addr, &ttl);
+ tt_int_op(r, ==, -1);
+
+ /* Now make sure we can generate connected cells correctly. */
+ /* Try an IPv4 address */
+ memset(&rh, 0, sizeof(rh));
+ memset(&cell, 0, sizeof(cell));
+ tor_addr_parse(&addr, "30.40.50.60");
+ rh.length = connected_cell_format_payload(cell.payload+RELAY_HEADER_SIZE,
+ &addr, 128);
+ tt_int_op(rh.length, ==, 8);
+ test_memeq_hex(cell.payload+RELAY_HEADER_SIZE, "1e28323c" "00000080");
+
+ /* Try parsing it. */
+ tor_addr_make_unspec(&addr);
+ r = connected_cell_parse(&rh, &cell, &addr, &ttl);
+ tt_int_op(r, ==, 0);
+ tt_int_op(tor_addr_family(&addr), ==, AF_INET);
+ tt_str_op(fmt_addr(&addr), ==, "30.40.50.60");
+ tt_int_op(ttl, ==, 128);
+
+ /* Try an IPv6 address */
+ memset(&rh, 0, sizeof(rh));
+ memset(&cell, 0, sizeof(cell));
+ tor_addr_parse(&addr, "2620::6b0:b:1a1a:0:26e5:480e");
+ rh.length = connected_cell_format_payload(cell.payload+RELAY_HEADER_SIZE,
+ &addr, 3600);
+ tt_int_op(rh.length, ==, 25);
+ test_memeq_hex(cell.payload + RELAY_HEADER_SIZE,
+ "00000000" "06"
+ "2620000006b0000b1a1a000026e5480e" "00000e10");
+
+ /* Try parsing it. */
+ tor_addr_make_unspec(&addr);
+ r = connected_cell_parse(&rh, &cell, &addr, &ttl);
+ tt_int_op(r, ==, 0);
+ tt_int_op(tor_addr_family(&addr), ==, AF_INET6);
+ tt_str_op(fmt_addr(&addr), ==, "2620:0:6b0:b:1a1a:0:26e5:480e");
+ tt_int_op(ttl, ==, 3600);
+
+ done:
+ tor_free(mem_op_hex_tmp);
+}
+
+static void
+test_cfmt_create_cells(void *arg)
+{
+ uint8_t b[MAX_ONIONSKIN_CHALLENGE_LEN];
+ create_cell_t cc;
+ cell_t cell;
+ cell_t cell2;
+
+ (void)arg;
+
+ /* === Let's try parsing some good cells! */
+
+ /* A valid create cell. */
+ memset(&cell, 0, sizeof(cell));
+ memset(b, 0, sizeof(b));
+ crypto_rand((char*)b, TAP_ONIONSKIN_CHALLENGE_LEN);
+ cell.command = CELL_CREATE;
+ memcpy(cell.payload, b, TAP_ONIONSKIN_CHALLENGE_LEN);
+ tt_int_op(0, ==, create_cell_parse(&cc, &cell));
+ tt_int_op(CELL_CREATE, ==, cc.cell_type);
+ tt_int_op(ONION_HANDSHAKE_TYPE_TAP, ==, cc.handshake_type);
+ tt_int_op(TAP_ONIONSKIN_CHALLENGE_LEN, ==, cc.handshake_len);
+ test_memeq(cc.onionskin, b, TAP_ONIONSKIN_CHALLENGE_LEN + 10);
+ tt_int_op(0, ==, create_cell_format(&cell2, &cc));
+ tt_int_op(cell.command, ==, cell2.command);
+ test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE);
+
+ /* A valid create_fast cell. */
+ memset(&cell, 0, sizeof(cell));
+ memset(b, 0, sizeof(b));
+ crypto_rand((char*)b, CREATE_FAST_LEN);
+ cell.command = CELL_CREATE_FAST;
+ memcpy(cell.payload, b, CREATE_FAST_LEN);
+ tt_int_op(0, ==, create_cell_parse(&cc, &cell));
+ tt_int_op(CELL_CREATE_FAST, ==, cc.cell_type);
+ tt_int_op(ONION_HANDSHAKE_TYPE_FAST, ==, cc.handshake_type);
+ tt_int_op(CREATE_FAST_LEN, ==, cc.handshake_len);
+ test_memeq(cc.onionskin, b, CREATE_FAST_LEN + 10);
+ tt_int_op(0, ==, create_cell_format(&cell2, &cc));
+ tt_int_op(cell.command, ==, cell2.command);
+ test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE);
+
+ /* A valid create2 cell with a TAP payload */
+ memset(&cell, 0, sizeof(cell));
+ memset(b, 0, sizeof(b));
+ crypto_rand((char*)b, TAP_ONIONSKIN_CHALLENGE_LEN);
+ cell.command = CELL_CREATE2;
+ memcpy(cell.payload, "\x00\x00\x00\xBA", 4); /* TAP, 186 bytes long */
+ memcpy(cell.payload+4, b, TAP_ONIONSKIN_CHALLENGE_LEN);
+ tt_int_op(0, ==, create_cell_parse(&cc, &cell));
+ tt_int_op(CELL_CREATE2, ==, cc.cell_type);
+ tt_int_op(ONION_HANDSHAKE_TYPE_TAP, ==, cc.handshake_type);
+ tt_int_op(TAP_ONIONSKIN_CHALLENGE_LEN, ==, cc.handshake_len);
+ test_memeq(cc.onionskin, b, TAP_ONIONSKIN_CHALLENGE_LEN + 10);
+ tt_int_op(0, ==, create_cell_format(&cell2, &cc));
+ tt_int_op(cell.command, ==, cell2.command);
+ test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE);
+
+ /* A valid create2 cell with an ntor payload */
+ memset(&cell, 0, sizeof(cell));
+ memset(b, 0, sizeof(b));
+ crypto_rand((char*)b, NTOR_ONIONSKIN_LEN);
+ cell.command = CELL_CREATE2;
+ memcpy(cell.payload, "\x00\x02\x00\x54", 4); /* ntor, 84 bytes long */
+ memcpy(cell.payload+4, b, NTOR_ONIONSKIN_LEN);
+#ifdef CURVE25519_ENABLED
+ tt_int_op(0, ==, create_cell_parse(&cc, &cell));
+ tt_int_op(CELL_CREATE2, ==, cc.cell_type);
+ tt_int_op(ONION_HANDSHAKE_TYPE_NTOR, ==, cc.handshake_type);
+ tt_int_op(NTOR_ONIONSKIN_LEN, ==, cc.handshake_len);
+ test_memeq(cc.onionskin, b, NTOR_ONIONSKIN_LEN + 10);
+ tt_int_op(0, ==, create_cell_format(&cell2, &cc));
+ tt_int_op(cell.command, ==, cell2.command);
+ test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE);
+#else
+ tt_int_op(-1, ==, create_cell_parse(&cc, &cell));
+#endif
+
+ /* A valid create cell with an ntor payload, in legacy format. */
+ memset(&cell, 0, sizeof(cell));
+ memset(b, 0, sizeof(b));
+ crypto_rand((char*)b, NTOR_ONIONSKIN_LEN);
+ cell.command = CELL_CREATE;
+ memcpy(cell.payload, "ntorNTORntorNTOR", 16);
+ memcpy(cell.payload+16, b, NTOR_ONIONSKIN_LEN);
+#ifdef CURVE25519_ENABLED
+ tt_int_op(0, ==, create_cell_parse(&cc, &cell));
+ tt_int_op(CELL_CREATE, ==, cc.cell_type);
+ tt_int_op(ONION_HANDSHAKE_TYPE_NTOR, ==, cc.handshake_type);
+ tt_int_op(NTOR_ONIONSKIN_LEN, ==, cc.handshake_len);
+ test_memeq(cc.onionskin, b, NTOR_ONIONSKIN_LEN + 10);
+ tt_int_op(0, ==, create_cell_format(&cell2, &cc));
+ tt_int_op(cell.command, ==, cell2.command);
+ test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE);
+#else
+ tt_int_op(-1, ==, create_cell_parse(&cc, &cell));
+#endif
+
+ /* == Okay, now let's try to parse some impossible stuff. */
+
+ /* It has to be some kind of a create cell! */
+ cell.command = CELL_CREATED;
+ tt_int_op(-1, ==, create_cell_parse(&cc, &cell));
+
+ /* You can't acutally make an unparseable CREATE or CREATE_FAST cell. */
+
+ /* Try some CREATE2 cells. First with a bad type. */
+ cell.command = CELL_CREATE2;
+ memcpy(cell.payload, "\x00\x50\x00\x99", 4); /* Type 0x50???? */
+ tt_int_op(-1, ==, create_cell_parse(&cc, &cell));
+ /* Now a good type with an incorrect length. */
+ memcpy(cell.payload, "\x00\x00\x00\xBC", 4); /* TAP, 187 bytes.*/
+ tt_int_op(-1, ==, create_cell_parse(&cc, &cell));
+ /* Now a good type with a ridiculous length. */
+ memcpy(cell.payload, "\x00\x00\x02\x00", 4); /* TAP, 512 bytes.*/
+ tt_int_op(-1, ==, create_cell_parse(&cc, &cell));
+
+ /* == Time to try formatting bad cells. The important thing is that
+ we reject big lengths, so just check that for now. */
+ cc.handshake_len = 512;
+ tt_int_op(-1, ==, create_cell_format(&cell2, &cc));
+
+ /* == Try formatting a create2 cell we don't understand. XXXX */
+
+ done:
+ ;
+}
+
+static void
+test_cfmt_created_cells(void *arg)
+{
+ uint8_t b[512];
+ created_cell_t cc;
+ cell_t cell;
+ cell_t cell2;
+
+ (void)arg;
+
+ /* A good CREATED cell */
+ memset(&cell, 0, sizeof(cell));
+ memset(b, 0, sizeof(b));
+ crypto_rand((char*)b, TAP_ONIONSKIN_REPLY_LEN);
+ cell.command = CELL_CREATED;
+ memcpy(cell.payload, b, TAP_ONIONSKIN_REPLY_LEN);
+ tt_int_op(0, ==, created_cell_parse(&cc, &cell));
+ tt_int_op(CELL_CREATED, ==, cc.cell_type);
+ tt_int_op(TAP_ONIONSKIN_REPLY_LEN, ==, cc.handshake_len);
+ test_memeq(cc.reply, b, TAP_ONIONSKIN_REPLY_LEN + 10);
+ tt_int_op(0, ==, created_cell_format(&cell2, &cc));
+ tt_int_op(cell.command, ==, cell2.command);
+ test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE);
+
+ /* A good CREATED_FAST cell */
+ memset(&cell, 0, sizeof(cell));
+ memset(b, 0, sizeof(b));
+ crypto_rand((char*)b, CREATED_FAST_LEN);
+ cell.command = CELL_CREATED_FAST;
+ memcpy(cell.payload, b, CREATED_FAST_LEN);
+ tt_int_op(0, ==, created_cell_parse(&cc, &cell));
+ tt_int_op(CELL_CREATED_FAST, ==, cc.cell_type);
+ tt_int_op(CREATED_FAST_LEN, ==, cc.handshake_len);
+ test_memeq(cc.reply, b, CREATED_FAST_LEN + 10);
+ tt_int_op(0, ==, created_cell_format(&cell2, &cc));
+ tt_int_op(cell.command, ==, cell2.command);
+ test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE);
+
+ /* A good CREATED2 cell with short reply */
+ memset(&cell, 0, sizeof(cell));
+ memset(b, 0, sizeof(b));
+ crypto_rand((char*)b, 64);
+ cell.command = CELL_CREATED2;
+ memcpy(cell.payload, "\x00\x40", 2);
+ memcpy(cell.payload+2, b, 64);
+ tt_int_op(0, ==, created_cell_parse(&cc, &cell));
+ tt_int_op(CELL_CREATED2, ==, cc.cell_type);
+ tt_int_op(64, ==, cc.handshake_len);
+ test_memeq(cc.reply, b, 80);
+ tt_int_op(0, ==, created_cell_format(&cell2, &cc));
+ tt_int_op(cell.command, ==, cell2.command);
+ test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE);
+
+ /* A good CREATED2 cell with maximal reply */
+ memset(&cell, 0, sizeof(cell));
+ memset(b, 0, sizeof(b));
+ crypto_rand((char*)b, 496);
+ cell.command = CELL_CREATED2;
+ memcpy(cell.payload, "\x01\xF0", 2);
+ memcpy(cell.payload+2, b, 496);
+ tt_int_op(0, ==, created_cell_parse(&cc, &cell));
+ tt_int_op(CELL_CREATED2, ==, cc.cell_type);
+ tt_int_op(496, ==, cc.handshake_len);
+ test_memeq(cc.reply, b, 496);
+ tt_int_op(0, ==, created_cell_format(&cell2, &cc));
+ tt_int_op(cell.command, ==, cell2.command);
+ test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE);
+
+ /* Bogus CREATED2 cell: too long! */
+ memset(&cell, 0, sizeof(cell));
+ memset(b, 0, sizeof(b));
+ crypto_rand((char*)b, 496);
+ cell.command = CELL_CREATED2;
+ memcpy(cell.payload, "\x01\xF1", 2);
+ tt_int_op(-1, ==, created_cell_parse(&cc, &cell));
+
+ /* Unformattable CREATED2 cell: too long! */
+ cc.handshake_len = 497;
+ tt_int_op(-1, ==, created_cell_format(&cell2, &cc));
+
+ done:
+ ;
+}
+
+static void
+test_cfmt_extend_cells(void *arg)
+{
+ cell_t cell;
+ uint8_t b[512];
+ extend_cell_t ec;
+ create_cell_t *cc = &ec.create_cell;
+ uint8_t p[RELAY_PAYLOAD_SIZE];
+ uint8_t p2[RELAY_PAYLOAD_SIZE];
+ uint8_t p2_cmd;
+ uint16_t p2_len;
+ char *mem_op_hex_tmp = NULL;
+
+ (void) arg;
+
+ /* Let's start with a simple EXTEND cell. */
+ memset(p, 0, sizeof(p));
+ memset(b, 0, sizeof(b));
+ crypto_rand((char*)b, TAP_ONIONSKIN_CHALLENGE_LEN);
+ memcpy(p, "\x12\xf4\x00\x01\x01\x02", 6); /* 18 244 0 1 : 258 */
+ memcpy(p+6,b,TAP_ONIONSKIN_CHALLENGE_LEN);
+ memcpy(p+6+TAP_ONIONSKIN_CHALLENGE_LEN, "electroencephalogram", 20);
+ tt_int_op(0, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND,
+ p, 26+TAP_ONIONSKIN_CHALLENGE_LEN));
+ tt_int_op(RELAY_COMMAND_EXTEND, ==, ec.cell_type);
+ tt_str_op("18.244.0.1", ==, fmt_addr(&ec.orport_ipv4.addr));
+ tt_int_op(258, ==, ec.orport_ipv4.port);
+ tt_int_op(AF_UNSPEC, ==, tor_addr_family(&ec.orport_ipv6.addr));
+ test_memeq(ec.node_id, "electroencephalogram", 20);
+ tt_int_op(cc->cell_type, ==, CELL_CREATE);
+ tt_int_op(cc->handshake_type, ==, ONION_HANDSHAKE_TYPE_TAP);
+ tt_int_op(cc->handshake_len, ==, TAP_ONIONSKIN_CHALLENGE_LEN);
+ test_memeq(cc->onionskin, b, TAP_ONIONSKIN_CHALLENGE_LEN+20);
+ tt_int_op(0, ==, extend_cell_format(&p2_cmd, &p2_len, p2, &ec));
+ tt_int_op(p2_cmd, ==, RELAY_COMMAND_EXTEND);
+ tt_int_op(p2_len, ==, 26+TAP_ONIONSKIN_CHALLENGE_LEN);
+ test_memeq(p2, p, RELAY_PAYLOAD_SIZE);
+
+ /* Let's do an ntor stuffed in a legacy EXTEND cell */
+ memset(p, 0, sizeof(p));
+ memset(b, 0, sizeof(b));
+ crypto_rand((char*)b, NTOR_ONIONSKIN_LEN);
+ memcpy(p, "\x12\xf4\x00\x01\x01\x02", 6); /* 18 244 0 1 : 258 */
+ memcpy(p+6,"ntorNTORntorNTOR", 16);
+ memcpy(p+22, b, NTOR_ONIONSKIN_LEN);
+ memcpy(p+6+TAP_ONIONSKIN_CHALLENGE_LEN, "electroencephalogram", 20);
+ tt_int_op(0, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND,
+ p, 26+TAP_ONIONSKIN_CHALLENGE_LEN));
+ tt_int_op(RELAY_COMMAND_EXTEND, ==, ec.cell_type);
+ tt_str_op("18.244.0.1", ==, fmt_addr(&ec.orport_ipv4.addr));
+ tt_int_op(258, ==, ec.orport_ipv4.port);
+ tt_int_op(AF_UNSPEC, ==, tor_addr_family(&ec.orport_ipv6.addr));
+ test_memeq(ec.node_id, "electroencephalogram", 20);
+ tt_int_op(cc->cell_type, ==, CELL_CREATE2);
+ tt_int_op(cc->handshake_type, ==, ONION_HANDSHAKE_TYPE_NTOR);
+ tt_int_op(cc->handshake_len, ==, NTOR_ONIONSKIN_LEN);
+ test_memeq(cc->onionskin, b, NTOR_ONIONSKIN_LEN+20);
+ tt_int_op(0, ==, extend_cell_format(&p2_cmd, &p2_len, p2, &ec));
+ tt_int_op(p2_cmd, ==, RELAY_COMMAND_EXTEND);
+ tt_int_op(p2_len, ==, 26+TAP_ONIONSKIN_CHALLENGE_LEN);
+ test_memeq(p2, p, RELAY_PAYLOAD_SIZE);
+ tt_int_op(0, ==, create_cell_format_relayed(&cell, cc));
+
+ /* Now let's do a minimal ntor EXTEND2 cell. */
+ memset(&ec, 0xff, sizeof(ec));
+ memset(p, 0, sizeof(p));
+ memset(b, 0, sizeof(b));
+ crypto_rand((char*)b, NTOR_ONIONSKIN_LEN);
+ /* 2 items; one 18.244.0.1:61681 */
+ memcpy(p, "\x02\x00\x06\x12\xf4\x00\x01\xf0\xf1", 9);
+ /* The other is a digest. */
+ memcpy(p+9, "\x02\x14" "anarchoindividualist", 22);
+ /* Prep for the handshake: type and length */
+ memcpy(p+31, "\x00\x02\x00\x54", 4);
+ memcpy(p+35, b, NTOR_ONIONSKIN_LEN);
+ tt_int_op(0, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
+ p, 35+NTOR_ONIONSKIN_LEN));
+ tt_int_op(RELAY_COMMAND_EXTEND2, ==, ec.cell_type);
+ tt_str_op("18.244.0.1", ==, fmt_addr(&ec.orport_ipv4.addr));
+ tt_int_op(61681, ==, ec.orport_ipv4.port);
+ tt_int_op(AF_UNSPEC, ==, tor_addr_family(&ec.orport_ipv6.addr));
+ test_memeq(ec.node_id, "anarchoindividualist", 20);
+ tt_int_op(cc->cell_type, ==, CELL_CREATE2);
+ tt_int_op(cc->handshake_type, ==, ONION_HANDSHAKE_TYPE_NTOR);
+ tt_int_op(cc->handshake_len, ==, NTOR_ONIONSKIN_LEN);
+ test_memeq(cc->onionskin, b, NTOR_ONIONSKIN_LEN+20);
+ tt_int_op(0, ==, extend_cell_format(&p2_cmd, &p2_len, p2, &ec));
+ tt_int_op(p2_cmd, ==, RELAY_COMMAND_EXTEND2);
+ tt_int_op(p2_len, ==, 35+NTOR_ONIONSKIN_LEN);
+ test_memeq(p2, p, RELAY_PAYLOAD_SIZE);
+
+ /* Now let's do a fanciful EXTEND2 cell. */
+ memset(&ec, 0xff, sizeof(ec));
+ memset(p, 0, sizeof(p));
+ memset(b, 0, sizeof(b));
+ crypto_rand((char*)b, 99);
+ /* 4 items; one 18 244 0 1 61681 */
+ memcpy(p, "\x04\x00\x06\x12\xf4\x00\x01\xf0\xf1", 9);
+ /* One is a digest. */
+ memcpy(p+9, "\x02\x14" "anthropomorphization", 22);
+ /* One is an ipv6 address */
+ memcpy(p+31, "\x01\x12\x20\x02\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\xf0\xc5\x1e\x11\x12", 20);
+ /* One is the Konami code. */
+ memcpy(p+51, "\xf0\x20upupdowndownleftrightleftrightba", 34);
+ /* Prep for the handshake: weird type and length */
+ memcpy(p+85, "\x01\x05\x00\x63", 4);
+ memcpy(p+89, b, 99);
+ tt_int_op(0, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2, p, 89+99));
+ tt_int_op(RELAY_COMMAND_EXTEND2, ==, ec.cell_type);
+ tt_str_op("18.244.0.1", ==, fmt_addr(&ec.orport_ipv4.addr));
+ tt_int_op(61681, ==, ec.orport_ipv4.port);
+ tt_str_op("2002::f0:c51e", ==, fmt_addr(&ec.orport_ipv6.addr));
+ tt_int_op(4370, ==, ec.orport_ipv6.port);
+ test_memeq(ec.node_id, "anthropomorphization", 20);
+ tt_int_op(cc->cell_type, ==, CELL_CREATE2);
+ tt_int_op(cc->handshake_type, ==, 0x105);
+ tt_int_op(cc->handshake_len, ==, 99);
+ test_memeq(cc->onionskin, b, 99+20);
+ tt_int_op(0, ==, extend_cell_format(&p2_cmd, &p2_len, p2, &ec));
+ tt_int_op(p2_cmd, ==, RELAY_COMMAND_EXTEND2);
+ /* We'll generate it minus the IPv6 address and minus the konami code */
+ tt_int_op(p2_len, ==, 89+99-34-20);
+ test_memeq_hex(p2,
+ /* Two items: one that same darn IP address. */
+ "02000612F40001F0F1"
+ /* The next is a digest : anthropomorphization */
+ "0214616e7468726f706f6d6f727068697a6174696f6e"
+ /* Now the handshake prologue */
+ "01050063");
+ test_memeq(p2+1+8+22+4, b, 99+20);
+ tt_int_op(0, ==, create_cell_format_relayed(&cell, cc));
+
+ /* == Now try parsing some junk */
+
+ /* Try a too-long handshake */
+ memset(p, 0, sizeof(p));
+ memcpy(p, "\x02\x00\x06\x12\xf4\x00\x01\xf0\xf1", 9);
+ memcpy(p+9, "\x02\x14" "anarchoindividualist", 22);
+ memcpy(p+31, "\xff\xff\x01\xd0", 4);
+ tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
+ p, sizeof(p)));
+
+ /* Try two identities. */
+ memset(p, 0, sizeof(p));
+ memcpy(p, "\x03\x00\x06\x12\xf4\x00\x01\xf0\xf1", 9);
+ memcpy(p+9, "\x02\x14" "anarchoindividualist", 22);
+ memcpy(p+31, "\x02\x14" "autodepolymerization", 22);
+ memcpy(p+53, "\xff\xff\x00\x10", 4);
+ tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
+ p, sizeof(p)));
+
+ /* No identities. */
+ memset(p, 0, sizeof(p));
+ memcpy(p, "\x01\x00\x06\x12\xf4\x00\x01\xf0\xf1", 9);
+ memcpy(p+53, "\xff\xff\x00\x10", 4);
+ tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
+ p, sizeof(p)));
+
+ /* Try a bad IPv4 address (too long, too short)*/
+ memset(p, 0, sizeof(p));
+ memcpy(p, "\x02\x00\x07\x12\xf4\x00\x01\xf0\xf1\xff", 10);
+ memcpy(p+10, "\x02\x14" "anarchoindividualist", 22);
+ memcpy(p+32, "\xff\xff\x00\x10", 4);
+ tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
+ p, sizeof(p)));
+ memset(p, 0, sizeof(p));
+ memcpy(p, "\x02\x00\x05\x12\xf4\x00\x01\xf0", 8);
+ memcpy(p+8, "\x02\x14" "anarchoindividualist", 22);
+ memcpy(p+30, "\xff\xff\x00\x10", 4);
+ tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
+ p, sizeof(p)));
+
+ /* IPv6 address (too long, too short, no IPv4)*/
+ memset(p, 0, sizeof(p));
+ memcpy(p, "\x03\x00\x06\x12\xf4\x00\x01\xf0\xf1", 9);
+ memcpy(p+9, "\x02\x14" "anarchoindividualist", 22);
+ memcpy(p+31, "\x01\x13" "xxxxxxxxxxxxxxxxYYZ", 19);
+ memcpy(p+50, "\xff\xff\x00\x20", 4);
+ tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
+ p, sizeof(p)));
+ memset(p, 0, sizeof(p));
+ memcpy(p, "\x03\x00\x06\x12\xf4\x00\x01\xf0\xf1", 9);
+ memcpy(p+9, "\x02\x14" "anarchoindividualist", 22);
+ memcpy(p+31, "\x01\x11" "xxxxxxxxxxxxxxxxY", 17);
+ memcpy(p+48, "\xff\xff\x00\x20", 4);
+ tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
+ p, sizeof(p)));
+ memset(p, 0, sizeof(p));
+ memcpy(p, "\x02", 1);
+ memcpy(p+1, "\x02\x14" "anarchoindividualist", 22);
+ memcpy(p+23, "\x01\x12" "xxxxxxxxxxxxxxxxYY", 18);
+ memcpy(p+41, "\xff\xff\x00\x20", 4);
+ tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
+ p, sizeof(p)));
+
+ /* Running out of space in specifiers */
+ memset(p,0,sizeof(p));
+ memcpy(p, "\x05\x0a\xff", 3);
+ memcpy(p+3+255, "\x0a\xff", 2);
+ tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
+ p, sizeof(p)));
+
+ /* Fuzz, because why not. */
+ memset(&ec, 0xff, sizeof(ec));
+ {
+ int i;
+ memset(p, 0, sizeof(p));
+ for (i = 0; i < 10000; ++i) {
+ int n = crypto_rand_int(sizeof(p));
+ crypto_rand((char *)p, n);
+ extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2, p, n);
+ }
+ }
+
+ done:
+ tor_free(mem_op_hex_tmp);
+}
+
+static void
+test_cfmt_extended_cells(void *arg)
+{
+ uint8_t b[512];
+ extended_cell_t ec;
+ created_cell_t *cc = &ec.created_cell;
+ uint8_t p[RELAY_PAYLOAD_SIZE];
+ uint8_t p2[RELAY_PAYLOAD_SIZE];
+ uint8_t p2_cmd;
+ uint16_t p2_len;
+ char *mem_op_hex_tmp = NULL;
+
+ (void) arg;
+
+ /* Try a regular EXTENDED cell. */
+ memset(&ec, 0xff, sizeof(ec));
+ memset(p, 0, sizeof(p));
+ memset(b, 0, sizeof(b));
+ crypto_rand((char*)b, TAP_ONIONSKIN_REPLY_LEN);
+ memcpy(p,b,TAP_ONIONSKIN_REPLY_LEN);
+ tt_int_op(0, ==, extended_cell_parse(&ec, RELAY_COMMAND_EXTENDED, p,
+ TAP_ONIONSKIN_REPLY_LEN));
+ tt_int_op(RELAY_COMMAND_EXTENDED, ==, ec.cell_type);
+ tt_int_op(cc->cell_type, ==, CELL_CREATED);
+ tt_int_op(cc->handshake_len, ==, TAP_ONIONSKIN_REPLY_LEN);
+ test_memeq(cc->reply, b, TAP_ONIONSKIN_REPLY_LEN);
+ tt_int_op(0, ==, extended_cell_format(&p2_cmd, &p2_len, p2, &ec));
+ tt_int_op(RELAY_COMMAND_EXTENDED, ==, p2_cmd);
+ tt_int_op(TAP_ONIONSKIN_REPLY_LEN, ==, p2_len);
+ test_memeq(p2, p, sizeof(p2));
+
+ /* Try an EXTENDED2 cell */
+ memset(&ec, 0xff, sizeof(ec));
+ memset(p, 0, sizeof(p));
+ memset(b, 0, sizeof(b));
+ crypto_rand((char*)b, 42);
+ memcpy(p,"\x00\x2a",2);
+ memcpy(p+2,b,42);
+ tt_int_op(0, ==, extended_cell_parse(&ec, RELAY_COMMAND_EXTENDED2, p, 2+42));
+ tt_int_op(RELAY_COMMAND_EXTENDED2, ==, ec.cell_type);
+ tt_int_op(cc->cell_type, ==, CELL_CREATED2);
+ tt_int_op(cc->handshake_len, ==, 42);
+ test_memeq(cc->reply, b, 42+10);
+ tt_int_op(0, ==, extended_cell_format(&p2_cmd, &p2_len, p2, &ec));
+ tt_int_op(RELAY_COMMAND_EXTENDED2, ==, p2_cmd);
+ tt_int_op(2+42, ==, p2_len);
+ test_memeq(p2, p, sizeof(p2));
+
+ /* Try an almost-too-long EXTENDED2 cell */
+ memcpy(p, "\x01\xf0", 2);
+ tt_int_op(0, ==,
+ extended_cell_parse(&ec, RELAY_COMMAND_EXTENDED2, p, sizeof(p)));
+
+ /* Now try a too-long extended2 cell. That's the only misparse I can think
+ * of. */
+ memcpy(p, "\x01\xf1", 2);
+ tt_int_op(-1, ==,
+ extended_cell_parse(&ec, RELAY_COMMAND_EXTENDED2, p, sizeof(p)));
+
+ done:
+ tor_free(mem_op_hex_tmp);
+}
+
+#define TEST(name, flags) \
+ { #name, test_cfmt_ ## name, flags, 0, NULL }
+
+struct testcase_t cell_format_tests[] = {
+ TEST(relay_header, 0),
+ TEST(begin_cells, 0),
+ TEST(connected_cells, 0),
+ TEST(create_cells, 0),
+ TEST(created_cells, 0),
+ TEST(extend_cells, 0),
+ TEST(extended_cells, 0),
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_config.c b/src/test/test_config.c
index ff251a24d..e20fe7329 100644
--- a/src/test/test_config.c
+++ b/src/test/test_config.c
@@ -1,11 +1,13 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
#include "or.h"
+#include "addressmap.h"
#include "config.h"
+#include "confparse.h"
#include "connection_edge.h"
#include "test.h"
@@ -40,6 +42,11 @@ test_config_addressmap(void *arg)
config_get_lines(buf, &(get_options_mutable()->AddressMap), 0);
config_register_addressmaps(get_options());
+/* Use old interface for now, so we don't need to rewrite the unit tests */
+#define addressmap_rewrite(a,s,eo,ao) \
+ addressmap_rewrite((a),(s),AMR_FLAG_USE_IPV4_DNS|AMR_FLAG_USE_IPV6_DNS, \
+ (eo),(ao))
+
/* MapAddress .invalidwildcard.com .torserver.exit - no match */
strlcpy(address, "www.invalidwildcard.com", sizeof(address));
test_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL));
@@ -156,6 +163,8 @@ test_config_addressmap(void *arg)
strlcpy(address, "www.torproject.org", sizeof(address));
test_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL));
+#undef addressmap_rewrite
+
done:
;
}
diff --git a/src/test/test_containers.c b/src/test/test_containers.c
index 45898df4e..005e102e2 100644
--- a/src/test/test_containers.c
+++ b/src/test/test_containers.c
@@ -1,16 +1,17 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
#include "or.h"
+#include "fp_pair.h"
#include "test.h"
/** Helper: return a tristate based on comparing the strings in *<b>a</b> and
* *<b>b</b>. */
static int
-_compare_strs(const void **a, const void **b)
+compare_strs_(const void **a, const void **b)
{
const char *s1 = *a, *s2 = *b;
return strcmp(s1, s2);
@@ -28,7 +29,7 @@ compare_strs_for_bsearch_(const void *a, const void **b)
/** Helper: return a tristate based on comparing the strings in *<b>a</b> and
* *<b>b</b>, excluding a's first character, and ignoring case. */
static int
-_compare_without_first_ch(const void *a, const void **b)
+compare_without_first_ch_(const void *a, const void **b)
{
const char *s1 = a, *s2 = *b;
return strcasecmp(s1+1, s2);
@@ -66,8 +67,8 @@ test_container_smartlist_basic(void)
test_eq(4, smartlist_len(sl));
/* test isin. */
- test_assert(smartlist_isin(sl, (void*)3));
- test_assert(!smartlist_isin(sl, (void*)99));
+ test_assert(smartlist_contains(sl, (void*)3));
+ test_assert(!smartlist_contains(sl, (void*)99));
done:
smartlist_free(sl);
@@ -185,7 +186,7 @@ test_container_smartlist_strings(void)
/* Test swapping, shuffling, and sorting. */
smartlist_split_string(sl, "the,onion,router,by,arma,and,nickm", ",", 0, 0);
test_eq(7, smartlist_len(sl));
- smartlist_sort(sl, _compare_strs);
+ smartlist_sort(sl, compare_strs_);
cp_alloc = smartlist_join_strings(sl, ",", 0, NULL);
test_streq(cp_alloc,"and,arma,by,nickm,onion,router,the");
tor_free(cp_alloc);
@@ -195,37 +196,37 @@ test_container_smartlist_strings(void)
tor_free(cp_alloc);
smartlist_shuffle(sl);
test_eq(7, smartlist_len(sl));
- test_assert(smartlist_string_isin(sl, "and"));
- test_assert(smartlist_string_isin(sl, "router"));
- test_assert(smartlist_string_isin(sl, "by"));
- test_assert(smartlist_string_isin(sl, "nickm"));
- test_assert(smartlist_string_isin(sl, "onion"));
- test_assert(smartlist_string_isin(sl, "arma"));
- test_assert(smartlist_string_isin(sl, "the"));
+ test_assert(smartlist_contains_string(sl, "and"));
+ test_assert(smartlist_contains_string(sl, "router"));
+ test_assert(smartlist_contains_string(sl, "by"));
+ test_assert(smartlist_contains_string(sl, "nickm"));
+ test_assert(smartlist_contains_string(sl, "onion"));
+ test_assert(smartlist_contains_string(sl, "arma"));
+ test_assert(smartlist_contains_string(sl, "the"));
/* Test bsearch. */
- smartlist_sort(sl, _compare_strs);
+ smartlist_sort(sl, compare_strs_);
test_streq("nickm", smartlist_bsearch(sl, "zNicKM",
- _compare_without_first_ch));
- test_streq("and", smartlist_bsearch(sl, " AND", _compare_without_first_ch));
- test_eq_ptr(NULL, smartlist_bsearch(sl, " ANz", _compare_without_first_ch));
+ compare_without_first_ch_));
+ test_streq("and", smartlist_bsearch(sl, " AND", compare_without_first_ch_));
+ test_eq_ptr(NULL, smartlist_bsearch(sl, " ANz", compare_without_first_ch_));
/* Test bsearch_idx */
{
int f;
smartlist_t *tmp = NULL;
- test_eq(0, smartlist_bsearch_idx(sl," aaa",_compare_without_first_ch,&f));
+ test_eq(0, smartlist_bsearch_idx(sl," aaa",compare_without_first_ch_,&f));
test_eq(f, 0);
- test_eq(0, smartlist_bsearch_idx(sl," and",_compare_without_first_ch,&f));
+ test_eq(0, smartlist_bsearch_idx(sl," and",compare_without_first_ch_,&f));
test_eq(f, 1);
- test_eq(1, smartlist_bsearch_idx(sl," arm",_compare_without_first_ch,&f));
+ test_eq(1, smartlist_bsearch_idx(sl," arm",compare_without_first_ch_,&f));
test_eq(f, 0);
- test_eq(1, smartlist_bsearch_idx(sl," arma",_compare_without_first_ch,&f));
+ test_eq(1, smartlist_bsearch_idx(sl," arma",compare_without_first_ch_,&f));
test_eq(f, 1);
- test_eq(2, smartlist_bsearch_idx(sl," armb",_compare_without_first_ch,&f));
+ test_eq(2, smartlist_bsearch_idx(sl," armb",compare_without_first_ch_,&f));
test_eq(f, 0);
- test_eq(7, smartlist_bsearch_idx(sl," zzzz",_compare_without_first_ch,&f));
+ test_eq(7, smartlist_bsearch_idx(sl," zzzz",compare_without_first_ch_,&f));
test_eq(f, 0);
/* Test trivial cases for list of length 0 or 1 */
@@ -266,25 +267,25 @@ test_container_smartlist_strings(void)
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
smartlist_clear(sl);
cp_alloc = smartlist_pop_last(sl);
- test_eq(cp_alloc, NULL);
+ test_eq_ptr(cp_alloc, NULL);
/* Test uniq() */
smartlist_split_string(sl,
"50,noon,radar,a,man,a,plan,a,canal,panama,radar,noon,50",
",", 0, 0);
- smartlist_sort(sl, _compare_strs);
- smartlist_uniq(sl, _compare_strs, _tor_free);
+ smartlist_sort(sl, compare_strs_);
+ smartlist_uniq(sl, compare_strs_, tor_free_);
cp_alloc = smartlist_join_strings(sl, ",", 0, NULL);
test_streq(cp_alloc, "50,a,canal,man,noon,panama,plan,radar");
tor_free(cp_alloc);
- /* Test string_isin and isin_case and num_isin */
- test_assert(smartlist_string_isin(sl, "noon"));
- test_assert(!smartlist_string_isin(sl, "noonoon"));
- test_assert(smartlist_string_isin_case(sl, "nOOn"));
- test_assert(!smartlist_string_isin_case(sl, "nooNooN"));
- test_assert(smartlist_string_num_isin(sl, 50));
- test_assert(!smartlist_string_num_isin(sl, 60));
+ /* Test contains_string, contains_string_case and contains_int_as_string */
+ test_assert(smartlist_contains_string(sl, "noon"));
+ test_assert(!smartlist_contains_string(sl, "noonoon"));
+ test_assert(smartlist_contains_string_case(sl, "nOOn"));
+ test_assert(!smartlist_contains_string_case(sl, "nooNooN"));
+ test_assert(smartlist_contains_int_as_string(sl, 50));
+ test_assert(!smartlist_contains_int_as_string(sl, 60));
/* Test smartlist_choose */
{
@@ -292,12 +293,12 @@ test_container_smartlist_strings(void)
int allsame = 1;
int allin = 1;
void *first = smartlist_choose(sl);
- test_assert(smartlist_isin(sl, first));
+ test_assert(smartlist_contains(sl, first));
for (i = 0; i < 100; ++i) {
void *second = smartlist_choose(sl);
if (second != first)
allsame = 0;
- if (!smartlist_isin(sl, second))
+ if (!smartlist_contains(sl, second))
allin = 0;
}
test_assert(!allsame);
@@ -365,15 +366,15 @@ test_container_smartlist_overlap(void)
smartlist_add_all(sl, odds);
smartlist_intersect(sl, primes);
test_eq(smartlist_len(sl), 3);
- test_assert(smartlist_isin(sl, (void*)3));
- test_assert(smartlist_isin(sl, (void*)5));
- test_assert(smartlist_isin(sl, (void*)7));
+ test_assert(smartlist_contains(sl, (void*)3));
+ test_assert(smartlist_contains(sl, (void*)5));
+ test_assert(smartlist_contains(sl, (void*)7));
/* subtract */
smartlist_add_all(sl, primes);
smartlist_subtract(sl, odds);
test_eq(smartlist_len(sl), 1);
- test_assert(smartlist_isin(sl, (void*)2));
+ test_assert(smartlist_contains(sl, (void*)2));
done:
smartlist_free(odds);
@@ -389,14 +390,14 @@ test_container_smartlist_digests(void)
{
smartlist_t *sl = smartlist_new();
- /* digest_isin. */
+ /* contains_digest */
smartlist_add(sl, tor_memdup("AAAAAAAAAAAAAAAAAAAA", DIGEST_LEN));
smartlist_add(sl, tor_memdup("\00090AAB2AAAAaasdAAAAA", DIGEST_LEN));
smartlist_add(sl, tor_memdup("\00090AAB2AAAAaasdAAAAA", DIGEST_LEN));
- test_eq(0, smartlist_digest_isin(NULL, "AAAAAAAAAAAAAAAAAAAA"));
- test_assert(smartlist_digest_isin(sl, "AAAAAAAAAAAAAAAAAAAA"));
- test_assert(smartlist_digest_isin(sl, "\00090AAB2AAAAaasdAAAAA"));
- test_eq(0, smartlist_digest_isin(sl, "\00090AAB2AAABaasdAAAAA"));
+ test_eq(0, smartlist_contains_digest(NULL, "AAAAAAAAAAAAAAAAAAAA"));
+ test_assert(smartlist_contains_digest(sl, "AAAAAAAAAAAAAAAAAAAA"));
+ test_assert(smartlist_contains_digest(sl, "\00090AAB2AAAAaasdAAAAA"));
+ test_eq(0, smartlist_contains_digest(sl, "\00090AAB2AAABaasdAAAAA"));
/* sort digests */
smartlist_sort_digests(sl);
@@ -445,11 +446,11 @@ test_container_smartlist_join(void)
} SMARTLIST_FOREACH_JOIN_END(cp1, cp2);
SMARTLIST_FOREACH(sl3, const char *, cp,
- test_assert(smartlist_isin(sl2, cp) &&
- !smartlist_string_isin(sl, cp)));
+ test_assert(smartlist_contains(sl2, cp) &&
+ !smartlist_contains_string(sl, cp)));
SMARTLIST_FOREACH(sl4, const char *, cp,
- test_assert(smartlist_isin(sl, cp) &&
- smartlist_string_isin(sl2, cp)));
+ test_assert(smartlist_contains(sl, cp) &&
+ smartlist_contains_string(sl2, cp)));
joined = smartlist_join_strings(sl3, ",", 0, NULL);
test_streq(joined, "Anemias,Anemias,Crossbowmen,Work");
tor_free(joined);
@@ -528,18 +529,18 @@ test_container_digestset(void)
}
set = digestset_new(1000);
SMARTLIST_FOREACH(included, const char *, cp,
- if (digestset_isin(set, cp))
+ if (digestset_contains(set, cp))
ok = 0);
test_assert(ok);
SMARTLIST_FOREACH(included, const char *, cp,
digestset_add(set, cp));
SMARTLIST_FOREACH(included, const char *, cp,
- if (!digestset_isin(set, cp))
+ if (!digestset_contains(set, cp))
ok = 0);
test_assert(ok);
for (i = 0; i < 1000; ++i) {
crypto_rand(d, DIGEST_LEN);
- if (digestset_isin(set, d))
+ if (digestset_contains(set, d))
++false_positives;
}
test_assert(false_positives < 50); /* Should be far lower. */
@@ -558,7 +559,7 @@ typedef struct pq_entry_t {
/** Helper: return a tristate based on comparing two pq_entry_t values. */
static int
-_compare_strings_for_pqueue(const void *p1, const void *p2)
+compare_strings_for_pqueue_(const void *p1, const void *p2)
{
const pq_entry_t *e1=p1, *e2=p2;
return strcmp(e1->val, e2->val);
@@ -588,7 +589,7 @@ test_container_pqueue(void)
#define OK() smartlist_pqueue_assert_ok(sl, cmp, offset)
- cmp = _compare_strings_for_pqueue;
+ cmp = compare_strings_for_pqueue_;
smartlist_pqueue_add(sl, cmp, offset, &cows);
smartlist_pqueue_add(sl, cmp, offset, &zebras);
smartlist_pqueue_add(sl, cmp, offset, &fish);
@@ -677,12 +678,12 @@ test_container_strmap(void)
test_eq(strmap_size(map), 0);
test_assert(strmap_isempty(map));
v = strmap_set(map, "K1", (void*)99);
- test_eq(v, NULL);
+ test_eq_ptr(v, NULL);
test_assert(!strmap_isempty(map));
v = strmap_set(map, "K2", (void*)101);
- test_eq(v, NULL);
+ test_eq_ptr(v, NULL);
v = strmap_set(map, "K1", (void*)100);
- test_eq(v, (void*)99);
+ test_eq_ptr(v, (void*)99);
test_eq_ptr(strmap_get(map,"K1"), (void*)100);
test_eq_ptr(strmap_get(map,"K2"), (void*)101);
test_eq_ptr(strmap_get(map,"K-not-there"), NULL);
@@ -782,6 +783,132 @@ test_container_order_functions(void)
;
}
+static void
+test_di_map(void *arg)
+{
+ di_digest256_map_t *map = NULL;
+ const uint8_t key1[] = "In view of the fact that it was ";
+ const uint8_t key2[] = "superficially convincing, being ";
+ const uint8_t key3[] = "properly enciphered in a one-tim";
+ const uint8_t key4[] = "e cipher scheduled for use today";
+ char *v1 = tor_strdup(", it came close to causing a disaster...");
+ char *v2 = tor_strdup("I regret to have to advise you that the mission");
+ char *v3 = tor_strdup("was actually initiated...");
+ /* -- John Brunner, _The Shockwave Rider_ */
+
+ (void)arg;
+
+ /* Try searching on an empty map. */
+ tt_ptr_op(NULL, ==, dimap_search(map, key1, NULL));
+ tt_ptr_op(NULL, ==, dimap_search(map, key2, NULL));
+ tt_ptr_op(v3, ==, dimap_search(map, key2, v3));
+ dimap_free(map, NULL);
+ map = NULL;
+
+ /* Add a single entry. */
+ dimap_add_entry(&map, key1, v1);
+ tt_ptr_op(NULL, ==, dimap_search(map, key2, NULL));
+ tt_ptr_op(v3, ==, dimap_search(map, key2, v3));
+ tt_ptr_op(v1, ==, dimap_search(map, key1, NULL));
+
+ /* Now try it with three entries in the map. */
+ dimap_add_entry(&map, key2, v2);
+ dimap_add_entry(&map, key3, v3);
+ tt_ptr_op(v1, ==, dimap_search(map, key1, NULL));
+ tt_ptr_op(v2, ==, dimap_search(map, key2, NULL));
+ tt_ptr_op(v3, ==, dimap_search(map, key3, NULL));
+ tt_ptr_op(NULL, ==, dimap_search(map, key4, NULL));
+ tt_ptr_op(v1, ==, dimap_search(map, key4, v1));
+
+ done:
+ tor_free(v1);
+ tor_free(v2);
+ tor_free(v3);
+ dimap_free(map, NULL);
+}
+
+/** Run unit tests for fp_pair-to-void* map functions */
+static void
+test_container_fp_pair_map(void)
+{
+ fp_pair_map_t *map;
+ fp_pair_t fp1, fp2, fp3, fp4, fp5, fp6;
+ void *v;
+ fp_pair_map_iter_t *iter;
+ fp_pair_t k;
+
+ map = fp_pair_map_new();
+ test_assert(map);
+ test_eq(fp_pair_map_size(map), 0);
+ test_assert(fp_pair_map_isempty(map));
+
+ memset(fp1.first, 0x11, DIGEST_LEN);
+ memset(fp1.second, 0x12, DIGEST_LEN);
+ memset(fp2.first, 0x21, DIGEST_LEN);
+ memset(fp2.second, 0x22, DIGEST_LEN);
+ memset(fp3.first, 0x31, DIGEST_LEN);
+ memset(fp3.second, 0x32, DIGEST_LEN);
+ memset(fp4.first, 0x41, DIGEST_LEN);
+ memset(fp4.second, 0x42, DIGEST_LEN);
+ memset(fp5.first, 0x51, DIGEST_LEN);
+ memset(fp5.second, 0x52, DIGEST_LEN);
+ memset(fp6.first, 0x61, DIGEST_LEN);
+ memset(fp6.second, 0x62, DIGEST_LEN);
+
+ v = fp_pair_map_set(map, &fp1, (void*)99);
+ test_eq(v, NULL);
+ test_assert(!fp_pair_map_isempty(map));
+ v = fp_pair_map_set(map, &fp2, (void*)101);
+ test_eq(v, NULL);
+ v = fp_pair_map_set(map, &fp1, (void*)100);
+ test_eq(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);
+ fp_pair_map_assert_ok(map);
+
+ v = fp_pair_map_remove(map, &fp2);
+ fp_pair_map_assert_ok(map);
+ test_eq_ptr(v, (void*)101);
+ test_eq_ptr(fp_pair_map_get(map, &fp2), NULL);
+ test_eq_ptr(fp_pair_map_remove(map, &fp2), NULL);
+
+ fp_pair_map_set(map, &fp2, (void*)101);
+ fp_pair_map_set(map, &fp3, (void*)102);
+ fp_pair_map_set(map, &fp4, (void*)103);
+ test_eq(fp_pair_map_size(map), 4);
+ fp_pair_map_assert_ok(map);
+ fp_pair_map_set(map, &fp5, (void*)104);
+ fp_pair_map_set(map, &fp6, (void*)105);
+ fp_pair_map_assert_ok(map);
+
+ /* Test iterator. */
+ iter = fp_pair_map_iter_init(map);
+ while (!fp_pair_map_iter_done(iter)) {
+ fp_pair_map_iter_get(iter, &k, &v);
+ test_eq_ptr(v, fp_pair_map_get(map, &k));
+
+ if (tor_memeq(&fp2, &k, sizeof(fp2))) {
+ iter = fp_pair_map_iter_next_rmv(map, iter);
+ } else {
+ iter = fp_pair_map_iter_next(map, iter);
+ }
+ }
+
+ /* Make sure we removed fp2, but not the others. */
+ test_eq_ptr(fp_pair_map_get(map, &fp2), NULL);
+ test_eq_ptr(fp_pair_map_get(map, &fp5), (void*)104);
+
+ fp_pair_map_assert_ok(map);
+ /* Clean up after ourselves. */
+ fp_pair_map_free(map, NULL);
+ map = NULL;
+
+ done:
+ if (map)
+ fp_pair_map_free(map, NULL);
+}
+
#define CONTAINER_LEGACY(name) \
{ #name, legacy_test_helper, 0, &legacy_setup, test_container_ ## name }
@@ -796,6 +923,8 @@ struct testcase_t container_tests[] = {
CONTAINER_LEGACY(strmap),
CONTAINER_LEGACY(pqueue),
CONTAINER_LEGACY(order_functions),
+ { "di_map", test_di_map, 0, NULL, NULL },
+ CONTAINER_LEGACY(fp_pair_map),
END_OF_TESTCASES
};
diff --git a/src/test/test_crypto.c b/src/test/test_crypto.c
index 7f4347a41..f92bfd673 100644
--- a/src/test/test_crypto.c
+++ b/src/test/test_crypto.c
@@ -1,13 +1,18 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* 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"
+#ifdef CURVE25519_ENABLED
+#include "crypto_curve25519.h"
+#endif
/** Run unit tests for Diffie-Hellman functionality. */
static void
@@ -119,9 +124,9 @@ test_crypto_aes(void *arg)
memset(data2, 0, 1024);
memset(data3, 0, 1024);
env1 = crypto_cipher_new(NULL);
- test_neq(env1, 0);
+ test_neq_ptr(env1, 0);
env2 = crypto_cipher_new(crypto_cipher_get_key(env1));
- test_neq(env2, 0);
+ test_neq_ptr(env2, 0);
/* Try encrypting 512 chars. */
crypto_cipher_encrypt(env1, data2, data1, 512);
@@ -152,7 +157,7 @@ test_crypto_aes(void *arg)
memset(data3, 0, 1024);
env2 = crypto_cipher_new(crypto_cipher_get_key(env1));
- test_neq(env2, 0);
+ test_neq_ptr(env2, NULL);
for (j = 0; j < 1024-16; j += 17) {
crypto_cipher_encrypt(env2, data3+j, data1+j, 17);
}
@@ -427,6 +432,11 @@ test_crypto_pk(void)
test_assert(! crypto_pk_read_public_key_from_string(pk2, encoded, size));
test_eq(0, crypto_pk_cmp_keys(pk1, pk2));
+ /* comparison between keys and NULL */
+ tt_int_op(crypto_pk_cmp_keys(NULL, pk1), <, 0);
+ tt_int_op(crypto_pk_cmp_keys(NULL, NULL), ==, 0);
+ tt_int_op(crypto_pk_cmp_keys(pk1, NULL), >, 0);
+
test_eq(128, crypto_pk_keysize(pk1));
test_eq(1024, crypto_pk_num_bits(pk1));
test_eq(128, crypto_pk_keysize(pk2));
@@ -626,22 +636,6 @@ test_crypto_formats(void)
tor_free(data2);
}
- /* Check fingerprint */
- {
- test_assert(crypto_pk_check_fingerprint_syntax(
- "ABCD 1234 ABCD 5678 0000 ABCD 1234 ABCD 5678 0000"));
- test_assert(!crypto_pk_check_fingerprint_syntax(
- "ABCD 1234 ABCD 5678 0000 ABCD 1234 ABCD 5678 000"));
- test_assert(!crypto_pk_check_fingerprint_syntax(
- "ABCD 1234 ABCD 5678 0000 ABCD 1234 ABCD 5678 00000"));
- test_assert(!crypto_pk_check_fingerprint_syntax(
- "ABCD 1234 ABCD 5678 0000 ABCD1234 ABCD 5678 0000"));
- test_assert(!crypto_pk_check_fingerprint_syntax(
- "ABCD 1234 ABCD 5678 0000 ABCD1234 ABCD 5678 00000"));
- test_assert(!crypto_pk_check_fingerprint_syntax(
- "ACD 1234 ABCD 5678 0000 ABCD 1234 ABCD 5678 00000"));
- }
-
done:
tor_free(data1);
tor_free(data2);
@@ -736,7 +730,7 @@ 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_memneq(plain, decrypted2, encrypted_size);
+ test_memneq(plain, decrypted2, decrypted_size);
/* Alter the initialization vector. */
encrypted1[0] += 42;
decrypted_size = crypto_cipher_decrypt_with_iv(key1, decrypted1, 4095,
@@ -827,6 +821,293 @@ test_crypto_base32_decode(void)
;
}
+static void
+test_crypto_kdf_TAP(void *arg)
+{
+ uint8_t key_material[100];
+ int r;
+ char *mem_op_hex_tmp = NULL;
+
+ (void)arg;
+#define EXPAND(s) \
+ r = crypto_expand_key_material_TAP( \
+ (const uint8_t*)(s), strlen(s), \
+ key_material, 100)
+
+ /* Test vectors generated with a little python script; feel free to write
+ * your own. */
+ memset(key_material, 0, sizeof(key_material));
+ EXPAND("");
+ tt_int_op(r, ==, 0);
+ test_memeq_hex(key_material,
+ "5ba93c9db0cff93f52b521d7420e43f6eda2784fbf8b4530d8"
+ "d246dd74ac53a13471bba17941dff7c4ea21bb365bbeeaf5f2"
+ "c654883e56d11e43c44e9842926af7ca0a8cca12604f945414"
+ "f07b01e13da42c6cf1de3abfdea9b95f34687cbbe92b9a7383");
+
+ EXPAND("Tor");
+ tt_int_op(r, ==, 0);
+ test_memeq_hex(key_material,
+ "776c6214fc647aaa5f683c737ee66ec44f03d0372e1cce6922"
+ "7950f236ddf1e329a7ce7c227903303f525a8c6662426e8034"
+ "870642a6dabbd41b5d97ec9bf2312ea729992f48f8ea2d0ba8"
+ "3f45dfda1a80bdc8b80de01b23e3e0ffae099b3e4ccf28dc28");
+
+ EXPAND("AN ALARMING ITEM TO FIND ON A MONTHLY AUTO-DEBIT NOTICE");
+ tt_int_op(r, ==, 0);
+ test_memeq_hex(key_material,
+ "a340b5d126086c3ab29c2af4179196dbf95e1c72431419d331"
+ "4844bf8f6afb6098db952b95581fb6c33625709d6f4400b8e7"
+ "ace18a70579fad83c0982ef73f89395bcc39493ad53a685854"
+ "daf2ba9b78733b805d9a6824c907ee1dba5ac27a1e466d4d10");
+
+ done:
+ tor_free(mem_op_hex_tmp);
+
+#undef EXPAND
+}
+
+static void
+test_crypto_hkdf_sha256(void *arg)
+{
+ uint8_t key_material[100];
+ const uint8_t salt[] = "ntor-curve25519-sha256-1:key_extract";
+ const size_t salt_len = strlen((char*)salt);
+ const uint8_t m_expand[] = "ntor-curve25519-sha256-1:key_expand";
+ const size_t m_expand_len = strlen((char*)m_expand);
+ int r;
+ char *mem_op_hex_tmp = NULL;
+
+ (void)arg;
+
+#define EXPAND(s) \
+ r = crypto_expand_key_material_rfc5869_sha256( \
+ (const uint8_t*)(s), strlen(s), \
+ salt, salt_len, \
+ m_expand, m_expand_len, \
+ key_material, 100)
+
+ /* Test vectors generated with ntor_ref.py */
+ memset(key_material, 0, sizeof(key_material));
+ EXPAND("");
+ tt_int_op(r, ==, 0);
+ test_memeq_hex(key_material,
+ "d3490ed48b12a48f9547861583573fe3f19aafe3f81dc7fc75"
+ "eeed96d741b3290f941576c1f9f0b2d463d1ec7ab2c6bf71cd"
+ "d7f826c6298c00dbfe6711635d7005f0269493edf6046cc7e7"
+ "dcf6abe0d20c77cf363e8ffe358927817a3d3e73712cee28d8");
+
+ EXPAND("Tor");
+ tt_int_op(r, ==, 0);
+ test_memeq_hex(key_material,
+ "5521492a85139a8d9107a2d5c0d9c91610d0f95989975ebee6"
+ "c02a4f8d622a6cfdf9b7c7edd3832e2760ded1eac309b76f8d"
+ "66c4a3c4d6225429b3a016e3c3d45911152fc87bc2de9630c3"
+ "961be9fdb9f93197ea8e5977180801926d3321fa21513e59ac");
+
+ EXPAND("AN ALARMING ITEM TO FIND ON YOUR CREDIT-RATING STATEMENT");
+ tt_int_op(r, ==, 0);
+ test_memeq_hex(key_material,
+ "a2aa9b50da7e481d30463adb8f233ff06e9571a0ca6ab6df0f"
+ "b206fa34e5bc78d063fc291501beec53b36e5a0e434561200c"
+ "5f8bd13e0f88b3459600b4dc21d69363e2895321c06184879d"
+ "94b18f078411be70b767c7fc40679a9440a0c95ea83a23efbf");
+
+ done:
+ tor_free(mem_op_hex_tmp);
+#undef EXPAND
+}
+
+#ifdef CURVE25519_ENABLED
+static void
+test_crypto_curve25519_impl(void *arg)
+{
+ /* adapted from curve25519_donna, which adapted it from test-curve25519
+ version 20050915, by D. J. Bernstein, Public domain. */
+
+ const int randomize_high_bit = (arg != NULL);
+
+#ifdef SLOW_CURVE25519_TEST
+ const int loop_max=10000;
+ const char e1_expected[] = "4faf81190869fd742a33691b0e0824d5"
+ "7e0329f4dd2819f5f32d130f1296b500";
+ const char e2k_expected[] = "05aec13f92286f3a781ccae98995a3b9"
+ "e0544770bc7de853b38f9100489e3e79";
+ const char e1e2k_expected[] = "cd6e8269104eb5aaee886bd2071fba88"
+ "bd13861475516bc2cd2b6e005e805064";
+#else
+ const int loop_max=200;
+ const char e1_expected[] = "bc7112cde03f97ef7008cad1bdc56be3"
+ "c6a1037d74cceb3712e9206871dcf654";
+ const char e2k_expected[] = "dd8fa254fb60bdb5142fe05b1f5de44d"
+ "8e3ee1a63c7d14274ea5d4c67f065467";
+ const char e1e2k_expected[] = "7ddb98bd89025d2347776b33901b3e7e"
+ "c0ee98cb2257a4545c0cfb2ca3e1812b";
+#endif
+
+ unsigned char e1k[32];
+ unsigned char e2k[32];
+ unsigned char e1e2k[32];
+ unsigned char e2e1k[32];
+ unsigned char e1[32] = {3};
+ unsigned char e2[32] = {5};
+ unsigned char k[32] = {9};
+ int loop, i;
+
+ char *mem_op_hex_tmp = NULL;
+
+ for (loop = 0; loop < loop_max; ++loop) {
+ curve25519_impl(e1k,e1,k);
+ curve25519_impl(e2e1k,e2,e1k);
+ curve25519_impl(e2k,e2,k);
+ if (randomize_high_bit) {
+ /* We require that the high bit of the public key be ignored. So if
+ * we're doing this variant test, we randomize the high bit of e2k, and
+ * make sure that the handshake still works out the same as it would
+ * otherwise. */
+ uint8_t byte;
+ crypto_rand((char*)&byte, 1);
+ e2k[31] |= (byte & 0x80);
+ }
+ curve25519_impl(e1e2k,e1,e2k);
+ test_memeq(e1e2k, e2e1k, 32);
+ if (loop == loop_max-1) {
+ break;
+ }
+ for (i = 0;i < 32;++i) e1[i] ^= e2k[i];
+ for (i = 0;i < 32;++i) e2[i] ^= e1k[i];
+ for (i = 0;i < 32;++i) k[i] ^= e1e2k[i];
+ }
+
+ test_memeq_hex(e1, e1_expected);
+ test_memeq_hex(e2k, e2k_expected);
+ test_memeq_hex(e1e2k, e1e2k_expected);
+
+ done:
+ tor_free(mem_op_hex_tmp);
+}
+
+static void
+test_crypto_curve25519_wrappers(void *arg)
+{
+ curve25519_public_key_t pubkey1, pubkey2;
+ curve25519_secret_key_t seckey1, seckey2;
+
+ uint8_t output1[CURVE25519_OUTPUT_LEN];
+ uint8_t output2[CURVE25519_OUTPUT_LEN];
+ (void)arg;
+
+ /* Test a simple handshake, serializing and deserializing some stuff. */
+ curve25519_secret_key_generate(&seckey1, 0);
+ curve25519_secret_key_generate(&seckey2, 1);
+ curve25519_public_key_generate(&pubkey1, &seckey1);
+ curve25519_public_key_generate(&pubkey2, &seckey2);
+ test_assert(curve25519_public_key_is_ok(&pubkey1));
+ test_assert(curve25519_public_key_is_ok(&pubkey2));
+ curve25519_handshake(output1, &seckey1, &pubkey2);
+ curve25519_handshake(output2, &seckey2, &pubkey1);
+ test_memeq(output1, output2, sizeof(output1));
+
+ done:
+ ;
+}
+
+static void
+test_crypto_curve25519_encode(void *arg)
+{
+ curve25519_secret_key_t seckey;
+ curve25519_public_key_t key1, key2, key3;
+ char buf[64];
+
+ (void)arg;
+
+ curve25519_secret_key_generate(&seckey, 0);
+ curve25519_public_key_generate(&key1, &seckey);
+ tt_int_op(0, ==, curve25519_public_to_base64(buf, &key1));
+ tt_int_op(CURVE25519_BASE64_PADDED_LEN, ==, strlen(buf));
+
+ tt_int_op(0, ==, curve25519_public_from_base64(&key2, buf));
+ test_memeq(key1.public_key, key2.public_key, CURVE25519_PUBKEY_LEN);
+
+ buf[CURVE25519_BASE64_PADDED_LEN - 1] = '\0';
+ tt_int_op(CURVE25519_BASE64_PADDED_LEN-1, ==, strlen(buf));
+ tt_int_op(0, ==, curve25519_public_from_base64(&key3, buf));
+ test_memeq(key1.public_key, key3.public_key, CURVE25519_PUBKEY_LEN);
+
+ /* Now try bogus parses. */
+ strlcpy(buf, "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$=", sizeof(buf));
+ tt_int_op(-1, ==, curve25519_public_from_base64(&key3, buf));
+
+ strlcpy(buf, "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", sizeof(buf));
+ tt_int_op(-1, ==, curve25519_public_from_base64(&key3, buf));
+
+ strlcpy(buf, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", sizeof(buf));
+ tt_int_op(-1, ==, curve25519_public_from_base64(&key3, buf));
+
+ done:
+ ;
+}
+
+static void
+test_crypto_curve25519_persist(void *arg)
+{
+ curve25519_keypair_t keypair, keypair2;
+ char *fname = tor_strdup(get_fname("curve25519_keypair"));
+ char *tag = NULL;
+ char *content = NULL;
+ const char *cp;
+ struct stat st;
+ size_t taglen;
+
+ (void)arg;
+
+ tt_int_op(0,==,curve25519_keypair_generate(&keypair, 0));
+
+ tt_int_op(0,==,curve25519_keypair_write_to_file(&keypair, fname, "testing"));
+ tt_int_op(0,==,curve25519_keypair_read_from_file(&keypair2, &tag, fname));
+ tt_str_op(tag,==,"testing");
+ tor_free(tag);
+
+ test_memeq(keypair.pubkey.public_key,
+ keypair2.pubkey.public_key,
+ CURVE25519_PUBKEY_LEN);
+ test_memeq(keypair.seckey.secret_key,
+ keypair2.seckey.secret_key,
+ CURVE25519_SECKEY_LEN);
+
+ 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_assert(fast_memeq(content, "== c25519v1: testing ==", taglen));
+ tt_assert(tor_mem_is_zero(content+taglen, 32-taglen));
+ cp = content + 32;
+ test_memeq(keypair.seckey.secret_key,
+ cp,
+ CURVE25519_SECKEY_LEN);
+ cp += CURVE25519_SECKEY_LEN;
+ test_memeq(keypair.pubkey.public_key,
+ cp,
+ CURVE25519_SECKEY_LEN);
+
+ tor_free(fname);
+ fname = tor_strdup(get_fname("bogus_keypair"));
+
+ tt_int_op(-1, ==, curve25519_keypair_read_from_file(&keypair2, &tag, fname));
+ tor_free(tag);
+
+ content[69] ^= 0xff;
+ tt_int_op(0, ==, write_bytes_to_file(fname, content, (size_t)st.st_size, 1));
+ tt_int_op(-1, ==, curve25519_keypair_read_from_file(&keypair2, &tag, fname));
+
+ done:
+ tor_free(fname);
+ tor_free(content);
+ tor_free(tag);
+}
+
+#endif
+
static void *
pass_data_setup_fn(const struct testcase_t *testcase)
{
@@ -858,6 +1139,15 @@ struct testcase_t crypto_tests[] = {
{ "aes_iv_AES", test_crypto_aes_iv, TT_FORK, &pass_data, (void*)"aes" },
{ "aes_iv_EVP", test_crypto_aes_iv, TT_FORK, &pass_data, (void*)"evp" },
CRYPTO_LEGACY(base32_decode),
+ { "kdf_TAP", test_crypto_kdf_TAP, 0, NULL, NULL },
+ { "hkdf_sha256", test_crypto_hkdf_sha256, 0, NULL, NULL },
+#ifdef CURVE25519_ENABLED
+ { "curve25519_impl", test_crypto_curve25519_impl, 0, NULL, NULL },
+ { "curve25519_impl_hibit", test_crypto_curve25519_impl, 0, NULL, (void*)"y"},
+ { "curve25519_wrappers", test_crypto_curve25519_wrappers, 0, NULL, NULL },
+ { "curve25519_encode", test_crypto_curve25519_encode, 0, NULL, NULL },
+ { "curve25519_persist", test_crypto_curve25519_persist, 0, NULL, NULL },
+#endif
END_OF_TESTCASES
};
diff --git a/src/test/test_data.c b/src/test/test_data.c
index de2f9f58e..5f0f7cba0 100644
--- a/src/test/test_data.c
+++ b/src/test/test_data.c
@@ -1,6 +1,6 @@
/* Copyright 2001-2004 Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/** First of 3 example authority certificates for unit testing. */
diff --git a/src/test/test_dir.c b/src/test/test_dir.c
index 83c612045..56ac3b34c 100644
--- a/src/test/test_dir.c
+++ b/src/test/test_dir.c
@@ -1,14 +1,18 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
+#include <math.h>
+
#define DIRSERV_PRIVATE
#define DIRVOTE_PRIVATE
#define ROUTER_PRIVATE
+#define ROUTERLIST_PRIVATE
#define HIBERNATE_PRIVATE
#include "or.h"
+#include "config.h"
#include "directory.h"
#include "dirserv.h"
#include "dirvote.h"
@@ -70,22 +74,24 @@ test_dir_nicknames(void)
static void
test_dir_formats(void)
{
- char buf[8192], buf2[8192];
+ char *buf = NULL;
+ char buf2[8192];
char platform[256];
char fingerprint[FINGERPRINT_LEN+1];
- char *pk1_str = NULL, *pk2_str = NULL, *pk3_str = NULL, *cp;
- size_t pk1_str_len, pk2_str_len, pk3_str_len;
+ char *pk1_str = NULL, *pk2_str = NULL, *cp;
+ size_t pk1_str_len, pk2_str_len;
routerinfo_t *r1=NULL, *r2=NULL;
- crypto_pk_t *pk1 = NULL, *pk2 = NULL, *pk3 = NULL;
- routerinfo_t *rp1 = NULL;
+ crypto_pk_t *pk1 = NULL, *pk2 = NULL;
+ routerinfo_t *rp1 = NULL, *rp2 = NULL;
addr_policy_t *ex1, *ex2;
routerlist_t *dir1 = NULL, *dir2 = NULL;
+ or_options_t *options = get_options_mutable();
+ const addr_policy_t *p;
pk1 = pk_generate(0);
pk2 = pk_generate(1);
- pk3 = pk_generate(2);
- test_assert(pk1 && pk2 && pk3);
+ test_assert(pk1 && pk2);
hibernate_set_state_for_testing_(HIBERNATE_STATE_LIVE);
@@ -125,31 +131,36 @@ test_dir_formats(void)
r2->or_port = 9005;
r2->dir_port = 0;
r2->onion_pkey = crypto_pk_dup_key(pk2);
+ r2->onion_curve25519_pkey = tor_malloc_zero(sizeof(curve25519_public_key_t));
+ curve25519_public_from_base64(r2->onion_curve25519_pkey,
+ "skyinAnvardNostarsNomoonNowindormistsorsnow");
r2->identity_pkey = crypto_pk_dup_key(pk1);
r2->bandwidthrate = r2->bandwidthburst = r2->bandwidthcapacity = 3000;
r2->exit_policy = smartlist_new();
- smartlist_add(r2->exit_policy, ex2);
smartlist_add(r2->exit_policy, ex1);
+ smartlist_add(r2->exit_policy, ex2);
r2->nickname = tor_strdup("Fred");
test_assert(!crypto_pk_write_public_key_to_string(pk1, &pk1_str,
&pk1_str_len));
test_assert(!crypto_pk_write_public_key_to_string(pk2 , &pk2_str,
&pk2_str_len));
- test_assert(!crypto_pk_write_public_key_to_string(pk3 , &pk3_str,
- &pk3_str_len));
- memset(buf, 0, 2048);
- test_assert(router_dump_router_to_string(buf, 2048, r1, pk2)>0);
+ /* XXXX025 router_dump_to_string should really take this from ri.*/
+ options->ContactInfo = tor_strdup("Magri White "
+ "<magri@elsewhere.example.com>");
+ buf = router_dump_router_to_string(r1, pk2);
+ tor_free(options->ContactInfo);
+ test_assert(buf);
strlcpy(buf2, "router Magri 18.244.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));
strlcat(buf2, "\n"
- "opt protocols Link 1 2 Circuit 1\n"
+ "protocols Link 1 2 Circuit 1\n"
"published 1970-01-01 00:00:00\n"
- "opt fingerprint ", sizeof(buf2));
+ "fingerprint ", sizeof(buf2));
test_assert(!crypto_pk_get_fingerprint(pk2, fingerprint, 1));
strlcat(buf2, fingerprint, sizeof(buf2));
strlcat(buf2, "\nuptime 0\n"
@@ -161,14 +172,18 @@ test_dir_formats(void)
strlcat(buf2, pk1_str, sizeof(buf2));
strlcat(buf2, "signing-key\n", sizeof(buf2));
strlcat(buf2, pk2_str, sizeof(buf2));
- strlcat(buf2, "opt hidden-service-dir\n", sizeof(buf2));
+ strlcat(buf2, "hidden-service-dir\n", sizeof(buf2));
+ strlcat(buf2, "contact Magri White <magri@elsewhere.example.com>\n",
+ sizeof(buf2));
strlcat(buf2, "reject *:*\nrouter-signature\n", sizeof(buf2));
buf[strlen(buf2)] = '\0'; /* Don't compare the sig; it's never the same
* twice */
test_streq(buf, buf2);
+ tor_free(buf);
- test_assert(router_dump_router_to_string(buf, 2048, r1, pk2)>0);
+ buf = router_dump_router_to_string(r1, pk2);
+ test_assert(buf);
cp = buf;
rp1 = router_parse_entry_from_string((const char*)cp,NULL,1,0,NULL);
test_assert(rp1);
@@ -182,35 +197,67 @@ test_dir_formats(void)
test_assert(crypto_pk_cmp_keys(rp1->identity_pkey, pk2) == 0);
//test_assert(rp1->exit_policy == NULL);
-#if 0
- /* XXX Once we have exit policies, test this again. XXX */
- strlcpy(buf2, "router tor.tor.tor 9005 0 0 3000\n", sizeof(buf2));
+ strlcpy(buf2,
+ "router Fred 1.1.1.1 9005 0 0\n"
+ "platform Tor "VERSION" on ", sizeof(buf2));
+ strlcat(buf2, get_uname(), sizeof(buf2));
+ strlcat(buf2, "\n"
+ "protocols Link 1 2 Circuit 1\n"
+ "published 1970-01-01 00:00:05\n"
+ "fingerprint ", sizeof(buf2));
+ test_assert(!crypto_pk_get_fingerprint(pk1, fingerprint, 1));
+ strlcat(buf2, fingerprint, sizeof(buf2));
+ strlcat(buf2, "\nuptime 0\n"
+ "bandwidth 3000 3000 3000\n", sizeof(buf2));
+ strlcat(buf2, "onion-key\n", sizeof(buf2));
strlcat(buf2, pk2_str, sizeof(buf2));
strlcat(buf2, "signing-key\n", sizeof(buf2));
strlcat(buf2, pk1_str, sizeof(buf2));
- strlcat(buf2, "accept *:80\nreject 18.*:24\n\n", sizeof(buf2));
- test_assert(router_dump_router_to_string(buf, 2048, &r2, pk2)>0);
+ strlcat(buf2, "hidden-service-dir\n", sizeof(buf2));
+ strlcat(buf2, "ntor-onion-key "
+ "skyinAnvardNostarsNomoonNowindormistsorsnow=\n", sizeof(buf2));
+ strlcat(buf2, "accept *:80\nreject 18.0.0.0/8:24\n", sizeof(buf2));
+ strlcat(buf2, "router-signature\n", sizeof(buf2));
+
+ buf = router_dump_router_to_string(r2, pk1);
+ buf[strlen(buf2)] = '\0'; /* Don't compare the sig; it's never the same
+ * twice */
test_streq(buf, buf2);
+ tor_free(buf);
+ buf = router_dump_router_to_string(r2, pk1);
cp = buf;
- rp2 = router_parse_entry_from_string(&cp,1);
+ 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->or_port, r2.or_port);
- test_eq(rp2->dir_port, r2.dir_port);
- test_eq(rp2->bandwidth, r2.bandwidth);
+ test_streq(rp2->address, r2->address);
+ 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);
+ test_memeq(rp2->onion_curve25519_pkey->public_key,
+ r2->onion_curve25519_pkey->public_key,
+ CURVE25519_PUBKEY_LEN);
test_assert(crypto_pk_cmp_keys(rp2->onion_pkey, pk2) == 0);
test_assert(crypto_pk_cmp_keys(rp2->identity_pkey, pk1) == 0);
- test_eq(rp2->exit_policy->policy_type, EXIT_POLICY_ACCEPT);
- test_streq(rp2->exit_policy->string, "accept *:80");
- test_streq(rp2->exit_policy->address, "*");
- test_streq(rp2->exit_policy->port, "80");
- test_eq(rp2->exit_policy->next->policy_type, EXIT_POLICY_REJECT);
- test_streq(rp2->exit_policy->next->string, "reject 18.*:24");
- test_streq(rp2->exit_policy->next->address, "18.*");
- test_streq(rp2->exit_policy->next->port, "24");
- test_assert(rp2->exit_policy->next->next == NULL);
+ test_eq(smartlist_len(rp2->exit_policy), 2);
+
+ p = smartlist_get(rp2->exit_policy, 0);
+ test_eq(p->policy_type, ADDR_POLICY_ACCEPT);
+ test_assert(tor_addr_is_null(&p->addr));
+ test_eq(p->maskbits, 0);
+ test_eq(p->prt_min, 80);
+ test_eq(p->prt_max, 80);
+
+ p = smartlist_get(rp2->exit_policy, 1);
+ test_eq(p->policy_type, ADDR_POLICY_REJECT);
+ test_assert(tor_addr_eq(&p->addr, &ex2->addr));
+ test_eq(p->maskbits, 8);
+ test_eq(p->prt_min, 24);
+ test_eq(p->prt_max, 24);
+
+#if 0
/* Okay, now for the directories. */
{
fingerprint_list = smartlist_new();
@@ -220,24 +267,6 @@ test_dir_formats(void)
add_fingerprint_to_dir("Fred", buf, fingerprint_list);
}
- {
- char d[DIGEST_LEN];
- const char *m;
- /* XXXX NM re-enable. */
- /* Make sure routers aren't too far in the past any more. */
- r1->cache_info.published_on = time(NULL);
- r2->cache_info.published_on = time(NULL)-3*60*60;
- test_assert(router_dump_router_to_string(buf, 2048, r1, pk2)>0);
- test_eq(dirserv_add_descriptor(buf,&m,""), ROUTER_ADDED_NOTIFY_GENERATOR);
- test_assert(router_dump_router_to_string(buf, 2048, r2, pk1)>0);
- test_eq(dirserv_add_descriptor(buf,&m,""), ROUTER_ADDED_NOTIFY_GENERATOR);
- get_options()->Nickname = tor_strdup("DirServer");
- test_assert(!dirserv_dump_directory_to_string(&cp,pk3, 0));
- crypto_pk_get_digest(pk3, d);
- test_assert(!router_parse_directory(cp));
- test_eq(2, smartlist_len(dir1->routers));
- tor_free(cp);
- }
#endif
dirserv_free_fingerprint_list();
@@ -247,12 +276,11 @@ test_dir_formats(void)
if (r2)
routerinfo_free(r2);
+ tor_free(buf);
tor_free(pk1_str);
tor_free(pk2_str);
- tor_free(pk3_str);
if (pk1) crypto_pk_free(pk1);
if (pk2) crypto_pk_free(pk2);
- if (pk3) crypto_pk_free(pk3);
if (rp1) routerinfo_free(rp1);
tor_free(dir1); /* XXXX And more !*/
tor_free(dir2); /* And more !*/
@@ -422,10 +450,8 @@ test_dir_split_fps(void *testdata)
"0123456789ABCdef0123456789ABCdef0123456789ABCdef0123456789ABCdef"
#define B64_1 "/g2v+JEnOJvGdVhpEjEjRVEZPu4"
#define B64_2 "3q2+75mZmZERERmZmRERERHwC6Q"
-#define B64_3 "sz/wDbM/8A2zP/ANsz/wDbM/8A0"
#define B64_256_1 "8/Pz8/u7vz8/Pz+7vz8/Pz+7u/Pz8/P7u/Pz8/P7u78"
#define B64_256_2 "zMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMw"
-#define B64_256_3 "ASNFZ4mrze8BI0VniavN7wEjRWeJq83vASNFZ4mrze8"
/* no flags set */
dir_split_resource_into_fingerprints("A+C+B", sl, NULL, 0);
@@ -525,7 +551,7 @@ test_dir_split_fps(void *testdata)
}
static void
-test_dir_measured_bw(void)
+test_dir_measured_bw_kb(void)
{
measured_bw_line_t mbwl;
int i;
@@ -581,7 +607,7 @@ test_dir_measured_bw(void)
for (i = 0; strcmp(lines_pass[i], "end"); i++) {
//fprintf(stderr, "Testing: %s %d\n", lines_pass[i], TOR_ISSPACE('\n'));
test_assert(measured_bw_line_parse(&mbwl, lines_pass[i]) == 0);
- test_assert(mbwl.bw == 1024);
+ test_assert(mbwl.bw_kb == 1024);
test_assert(strcmp(mbwl.node_hex,
"557365204145532d32353620696e73746561642e") == 0);
}
@@ -590,6 +616,83 @@ test_dir_measured_bw(void)
return;
}
+#define MBWC_INIT_TIME 1000
+
+/** Do the measured bandwidth cache unit test */
+static void
+test_dir_measured_bw_kb_cache(void)
+{
+ /* Initial fake time_t for testing */
+ time_t curr = MBWC_INIT_TIME;
+ /* Some measured_bw_line_ts */
+ measured_bw_line_t mbwl[3];
+ /* For receiving output on cache queries */
+ long bw;
+ time_t as_of;
+
+ /* First, clear the cache and assert that it's empty */
+ dirserv_clear_measured_bw_cache();
+ test_eq(dirserv_get_measured_bw_cache_size(), 0);
+ /*
+ * Set up test mbwls; none of the dirserv_cache_*() functions care about
+ * the node_hex field.
+ */
+ memset(mbwl[0].node_id, 0x01, DIGEST_LEN);
+ mbwl[0].bw_kb = 20;
+ memset(mbwl[1].node_id, 0x02, DIGEST_LEN);
+ mbwl[1].bw_kb = 40;
+ memset(mbwl[2].node_id, 0x03, DIGEST_LEN);
+ mbwl[2].bw_kb = 80;
+ /* Try caching something */
+ dirserv_cache_measured_bw(&(mbwl[0]), curr);
+ test_eq(dirserv_get_measured_bw_cache_size(), 1);
+ /* Okay, let's see if we can retrieve it */
+ test_assert(dirserv_query_measured_bw_cache_kb(mbwl[0].node_id,&bw, &as_of));
+ test_eq(bw, 20);
+ test_eq(as_of, MBWC_INIT_TIME);
+ /* Try retrieving it without some outputs */
+ test_assert(dirserv_query_measured_bw_cache_kb(mbwl[0].node_id,NULL, NULL));
+ test_assert(dirserv_query_measured_bw_cache_kb(mbwl[0].node_id,&bw, NULL));
+ test_eq(bw, 20);
+ test_assert(dirserv_query_measured_bw_cache_kb(mbwl[0].node_id,NULL,&as_of));
+ test_eq(as_of, MBWC_INIT_TIME);
+ /* Now expire it */
+ curr += MAX_MEASUREMENT_AGE + 1;
+ dirserv_expire_measured_bw_cache(curr);
+ /* Check that the cache is empty */
+ test_eq(dirserv_get_measured_bw_cache_size(), 0);
+ /* Check that we can't retrieve it */
+ test_assert(!dirserv_query_measured_bw_cache_kb(mbwl[0].node_id, NULL,NULL));
+ /* Try caching a few things now */
+ dirserv_cache_measured_bw(&(mbwl[0]), curr);
+ test_eq(dirserv_get_measured_bw_cache_size(), 1);
+ curr += MAX_MEASUREMENT_AGE / 4;
+ dirserv_cache_measured_bw(&(mbwl[1]), curr);
+ test_eq(dirserv_get_measured_bw_cache_size(), 2);
+ curr += MAX_MEASUREMENT_AGE / 4;
+ dirserv_cache_measured_bw(&(mbwl[2]), curr);
+ test_eq(dirserv_get_measured_bw_cache_size(), 3);
+ curr += MAX_MEASUREMENT_AGE / 4 + 1;
+ /* Do an expire that's too soon to get any of them */
+ dirserv_expire_measured_bw_cache(curr);
+ test_eq(dirserv_get_measured_bw_cache_size(), 3);
+ /* Push the oldest one off the cliff */
+ curr += MAX_MEASUREMENT_AGE / 4;
+ dirserv_expire_measured_bw_cache(curr);
+ test_eq(dirserv_get_measured_bw_cache_size(), 2);
+ /* And another... */
+ curr += MAX_MEASUREMENT_AGE / 4;
+ dirserv_expire_measured_bw_cache(curr);
+ test_eq(dirserv_get_measured_bw_cache_size(), 1);
+ /* This should empty it out again */
+ curr += MAX_MEASUREMENT_AGE / 4;
+ dirserv_expire_measured_bw_cache(curr);
+ test_eq(dirserv_get_measured_bw_cache_size(), 0);
+
+ done:
+ return;
+}
+
static void
test_dir_param_voting(void)
{
@@ -761,6 +864,17 @@ generate_ri_from_rs(const vote_routerstatus_t *vrs)
strlen(r->cache_info.signed_descriptor_body);
r->exit_policy = smartlist_new();
r->cache_info.published_on = ++published + time(NULL);
+ if (rs->has_bandwidth) {
+ /*
+ * Multiply by 1000 because the routerinfo_t and the routerstatus_t
+ * seem to use different units (*sigh*) and because we seem stuck on
+ * icky and perverse decimal kilobytes (*double sigh*) - see
+ * router_get_advertised_bandwidth_capped() of routerlist.c and
+ * routerstatus_format_entry() of dirserv.c.
+ */
+ r->bandwidthrate = rs->bandwidth_kb * 1000;
+ r->bandwidthcapacity = rs->bandwidth_kb * 1000;
+ }
return r;
}
@@ -781,15 +895,328 @@ get_detached_sigs(networkstatus_t *ns, networkstatus_t *ns2)
return r;
}
-/** Run unit tests for generating and parsing V3 consensus networkstatus
- * documents. */
+/**
+ * Generate a routerstatus for v3_networkstatus test
+ */
+static vote_routerstatus_t *
+gen_routerstatus_for_v3ns(int idx, time_t now)
+{
+ vote_routerstatus_t *vrs=NULL;
+ routerstatus_t *rs;
+ tor_addr_t addr_ipv6;
+
+ switch (idx) {
+ case 0:
+ /* Generate the first routerstatus. */
+ vrs = tor_malloc_zero(sizeof(vote_routerstatus_t));
+ rs = &vrs->status;
+ vrs->version = tor_strdup("0.1.2.14");
+ rs->published_on = now-1500;
+ strlcpy(rs->nickname, "router2", sizeof(rs->nickname));
+ memset(rs->identity_digest, 3, DIGEST_LEN);
+ memset(rs->descriptor_digest, 78, DIGEST_LEN);
+ rs->addr = 0x99008801;
+ rs->or_port = 443;
+ rs->dir_port = 8000;
+ /* all flags but running cleared */
+ rs->is_flagged_running = 1;
+ break;
+ case 1:
+ /* Generate the second routerstatus. */
+ vrs = tor_malloc_zero(sizeof(vote_routerstatus_t));
+ rs = &vrs->status;
+ vrs->version = tor_strdup("0.2.0.5");
+ rs->published_on = now-1000;
+ strlcpy(rs->nickname, "router1", sizeof(rs->nickname));
+ memset(rs->identity_digest, 5, DIGEST_LEN);
+ memset(rs->descriptor_digest, 77, DIGEST_LEN);
+ rs->addr = 0x99009901;
+ rs->or_port = 443;
+ rs->dir_port = 0;
+ tor_addr_parse(&addr_ipv6, "[1:2:3::4]");
+ 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;
+ break;
+ case 2:
+ /* Generate the third routerstatus. */
+ vrs = tor_malloc_zero(sizeof(vote_routerstatus_t));
+ rs = &vrs->status;
+ vrs->version = tor_strdup("0.1.0.3");
+ rs->published_on = now-1000;
+ strlcpy(rs->nickname, "router3", sizeof(rs->nickname));
+ memset(rs->identity_digest, 33, DIGEST_LEN);
+ memset(rs->descriptor_digest, 79, DIGEST_LEN);
+ rs->addr = 0xAA009901;
+ 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_possible_guard = 1;
+ break;
+ case 3:
+ /* Generate a fourth routerstatus that is not running. */
+ vrs = tor_malloc_zero(sizeof(vote_routerstatus_t));
+ rs = &vrs->status;
+ vrs->version = tor_strdup("0.1.6.3");
+ rs->published_on = now-1000;
+ strlcpy(rs->nickname, "router4", sizeof(rs->nickname));
+ memset(rs->identity_digest, 34, DIGEST_LEN);
+ memset(rs->descriptor_digest, 47, DIGEST_LEN);
+ rs->addr = 0xC0000203;
+ rs->or_port = 500;
+ rs->dir_port = 1999;
+ /* Running flag (and others) cleared */
+ break;
+ case 4:
+ /* No more for this test; return NULL */
+ vrs = NULL;
+ break;
+ default:
+ /* Shouldn't happen */
+ test_assert(0);
+ }
+ if (vrs) {
+ vrs->microdesc = tor_malloc_zero(sizeof(vote_microdesc_hash_t));
+ tor_asprintf(&vrs->microdesc->microdesc_hash_line,
+ "m 9,10,11,12,13,14,15,16,17 "
+ "sha256=xyzajkldsdsajdadlsdjaslsdksdjlsdjsdaskdaaa%d\n",
+ idx);
+ }
+
+ done:
+ return vrs;
+}
+
+/** Apply tweaks to the vote list for each voter */
+static int
+vote_tweaks_for_v3ns(networkstatus_t *v, int voter, time_t now)
+{
+ vote_routerstatus_t *vrs;
+ const char *msg = NULL;
+
+ test_assert(v);
+ (void)now;
+
+ if (voter == 1) {
+ measured_bw_line_t mbw;
+ memset(mbw.node_id, 33, sizeof(mbw.node_id));
+ mbw.bw_kb = 1024;
+ test_assert(measured_bw_line_apply(&mbw,
+ v->routerstatus_list) == 1);
+ } else if (voter == 2 || voter == 3) {
+ /* 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);
+ 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);
+ vrs = smartlist_get(v->routerstatus_list, 0);
+ memset(vrs->status.descriptor_digest, (int)'Z', DIGEST_LEN);
+ test_assert(router_add_to_routerlist(
+ generate_ri_from_rs(vrs), &msg,0,0) >= 0);
+ }
+ }
+
+ done:
+ return 0;
+}
+
+/**
+ * Test a parsed vote_routerstatus_t for v3_networkstatus test
+ */
static void
-test_dir_v3_networkstatus(void)
+test_vrs_for_v3ns(vote_routerstatus_t *vrs, int voter, time_t now)
+{
+ routerstatus_t *rs;
+ tor_addr_t addr_ipv6;
+
+ test_assert(vrs);
+ rs = &(vrs->status);
+ test_assert(rs);
+
+ /* Split out by digests to test */
+ if (tor_memeq(rs->identity_digest,
+ "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3"
+ "\x3\x3\x3\x3",
+ DIGEST_LEN) &&
+ (voter == 1)) {
+ /* Check the first routerstatus. */
+ test_streq(vrs->version, "0.1.2.14");
+ test_eq(rs->published_on, now-1500);
+ test_streq(rs->nickname, "router2");
+ test_memeq(rs->identity_digest,
+ "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3"
+ "\x3\x3\x3\x3",
+ DIGEST_LEN);
+ test_memeq(rs->descriptor_digest, "NNNNNNNNNNNNNNNNNNNN", DIGEST_LEN);
+ 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"
+ } 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",
+ DIGEST_LEN) &&
+ (voter == 1 || voter == 2)) {
+ test_memeq(rs->identity_digest,
+ "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5"
+ "\x5\x5\x5\x5",
+ DIGEST_LEN);
+
+ if (voter == 1) {
+ /* Check the second routerstatus. */
+ test_streq(vrs->version, "0.2.0.5");
+ test_eq(rs->published_on, now-1000);
+ test_streq(rs->nickname, "router1");
+ }
+ test_memeq(rs->descriptor_digest, "MMMMMMMMMMMMMMMMMMMM", DIGEST_LEN);
+ test_eq(rs->addr, 0x99009901);
+ test_eq(rs->or_port, 443);
+ test_eq(rs->dir_port, 0);
+ tor_addr_parse(&addr_ipv6, "[1:2:3::4]");
+ 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."
+ } else {
+ /* 1023 - authority(1) - madeofcheese(16) - madeoftin(32) */
+ test_eq(vrs->flags, U64_LITERAL(974));
+ }
+ } else if (tor_memeq(rs->identity_digest,
+ "\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33"
+ "\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33",
+ DIGEST_LEN) &&
+ (voter == 1 || voter == 2)) {
+ /* Check the measured bandwidth bits */
+ test_assert(vrs->has_measured_bw &&
+ vrs->measured_bw_kb == 1024);
+ } else {
+ /*
+ * Didn't expect this, but the old unit test only checked some of them,
+ * so don't assert.
+ */
+ /* test_assert(0); */
+ }
+
+ done:
+ return;
+}
+
+/**
+ * Test a consensus for v3_networkstatus_test
+ */
+static void
+test_consensus_for_v3ns(networkstatus_t *con, time_t now)
+{
+ (void)now;
+
+ test_assert(con);
+ test_assert(!con->cert);
+ test_eq(2, smartlist_len(con->routerstatus_list));
+ /* There should be two listed routers: one with identity 3, one with
+ * identity 5. */
+
+ done:
+ return;
+}
+
+/**
+ * Test a router list entry for v3_networkstatus test
+ */
+static void
+test_routerstatus_for_v3ns(routerstatus_t *rs, time_t now)
+{
+ tor_addr_t addr_ipv6;
+
+ test_assert(rs);
+
+ /* There should be two listed routers: one with identity 3, one with
+ * identity 5. */
+ /* This one showed up in 2 digests. */
+ if (tor_memeq(rs->identity_digest,
+ "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3"
+ "\x3\x3",
+ DIGEST_LEN)) {
+ test_memeq(rs->identity_digest,
+ "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3",
+ DIGEST_LEN);
+ test_memeq(rs->descriptor_digest, "NNNNNNNNNNNNNNNNNNNN", DIGEST_LEN);
+ test_assert(!rs->is_authority);
+ test_assert(!rs->is_exit);
+ test_assert(!rs->is_fast);
+ test_assert(!rs->is_possible_guard);
+ 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 */
+ } 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",
+ DIGEST_LEN)) {
+ /* This one showed up in 3 digests. Twice with ID 'M', once with 'Z'. */
+ test_memeq(rs->identity_digest,
+ "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5",
+ DIGEST_LEN);
+ test_streq(rs->nickname, "router1");
+ test_memeq(rs->descriptor_digest, "MMMMMMMMMMMMMMMMMMMM", DIGEST_LEN);
+ test_eq(rs->published_on, now-1000);
+ test_eq(rs->addr, 0x99009901);
+ test_eq(rs->or_port, 443);
+ test_eq(rs->dir_port, 0);
+ tor_addr_parse(&addr_ipv6, "[1:2:3::4]");
+ test_assert(tor_addr_eq(&rs->ipv6_addr, &addr_ipv6));
+ test_eq(rs->ipv6_orport, 4711);
+ test_assert(!rs->is_authority);
+ test_assert(rs->is_exit);
+ test_assert(rs->is_fast);
+ 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 */
+ } else {
+ /* Weren't expecting this... */
+ test_assert(0);
+ }
+
+ done:
+ return;
+}
+
+/** Run a unit tests for generating and parsing networkstatuses, with
+ * the supply test fns. */
+static void
+test_a_networkstatus(
+ vote_routerstatus_t * (*vrs_gen)(int idx, time_t now),
+ int (*vote_tweaks)(networkstatus_t *v, int voter, time_t now),
+ void (*vrs_test)(vote_routerstatus_t *vrs, int voter, time_t now),
+ void (*consensus_test)(networkstatus_t *con, time_t now),
+ void (*rs_test)(routerstatus_t *rs, time_t now))
{
authority_cert_t *cert1=NULL, *cert2=NULL, *cert3=NULL;
crypto_pk_t *sign_skey_1=NULL, *sign_skey_2=NULL, *sign_skey_3=NULL;
crypto_pk_t *sign_skey_leg1=NULL;
const char *msg=NULL;
+ /*
+ * Sum the non-zero returns from vote_tweaks() we've seen; if vote_tweaks()
+ * returns non-zero, it changed net_params and we should skip the tests for
+ * that later as they will fail.
+ */
+ int params_tweaked = 0;
time_t now = time(NULL);
networkstatus_voter_info_t *voter;
@@ -798,6 +1225,7 @@ test_dir_v3_networkstatus(void)
*con_md=NULL;
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;
smartlist_t *votes = smartlist_new();
@@ -809,6 +1237,10 @@ test_dir_v3_networkstatus(void)
networkstatus_t *con2=NULL, *con_md2=NULL, *con3=NULL, *con_md3=NULL;
ns_detached_signatures_t *dsig1=NULL, *dsig2=NULL;
+ test_assert(vrs_gen);
+ test_assert(rs_test);
+ test_assert(vrs_test);
+
/* Parse certificates and keys. */
cert1 = authority_cert_parse_from_string(AUTHORITY_CERT_1, NULL);
test_assert(cert1);
@@ -866,69 +1298,18 @@ test_dir_v3_networkstatus(void)
smartlist_split_string(vote->net_params, "circuitwindow=101 foo=990",
NULL, 0, 0);
vote->routerstatus_list = smartlist_new();
- /* add the first routerstatus. */
- vrs = tor_malloc_zero(sizeof(vote_routerstatus_t));
- rs = &vrs->status;
- vrs->version = tor_strdup("0.1.2.14");
- rs->published_on = now-1500;
- strlcpy(rs->nickname, "router2", sizeof(rs->nickname));
- memset(rs->identity_digest, 3, DIGEST_LEN);
- memset(rs->descriptor_digest, 78, DIGEST_LEN);
- rs->addr = 0x99008801;
- rs->or_port = 443;
- rs->dir_port = 8000;
- /* all flags but running cleared */
- rs->is_flagged_running = 1;
- smartlist_add(vote->routerstatus_list, vrs);
- test_assert(router_add_to_routerlist(generate_ri_from_rs(vrs), &msg,0,0)>=0);
-
- /* add the second routerstatus. */
- vrs = tor_malloc_zero(sizeof(vote_routerstatus_t));
- rs = &vrs->status;
- vrs->version = tor_strdup("0.2.0.5");
- rs->published_on = now-1000;
- strlcpy(rs->nickname, "router1", sizeof(rs->nickname));
- memset(rs->identity_digest, 5, DIGEST_LEN);
- memset(rs->descriptor_digest, 77, DIGEST_LEN);
- rs->addr = 0x99009901;
- rs->or_port = 443;
- rs->dir_port = 0;
- 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;
- smartlist_add(vote->routerstatus_list, vrs);
- test_assert(router_add_to_routerlist(generate_ri_from_rs(vrs), &msg,0,0)>=0);
-
- /* add the third routerstatus. */
- vrs = tor_malloc_zero(sizeof(vote_routerstatus_t));
- rs = &vrs->status;
- vrs->version = tor_strdup("0.1.0.3");
- rs->published_on = now-1000;
- strlcpy(rs->nickname, "router3", sizeof(rs->nickname));
- memset(rs->identity_digest, 33, DIGEST_LEN);
- memset(rs->descriptor_digest, 79, DIGEST_LEN);
- rs->addr = 0xAA009901;
- 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_possible_guard = 1;
- smartlist_add(vote->routerstatus_list, vrs);
- test_assert(router_add_to_routerlist(generate_ri_from_rs(vrs), &msg,0,0)>=0);
-
- /* add a fourth routerstatus that is not running. */
- vrs = tor_malloc_zero(sizeof(vote_routerstatus_t));
- rs = &vrs->status;
- vrs->version = tor_strdup("0.1.6.3");
- rs->published_on = now-1000;
- strlcpy(rs->nickname, "router4", sizeof(rs->nickname));
- memset(rs->identity_digest, 34, DIGEST_LEN);
- memset(rs->descriptor_digest, 47, DIGEST_LEN);
- rs->addr = 0xC0000203;
- rs->or_port = 500;
- rs->dir_port = 1999;
- /* Running flag (and others) cleared */
- smartlist_add(vote->routerstatus_list, vrs);
- test_assert(router_add_to_routerlist(generate_ri_from_rs(vrs), &msg,0,0)>=0);
+ /* add routerstatuses */
+ idx = 0;
+ do {
+ vrs = vrs_gen(idx, now);
+ if (vrs) {
+ smartlist_add(vote->routerstatus_list, vrs);
+ test_assert(router_add_to_routerlist(generate_ri_from_rs(vrs),
+ &msg,0,0)>=0);
+ ++idx;
+ }
+ } while (vrs);
+ n_vrs = idx;
/* dump the vote and try to parse it. */
v1_text = format_networkstatus_vote(sign_skey_1, vote);
@@ -959,45 +1340,15 @@ test_dir_v3_networkstatus(void)
cp = smartlist_join_strings(v1->known_flags, ":", 0, NULL);
test_streq(cp, "Authority:Exit:Fast:Guard:Running:Stable:V2Dir:Valid");
tor_free(cp);
- test_eq(smartlist_len(v1->routerstatus_list), 4);
- /* Check the first routerstatus. */
- vrs = smartlist_get(v1->routerstatus_list, 0);
- rs = &vrs->status;
- test_streq(vrs->version, "0.1.2.14");
- test_eq(rs->published_on, now-1500);
- test_streq(rs->nickname, "router2");
- test_memeq(rs->identity_digest,
- "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3",
- DIGEST_LEN);
- test_memeq(rs->descriptor_digest, "NNNNNNNNNNNNNNNNNNNN", DIGEST_LEN);
- 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"
- /* Check the second routerstatus. */
- vrs = smartlist_get(v1->routerstatus_list, 1);
- rs = &vrs->status;
- test_streq(vrs->version, "0.2.0.5");
- test_eq(rs->published_on, now-1000);
- test_streq(rs->nickname, "router1");
- test_memeq(rs->identity_digest,
- "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5",
- DIGEST_LEN);
- test_memeq(rs->descriptor_digest, "MMMMMMMMMMMMMMMMMMMM", DIGEST_LEN);
- test_eq(rs->addr, 0x99009901);
- test_eq(rs->or_port, 443);
- test_eq(rs->dir_port, 0);
- test_eq(vrs->flags, U64_LITERAL(254)); // all flags except "authority."
+ test_eq(smartlist_len(v1->routerstatus_list), n_vrs);
- {
- measured_bw_line_t mbw;
- memset(mbw.node_id, 33, sizeof(mbw.node_id));
- mbw.bw = 1024;
- test_assert(measured_bw_line_apply(&mbw,
- v1->routerstatus_list) == 1);
- vrs = smartlist_get(v1->routerstatus_list, 2);
- test_assert(vrs->status.has_measured_bw &&
- vrs->status.measured_bw == 1024);
+ if (vote_tweaks) params_tweaked += vote_tweaks(v1, 1, now);
+
+ /* Check the routerstatuses. */
+ for (idx = 0; idx < n_vrs; ++idx) {
+ vrs = smartlist_get(v1->routerstatus_list, idx);
+ test_assert(vrs);
+ vrs_test(vrs, 1, now);
}
/* Generate second vote. It disagrees on some of the times,
@@ -1022,25 +1373,28 @@ test_dir_v3_networkstatus(void)
smartlist_add(vote->known_flags, tor_strdup("MadeOfCheese"));
smartlist_add(vote->known_flags, tor_strdup("MadeOfTin"));
smartlist_sort_strings(vote->known_flags);
- vrs = smartlist_get(vote->routerstatus_list, 2);
- smartlist_del_keeporder(vote->routerstatus_list, 2);
- tor_free(vrs->version);
- tor_free(vrs);
- vrs = smartlist_get(vote->routerstatus_list, 0);
- vrs->status.is_fast = 1;
- /* generate and parse. */
+
+ /* generate and parse v2. */
v2_text = format_networkstatus_vote(sign_skey_2, vote);
test_assert(v2_text);
v2 = networkstatus_parse_vote_from_string(v2_text, NULL, NS_TYPE_VOTE);
test_assert(v2);
+
+ if (vote_tweaks) params_tweaked += vote_tweaks(v2, 2, now);
+
/* Check that flags come out right.*/
cp = smartlist_join_strings(v2->known_flags, ":", 0, NULL);
test_streq(cp, "Authority:Exit:Fast:Guard:MadeOfCheese:MadeOfTin:"
"Running:Stable:V2Dir:Valid");
tor_free(cp);
- vrs = smartlist_get(v2->routerstatus_list, 1);
- /* 1023 - authority(1) - madeofcheese(16) - madeoftin(32) */
- test_eq(vrs->flags, U64_LITERAL(974));
+
+ /* Check the routerstatuses. */
+ n_vrs = smartlist_len(v2->routerstatus_list);
+ for (idx = 0; idx < n_vrs; ++idx) {
+ vrs = smartlist_get(v2->routerstatus_list, idx);
+ test_assert(vrs);
+ vrs_test(vrs, 2, now);
+ }
/* Generate the third vote. */
vote->published = now;
@@ -1063,13 +1417,6 @@ test_dir_v3_networkstatus(void)
crypto_pk_get_digest(cert3->identity_key, voter->identity_digest);
/* This one has a legacy id. */
memset(voter->legacy_id_digest, (int)'A', DIGEST_LEN);
- vrs = smartlist_get(vote->routerstatus_list, 0);
- smartlist_del_keeporder(vote->routerstatus_list, 0);
- tor_free(vrs->version);
- tor_free(vrs);
- vrs = smartlist_get(vote->routerstatus_list, 0);
- memset(vrs->status.descriptor_digest, (int)'Z', DIGEST_LEN);
- test_assert(router_add_to_routerlist(generate_ri_from_rs(vrs), &msg,0,0)>=0);
v3_text = format_networkstatus_vote(sign_skey_3, vote);
test_assert(v3_text);
@@ -1077,6 +1424,8 @@ test_dir_v3_networkstatus(void)
v3 = networkstatus_parse_vote_from_string(v3_text, NULL, NS_TYPE_VOTE);
test_assert(v3);
+ if (vote_tweaks) params_tweaked += vote_tweaks(v3, 3, now);
+
/* Compute a consensus as voter 3. */
smartlist_add(votes, v3);
smartlist_add(votes, v1);
@@ -1119,9 +1468,12 @@ test_dir_v3_networkstatus(void)
test_streq(cp, "Authority:Exit:Fast:Guard:MadeOfCheese:MadeOfTin:"
"Running:Stable:V2Dir:Valid");
tor_free(cp);
- cp = smartlist_join_strings(con->net_params, ":", 0, NULL);
- test_streq(cp, "circuitwindow=80:foo=660");
- tor_free(cp);
+ if (!params_tweaked) {
+ /* Skip this one if vote_tweaks() messed with the param lists */
+ cp = smartlist_join_strings(con->net_params, ":", 0, NULL);
+ test_streq(cp, "circuitwindow=80:foo=660");
+ tor_free(cp);
+ }
test_eq(4, smartlist_len(con->voters)); /*3 voters, 1 legacy key.*/
/* The voter id digests should be in this order. */
@@ -1136,49 +1488,15 @@ test_dir_v3_networkstatus(void)
test_same_voter(smartlist_get(con->voters, 3),
smartlist_get(v3->voters, 0));
- test_assert(!con->cert);
- test_eq(2, smartlist_len(con->routerstatus_list));
- /* There should be two listed routers: one with identity 3, one with
- * identity 5. */
- /* This one showed up in 2 digests. */
- rs = smartlist_get(con->routerstatus_list, 0);
- test_memeq(rs->identity_digest,
- "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3",
- DIGEST_LEN);
- test_memeq(rs->descriptor_digest, "NNNNNNNNNNNNNNNNNNNN", DIGEST_LEN);
- test_assert(!rs->is_authority);
- test_assert(!rs->is_exit);
- test_assert(!rs->is_fast);
- test_assert(!rs->is_possible_guard);
- 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 */
-
- rs = smartlist_get(con->routerstatus_list, 1);
- /* This one showed up in 3 digests. Twice with ID 'M', once with 'Z'. */
- test_memeq(rs->identity_digest,
- "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5",
- DIGEST_LEN);
- test_streq(rs->nickname, "router1");
- test_memeq(rs->descriptor_digest, "MMMMMMMMMMMMMMMMMMMM", DIGEST_LEN);
- test_eq(rs->published_on, now-1000);
- test_eq(rs->addr, 0x99009901);
- test_eq(rs->or_port, 443);
- test_eq(rs->dir_port, 0);
- test_assert(!rs->is_authority);
- test_assert(rs->is_exit);
- test_assert(rs->is_fast);
- 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 */
+ consensus_test(con, now);
+
+ /* Check the routerstatuses. */
+ n_rs = smartlist_len(con->routerstatus_list);
+ for (idx = 0; idx < n_rs; ++idx) {
+ rs = smartlist_get(con->routerstatus_list, idx);
+ test_assert(rs);
+ rs_test(rs, now);
+ }
/* Check signatures. the first voter is a pseudo-entry with a legacy key.
* The second one hasn't signed. The fourth one has signed: validate it. */
@@ -1381,21 +1699,693 @@ test_dir_v3_networkstatus(void)
ns_detached_signatures_free(dsig2);
}
+/** Run unit tests for generating and parsing V3 consensus networkstatus
+ * documents. */
+static void
+test_dir_v3_networkstatus(void)
+{
+ test_a_networkstatus(gen_routerstatus_for_v3ns,
+ vote_tweaks_for_v3ns,
+ test_vrs_for_v3ns,
+ test_consensus_for_v3ns,
+ test_routerstatus_for_v3ns);
+}
+
+static void
+test_dir_scale_bw(void *testdata)
+{
+ double v[8] = { 2.0/3,
+ 7.0,
+ 1.0,
+ 3.0,
+ 1.0/5,
+ 1.0/7,
+ 12.0,
+ 24.0 };
+ u64_dbl_t vals[8];
+ uint64_t total;
+ int i;
+
+ (void) testdata;
+
+ for (i=0; i<8; ++i)
+ vals[i].dbl = v[i];
+
+ scale_array_elements_to_u64(vals, 8, &total);
+
+ tt_int_op((int)total, ==, 48);
+ total = 0;
+ for (i=0; i<8; ++i) {
+ total += vals[i].u64;
+ }
+ tt_assert(total >= (U64_LITERAL(1)<<60));
+ tt_assert(total <= (U64_LITERAL(1)<<62));
+
+ for (i=0; i<8; ++i) {
+ double ratio = ((double)vals[i].u64) / vals[2].u64;
+ tt_double_op(fabs(ratio - v[i]), <, .00001);
+ }
+
+ done:
+ ;
+}
+
+static void
+test_dir_random_weighted(void *testdata)
+{
+ int histogram[10];
+ uint64_t vals[10] = {3,1,2,4,6,0,7,5,8,9}, total=0;
+ u64_dbl_t inp[10];
+ int i, choice;
+ const int n = 50000;
+ double max_sq_error;
+ (void) testdata;
+
+ /* Try a ten-element array with values from 0 through 10. The values are
+ * in a scrambled order to make sure we don't depend on order. */
+ memset(histogram,0,sizeof(histogram));
+ for (i=0; i<10; ++i) {
+ inp[i].u64 = vals[i];
+ total += vals[i];
+ }
+ tt_int_op(total, ==, 45);
+ for (i=0; i<n; ++i) {
+ choice = choose_array_element_by_weight(inp, 10);
+ tt_int_op(choice, >=, 0);
+ tt_int_op(choice, <, 10);
+ histogram[choice]++;
+ }
+
+ /* Now see if we chose things about frequently enough. */
+ max_sq_error = 0;
+ for (i=0; i<10; ++i) {
+ int expected = (int)(n*vals[i]/total);
+ double frac_diff = 0, sq;
+ TT_BLATHER((" %d : %5d vs %5d\n", (int)vals[i], histogram[i], expected));
+ if (expected)
+ frac_diff = (histogram[i] - expected) / ((double)expected);
+ else
+ tt_int_op(histogram[i], ==, 0);
+
+ sq = frac_diff * frac_diff;
+ if (sq > max_sq_error)
+ max_sq_error = sq;
+ }
+ /* It should almost always be much much less than this. If you want to
+ * figure out the odds, please feel free. */
+ tt_double_op(max_sq_error, <, .05);
+
+ /* Now try a singleton; do we choose it? */
+ for (i = 0; i < 100; ++i) {
+ choice = choose_array_element_by_weight(inp, 1);
+ tt_int_op(choice, ==, 0);
+ }
+
+ /* Now try an array of zeros. We should choose randomly. */
+ memset(histogram,0,sizeof(histogram));
+ for (i = 0; i < 5; ++i)
+ inp[i].u64 = 0;
+ for (i = 0; i < n; ++i) {
+ choice = choose_array_element_by_weight(inp, 5);
+ tt_int_op(choice, >=, 0);
+ tt_int_op(choice, <, 5);
+ histogram[choice]++;
+ }
+ /* Now see if we chose things about frequently enough. */
+ max_sq_error = 0;
+ for (i=0; i<5; ++i) {
+ int expected = n/5;
+ double frac_diff = 0, sq;
+ TT_BLATHER((" %d : %5d vs %5d\n", (int)vals[i], histogram[i], expected));
+ frac_diff = (histogram[i] - expected) / ((double)expected);
+ sq = frac_diff * frac_diff;
+ if (sq > max_sq_error)
+ max_sq_error = sq;
+ }
+ /* It should almost always be much much less than this. If you want to
+ * figure out the odds, please feel free. */
+ tt_double_op(max_sq_error, <, .05);
+ done:
+ ;
+}
+
+/* Function pointers for test_dir_clip_unmeasured_bw_kb() */
+
+static uint32_t alternate_clip_bw = 0;
+
+/**
+ * Generate a routerstatus for clip_unmeasured_bw_kb test; based on the
+ * v3_networkstatus ones.
+ */
+static vote_routerstatus_t *
+gen_routerstatus_for_umbw(int idx, time_t now)
+{
+ vote_routerstatus_t *vrs = NULL;
+ routerstatus_t *rs;
+ tor_addr_t addr_ipv6;
+ uint32_t max_unmeasured_bw_kb = (alternate_clip_bw > 0) ?
+ alternate_clip_bw : DEFAULT_MAX_UNMEASURED_BW_KB;
+
+ switch (idx) {
+ case 0:
+ /* Generate the first routerstatus. */
+ vrs = tor_malloc_zero(sizeof(vote_routerstatus_t));
+ rs = &vrs->status;
+ vrs->version = tor_strdup("0.1.2.14");
+ rs->published_on = now-1500;
+ strlcpy(rs->nickname, "router2", sizeof(rs->nickname));
+ memset(rs->identity_digest, 3, DIGEST_LEN);
+ memset(rs->descriptor_digest, 78, DIGEST_LEN);
+ rs->addr = 0x99008801;
+ rs->or_port = 443;
+ rs->dir_port = 8000;
+ /* all flags but running cleared */
+ rs->is_flagged_running = 1;
+ /*
+ * This one has measured bandwidth below the clip cutoff, and
+ * so shouldn't be clipped; we'll have to test that it isn't
+ * later.
+ */
+ vrs->has_measured_bw = 1;
+ rs->has_bandwidth = 1;
+ vrs->measured_bw_kb = rs->bandwidth_kb = max_unmeasured_bw_kb / 2;
+ break;
+ case 1:
+ /* Generate the second routerstatus. */
+ vrs = tor_malloc_zero(sizeof(vote_routerstatus_t));
+ rs = &vrs->status;
+ vrs->version = tor_strdup("0.2.0.5");
+ rs->published_on = now-1000;
+ strlcpy(rs->nickname, "router1", sizeof(rs->nickname));
+ memset(rs->identity_digest, 5, DIGEST_LEN);
+ memset(rs->descriptor_digest, 77, DIGEST_LEN);
+ rs->addr = 0x99009901;
+ rs->or_port = 443;
+ rs->dir_port = 0;
+ tor_addr_parse(&addr_ipv6, "[1:2:3::4]");
+ 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;
+ /*
+ * This one has measured bandwidth above the clip cutoff, and
+ * so shouldn't be clipped; we'll have to test that it isn't
+ * later.
+ */
+ vrs->has_measured_bw = 1;
+ rs->has_bandwidth = 1;
+ vrs->measured_bw_kb = rs->bandwidth_kb = 2 * max_unmeasured_bw_kb;
+ break;
+ case 2:
+ /* Generate the third routerstatus. */
+ vrs = tor_malloc_zero(sizeof(vote_routerstatus_t));
+ rs = &vrs->status;
+ vrs->version = tor_strdup("0.1.0.3");
+ rs->published_on = now-1000;
+ strlcpy(rs->nickname, "router3", sizeof(rs->nickname));
+ memset(rs->identity_digest, 0x33, DIGEST_LEN);
+ memset(rs->descriptor_digest, 79, DIGEST_LEN);
+ rs->addr = 0xAA009901;
+ 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_possible_guard = 1;
+ /*
+ * This one has unmeasured bandwidth above the clip cutoff, and
+ * so should be clipped; we'll have to test that it isn't
+ * later.
+ */
+ vrs->has_measured_bw = 0;
+ rs->has_bandwidth = 1;
+ vrs->measured_bw_kb = 0;
+ rs->bandwidth_kb = 2 * max_unmeasured_bw_kb;
+ break;
+ case 3:
+ /* Generate a fourth routerstatus that is not running. */
+ vrs = tor_malloc_zero(sizeof(vote_routerstatus_t));
+ rs = &vrs->status;
+ vrs->version = tor_strdup("0.1.6.3");
+ rs->published_on = now-1000;
+ strlcpy(rs->nickname, "router4", sizeof(rs->nickname));
+ memset(rs->identity_digest, 0x34, DIGEST_LEN);
+ memset(rs->descriptor_digest, 47, DIGEST_LEN);
+ rs->addr = 0xC0000203;
+ rs->or_port = 500;
+ rs->dir_port = 1999;
+ /* all flags but running cleared */
+ rs->is_flagged_running = 1;
+ /*
+ * This one has unmeasured bandwidth below the clip cutoff, and
+ * so shouldn't be clipped; we'll have to test that it isn't
+ * later.
+ */
+ vrs->has_measured_bw = 0;
+ rs->has_bandwidth = 1;
+ vrs->measured_bw_kb = 0;
+ rs->bandwidth_kb = max_unmeasured_bw_kb / 2;
+ break;
+ case 4:
+ /* No more for this test; return NULL */
+ vrs = NULL;
+ break;
+ default:
+ /* Shouldn't happen */
+ test_assert(0);
+ }
+ if (vrs) {
+ vrs->microdesc = tor_malloc_zero(sizeof(vote_microdesc_hash_t));
+ tor_asprintf(&vrs->microdesc->microdesc_hash_line,
+ "m 9,10,11,12,13,14,15,16,17 "
+ "sha256=xyzajkldsdsajdadlsdjaslsdksdjlsdjsdaskdaaa%d\n",
+ idx);
+ }
+
+ done:
+ return vrs;
+}
+
+/** Apply tweaks to the vote list for each voter; for the umbw test this is
+ * just adding the right consensus methods to let clipping happen */
+static int
+vote_tweaks_for_umbw(networkstatus_t *v, int voter, time_t now)
+{
+ char *maxbw_param = NULL;
+ int rv = 0;
+
+ test_assert(v);
+ (void)voter;
+ (void)now;
+
+ test_assert(v->supported_methods);
+ smartlist_clear(v->supported_methods);
+ /* Method 17 is MIN_METHOD_TO_CLIP_UNMEASURED_BW_KB */
+ smartlist_split_string(v->supported_methods,
+ "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17",
+ NULL, 0, -1);
+ /* If we're using a non-default clip bandwidth, add it to net_params */
+ if (alternate_clip_bw > 0) {
+ tor_asprintf(&maxbw_param, "maxunmeasuredbw=%u", alternate_clip_bw);
+ test_assert(maxbw_param);
+ if (maxbw_param) {
+ smartlist_add(v->net_params, maxbw_param);
+ rv = 1;
+ }
+ }
+
+ done:
+ return rv;
+}
+
+/**
+ * Test a parsed vote_routerstatus_t for umbw test.
+ */
+static void
+test_vrs_for_umbw(vote_routerstatus_t *vrs, int voter, time_t now)
+{
+ routerstatus_t *rs;
+ tor_addr_t addr_ipv6;
+ uint32_t max_unmeasured_bw_kb = (alternate_clip_bw > 0) ?
+ alternate_clip_bw : DEFAULT_MAX_UNMEASURED_BW_KB;
+
+ (void)voter;
+ test_assert(vrs);
+ rs = &(vrs->status);
+ test_assert(rs);
+
+ /* Split out by digests to test */
+ if (tor_memeq(rs->identity_digest,
+ "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3"
+ "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3",
+ DIGEST_LEN)) {
+ /*
+ * Check the first routerstatus - measured bandwidth below the clip
+ * cutoff.
+ */
+ test_streq(vrs->version, "0.1.2.14");
+ test_eq(rs->published_on, now-1500);
+ test_streq(rs->nickname, "router2");
+ test_memeq(rs->identity_digest,
+ "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3"
+ "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3",
+ DIGEST_LEN);
+ test_memeq(rs->descriptor_digest, "NNNNNNNNNNNNNNNNNNNN", DIGEST_LEN);
+ test_eq(rs->addr, 0x99008801);
+ test_eq(rs->or_port, 443);
+ test_eq(rs->dir_port, 8000);
+ test_assert(rs->has_bandwidth);
+ test_assert(vrs->has_measured_bw);
+ test_eq(rs->bandwidth_kb, max_unmeasured_bw_kb / 2);
+ test_eq(vrs->measured_bw_kb, max_unmeasured_bw_kb / 2);
+ } 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",
+ DIGEST_LEN)) {
+
+ /*
+ * Check the second routerstatus - measured bandwidth above the clip
+ * cutoff.
+ */
+ test_streq(vrs->version, "0.2.0.5");
+ test_eq(rs->published_on, now-1000);
+ test_streq(rs->nickname, "router1");
+ test_memeq(rs->identity_digest,
+ "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5"
+ "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5",
+ DIGEST_LEN);
+ test_memeq(rs->descriptor_digest, "MMMMMMMMMMMMMMMMMMMM", DIGEST_LEN);
+ test_eq(rs->addr, 0x99009901);
+ test_eq(rs->or_port, 443);
+ test_eq(rs->dir_port, 0);
+ tor_addr_parse(&addr_ipv6, "[1:2:3::4]");
+ test_assert(tor_addr_eq(&rs->ipv6_addr, &addr_ipv6));
+ test_eq(rs->ipv6_orport, 4711);
+ test_assert(rs->has_bandwidth);
+ test_assert(vrs->has_measured_bw);
+ test_eq(rs->bandwidth_kb, max_unmeasured_bw_kb * 2);
+ test_eq(vrs->measured_bw_kb, max_unmeasured_bw_kb * 2);
+ } else if (tor_memeq(rs->identity_digest,
+ "\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33"
+ "\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33",
+ DIGEST_LEN)) {
+ /*
+ * Check the third routerstatus - unmeasured bandwidth above the clip
+ * cutoff; this one should be clipped later on in the consensus, but
+ * appears unclipped in the vote.
+ */
+ test_assert(rs->has_bandwidth);
+ test_assert(!(vrs->has_measured_bw));
+ test_eq(rs->bandwidth_kb, max_unmeasured_bw_kb * 2);
+ test_eq(vrs->measured_bw_kb, 0);
+ } else if (tor_memeq(rs->identity_digest,
+ "\x34\x34\x34\x34\x34\x34\x34\x34\x34\x34"
+ "\x34\x34\x34\x34\x34\x34\x34\x34\x34\x34",
+ DIGEST_LEN)) {
+ /*
+ * Check the fourth routerstatus - unmeasured bandwidth below the clip
+ * cutoff; this one should not be clipped.
+ */
+ test_assert(rs->has_bandwidth);
+ test_assert(!(vrs->has_measured_bw));
+ test_eq(rs->bandwidth_kb, max_unmeasured_bw_kb / 2);
+ test_eq(vrs->measured_bw_kb, 0);
+ } else {
+ test_assert(0);
+ }
+
+ done:
+ return;
+}
+
+/**
+ * Test a consensus for v3_networkstatus_test
+ */
+static void
+test_consensus_for_umbw(networkstatus_t *con, time_t now)
+{
+ (void)now;
+
+ test_assert(con);
+ test_assert(!con->cert);
+ // test_assert(con->consensus_method >= MIN_METHOD_TO_CLIP_UNMEASURED_BW_KB);
+ test_assert(con->consensus_method >= 16);
+ test_eq(4, smartlist_len(con->routerstatus_list));
+ /* There should be four listed routers; all voters saw the same in this */
+
+ done:
+ return;
+}
+
+/**
+ * Test a router list entry for umbw test
+ */
+static void
+test_routerstatus_for_umbw(routerstatus_t *rs, time_t now)
+{
+ tor_addr_t addr_ipv6;
+ uint32_t max_unmeasured_bw_kb = (alternate_clip_bw > 0) ?
+ alternate_clip_bw : DEFAULT_MAX_UNMEASURED_BW_KB;
+
+ test_assert(rs);
+
+ /* There should be four listed routers, as constructed above */
+ if (tor_memeq(rs->identity_digest,
+ "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3"
+ "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3",
+ DIGEST_LEN)) {
+ test_memeq(rs->identity_digest,
+ "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3"
+ "\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3",
+ DIGEST_LEN);
+ test_memeq(rs->descriptor_digest, "NNNNNNNNNNNNNNNNNNNN", DIGEST_LEN);
+ test_assert(!rs->is_authority);
+ test_assert(!rs->is_exit);
+ test_assert(!rs->is_fast);
+ test_assert(!rs->is_possible_guard);
+ 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 */
+ test_assert(rs->has_bandwidth);
+ test_eq(rs->bandwidth_kb, max_unmeasured_bw_kb / 2);
+ test_assert(!(rs->bw_is_unmeasured));
+ } 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",
+ DIGEST_LEN)) {
+ /* This one showed up in 3 digests. Twice with ID 'M', once with 'Z'. */
+ test_memeq(rs->identity_digest,
+ "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5"
+ "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5",
+ DIGEST_LEN);
+ test_streq(rs->nickname, "router1");
+ test_memeq(rs->descriptor_digest, "MMMMMMMMMMMMMMMMMMMM", DIGEST_LEN);
+ test_eq(rs->published_on, now-1000);
+ test_eq(rs->addr, 0x99009901);
+ test_eq(rs->or_port, 443);
+ test_eq(rs->dir_port, 0);
+ tor_addr_parse(&addr_ipv6, "[1:2:3::4]");
+ test_assert(tor_addr_eq(&rs->ipv6_addr, &addr_ipv6));
+ test_eq(rs->ipv6_orport, 4711);
+ test_assert(!rs->is_authority);
+ test_assert(rs->is_exit);
+ test_assert(rs->is_fast);
+ 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 */
+ test_assert(rs->has_bandwidth);
+ test_eq(rs->bandwidth_kb, max_unmeasured_bw_kb * 2);
+ test_assert(!(rs->bw_is_unmeasured));
+ } else if (tor_memeq(rs->identity_digest,
+ "\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33"
+ "\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33",
+ DIGEST_LEN)) {
+ /*
+ * This one should have unmeasured bandwidth above the clip cutoff,
+ * and so should be clipped
+ */
+ test_assert(rs->has_bandwidth);
+ test_eq(rs->bandwidth_kb, max_unmeasured_bw_kb);
+ test_assert(rs->bw_is_unmeasured);
+ } else if (tor_memeq(rs->identity_digest,
+ "\x34\x34\x34\x34\x34\x34\x34\x34\x34\x34"
+ "\x34\x34\x34\x34\x34\x34\x34\x34\x34\x34",
+ DIGEST_LEN)) {
+ /*
+ * This one should have unmeasured bandwidth below the clip cutoff,
+ * and so should not be clipped
+ */
+ test_assert(rs->has_bandwidth);
+ test_eq(rs->bandwidth_kb, max_unmeasured_bw_kb / 2);
+ test_assert(rs->bw_is_unmeasured);
+ } else {
+ /* Weren't expecting this... */
+ test_assert(0);
+ }
+
+ done:
+ return;
+}
+
+/**
+ * Compute a consensus involving clipping unmeasured bandwidth with consensus
+ * method 17; this uses the same test_a_networkstatus() function that the
+ * v3_networkstatus test uses.
+ */
+
+static void
+test_dir_clip_unmeasured_bw_kb(void)
+{
+ /* Run the test with the default clip bandwidth */
+ alternate_clip_bw = 0;
+ test_a_networkstatus(gen_routerstatus_for_umbw,
+ vote_tweaks_for_umbw,
+ test_vrs_for_umbw,
+ test_consensus_for_umbw,
+ test_routerstatus_for_umbw);
+}
+
+/**
+ * This version of test_dir_clip_unmeasured_bw_kb() uses a non-default choice
+ * of clip bandwidth.
+ */
+
+static void
+test_dir_clip_unmeasured_bw_kb_alt(void)
+{
+ /*
+ * Try a different one; this value is chosen so that the below-the-cutoff
+ * unmeasured nodes the test uses, at alternate_clip_bw / 2, will be above
+ * DEFAULT_MAX_UNMEASURED_BW_KB and if the consensus incorrectly uses that
+ * cutoff it will fail the test.
+ */
+ alternate_clip_bw = 3 * DEFAULT_MAX_UNMEASURED_BW_KB;
+ test_a_networkstatus(gen_routerstatus_for_umbw,
+ vote_tweaks_for_umbw,
+ test_vrs_for_umbw,
+ test_consensus_for_umbw,
+ 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)
+{
+ char *s = NULL;
+ routerstatus_t rs;
+ (void)arg;
+
+ memset(&rs, 0, sizeof(rs));
+ rs.published_on = 1364925198;
+ strlcpy(rs.nickname, "TetsuoMilk", sizeof(rs.nickname));
+ memcpy(rs.identity_digest, "Stately, plump Buck ", DIGEST_LEN);
+ memcpy(rs.descriptor_digest, "Mulligan came up fro", DIGEST_LEN);
+ rs.addr = 0x20304050;
+ rs.or_port = 9001;
+ rs.dir_port = 9002;
+ rs.is_exit = 1;
+ rs.is_fast = 1;
+ rs.is_flagged_running = 1;
+ rs.has_bandwidth = 1;
+ rs.bandwidth_kb = 1000;
+
+ s = networkstatus_getinfo_helper_single(&rs);
+ tt_assert(s);
+ tt_str_op(s, ==,
+ "r TetsuoMilk U3RhdGVseSwgcGx1bXAgQnVjayA "
+ "TXVsbGlnYW4gY2FtZSB1cCBmcm8 2013-04-02 17:53:18 "
+ "32.48.64.80 9001 9002\n"
+ "s Exit Fast Running\n"
+ "w Bandwidth=1000\n");
+
+ done:
+ tor_free(s);
+}
+
#define DIR_LEGACY(name) \
{ #name, legacy_test_helper, TT_FORK, &legacy_setup, test_dir_ ## name }
-#define DIR(name) \
- { #name, test_dir_##name, 0, NULL, NULL }
+#define DIR(name,flags) \
+ { #name, test_dir_##name, (flags), NULL, NULL }
struct testcase_t dir_tests[] = {
DIR_LEGACY(nicknames),
DIR_LEGACY(formats),
DIR_LEGACY(versions),
DIR_LEGACY(fp_pairs),
- DIR(split_fps),
- DIR_LEGACY(measured_bw),
+ DIR(split_fps, 0),
+ DIR_LEGACY(measured_bw_kb),
+ DIR_LEGACY(measured_bw_kb_cache),
DIR_LEGACY(param_voting),
DIR_LEGACY(v3_networkstatus),
+ DIR(random_weighted, 0),
+ 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),
END_OF_TESTCASES
};
diff --git a/src/test/test_introduce.c b/src/test/test_introduce.c
new file mode 100644
index 000000000..69c115222
--- /dev/null
+++ b/src/test/test_introduce.c
@@ -0,0 +1,528 @@
+/* Copyright (c) 2012-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+#include "crypto.h"
+#include "or.h"
+#include "test.h"
+
+#define RENDSERVICE_PRIVATE
+#include "rendservice.h"
+
+extern const char AUTHORITY_SIGNKEY_1[];
+
+static uint8_t v0_test_plaintext[] =
+ /* 20 bytes of rendezvous point nickname */
+ { 0x4e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ /* 20 bytes dummy rendezvous cookie */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13,
+ /* 128 bytes dummy DH handshake data */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
+
+static uint8_t v1_test_plaintext[] =
+ /* Version byte */
+ { 0x01,
+ /* 42 bytes of dummy rendezvous point hex digest */
+ 0x24, 0x30, 0x30, 0x30, 0x31, 0x30, 0x32, 0x30,
+ 0x33, 0x30, 0x34, 0x30, 0x35, 0x30, 0x36, 0x30,
+ 0x37, 0x30, 0x38, 0x30, 0x39, 0x30, 0x41, 0x30,
+ 0x42, 0x30, 0x43, 0x30, 0x44, 0x30, 0x45, 0x30,
+ 0x46, 0x31, 0x30, 0x31, 0x31, 0x31, 0x32, 0x31,
+ 0x33, 0x00,
+ /* 20 bytes dummy rendezvous cookie */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13,
+ /* 128 bytes dummy DH handshake data */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
+
+static uint8_t v2_test_plaintext[] =
+ /* Version byte */
+ { 0x02,
+ /* 4 bytes rendezvous point's IP address */
+ 0xc0, 0xa8, 0x00, 0x01,
+ /* 2 bytes rendezvous point's OR port */
+ 0x23, 0x5a,
+ /* 20 bytes dummy rendezvous point's identity digest */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13,
+ /* 2 bytes length of onion key */
+ 0x00, 0x8c,
+ /* Onion key (140 bytes taken from live test) */
+ 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xb1,
+ 0xcd, 0x46, 0xa9, 0x18, 0xd2, 0x0f, 0x01, 0xf8,
+ 0xb2, 0xad, 0xa4, 0x79, 0xb4, 0xbb, 0x4b, 0xf4,
+ 0x54, 0x1e, 0x3f, 0x03, 0x54, 0xcf, 0x7c, 0xb6,
+ 0xb5, 0xf0, 0xfe, 0xed, 0x4b, 0x7d, 0xd7, 0x61,
+ 0xdb, 0x6d, 0xd9, 0x19, 0xe2, 0x72, 0x04, 0xaa,
+ 0x3e, 0x89, 0x26, 0x14, 0x62, 0x9a, 0x6c, 0x11,
+ 0x0b, 0x35, 0x99, 0x2c, 0x9f, 0x2c, 0x64, 0xa1,
+ 0xd9, 0xe2, 0x88, 0xce, 0xf6, 0x54, 0xfe, 0x1d,
+ 0x37, 0x5e, 0x6d, 0x73, 0x95, 0x54, 0x90, 0xf0,
+ 0x7b, 0xfa, 0xd4, 0x44, 0xac, 0xb2, 0x23, 0x9f,
+ 0x75, 0x36, 0xe2, 0x78, 0x62, 0x82, 0x80, 0xa4,
+ 0x23, 0x22, 0xc9, 0xbf, 0xc4, 0x36, 0xd1, 0x31,
+ 0x33, 0x8e, 0x64, 0xb4, 0xa9, 0x74, 0xa1, 0xcb,
+ 0x42, 0x8d, 0x60, 0xc7, 0xbb, 0x8e, 0x6e, 0x0f,
+ 0x36, 0x74, 0x8e, 0xf4, 0x08, 0x99, 0x06, 0x92,
+ 0xb1, 0x3f, 0xb3, 0xdd, 0xed, 0xf7, 0xc9, 0x02,
+ 0x03, 0x01, 0x00, 0x01,
+ /* 20 bytes dummy rendezvous cookie */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13,
+ /* 128 bytes dummy DH handshake data */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
+
+static uint8_t v3_no_auth_test_plaintext[] =
+ /* Version byte */
+ { 0x03,
+ /* Auth type (0 for no auth len/auth data) */
+ 0x00,
+ /* Timestamp */
+ 0x50, 0x0b, 0xb5, 0xaa,
+ /* 4 bytes rendezvous point's IP address */
+ 0xc0, 0xa8, 0x00, 0x01,
+ /* 2 bytes rendezvous point's OR port */
+ 0x23, 0x5a,
+ /* 20 bytes dummy rendezvous point's identity digest */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13,
+ /* 2 bytes length of onion key */
+ 0x00, 0x8c,
+ /* Onion key (140 bytes taken from live test) */
+ 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xb1,
+ 0xcd, 0x46, 0xa9, 0x18, 0xd2, 0x0f, 0x01, 0xf8,
+ 0xb2, 0xad, 0xa4, 0x79, 0xb4, 0xbb, 0x4b, 0xf4,
+ 0x54, 0x1e, 0x3f, 0x03, 0x54, 0xcf, 0x7c, 0xb6,
+ 0xb5, 0xf0, 0xfe, 0xed, 0x4b, 0x7d, 0xd7, 0x61,
+ 0xdb, 0x6d, 0xd9, 0x19, 0xe2, 0x72, 0x04, 0xaa,
+ 0x3e, 0x89, 0x26, 0x14, 0x62, 0x9a, 0x6c, 0x11,
+ 0x0b, 0x35, 0x99, 0x2c, 0x9f, 0x2c, 0x64, 0xa1,
+ 0xd9, 0xe2, 0x88, 0xce, 0xf6, 0x54, 0xfe, 0x1d,
+ 0x37, 0x5e, 0x6d, 0x73, 0x95, 0x54, 0x90, 0xf0,
+ 0x7b, 0xfa, 0xd4, 0x44, 0xac, 0xb2, 0x23, 0x9f,
+ 0x75, 0x36, 0xe2, 0x78, 0x62, 0x82, 0x80, 0xa4,
+ 0x23, 0x22, 0xc9, 0xbf, 0xc4, 0x36, 0xd1, 0x31,
+ 0x33, 0x8e, 0x64, 0xb4, 0xa9, 0x74, 0xa1, 0xcb,
+ 0x42, 0x8d, 0x60, 0xc7, 0xbb, 0x8e, 0x6e, 0x0f,
+ 0x36, 0x74, 0x8e, 0xf4, 0x08, 0x99, 0x06, 0x92,
+ 0xb1, 0x3f, 0xb3, 0xdd, 0xed, 0xf7, 0xc9, 0x02,
+ 0x03, 0x01, 0x00, 0x01,
+ /* 20 bytes dummy rendezvous cookie */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13,
+ /* 128 bytes dummy DH handshake data */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
+
+static uint8_t v3_basic_auth_test_plaintext[] =
+ /* Version byte */
+ { 0x03,
+ /* Auth type (1 for REND_BASIC_AUTH) */
+ 0x01,
+ /* Auth len (must be 16 bytes for REND_BASIC_AUTH) */
+ 0x00, 0x10,
+ /* Auth data (a 16-byte dummy descriptor cookie) */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ /* Timestamp */
+ 0x50, 0x0b, 0xb5, 0xaa,
+ /* 4 bytes rendezvous point's IP address */
+ 0xc0, 0xa8, 0x00, 0x01,
+ /* 2 bytes rendezvous point's OR port */
+ 0x23, 0x5a,
+ /* 20 bytes dummy rendezvous point's identity digest */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13,
+ /* 2 bytes length of onion key */
+ 0x00, 0x8c,
+ /* Onion key (140 bytes taken from live test) */
+ 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xb1,
+ 0xcd, 0x46, 0xa9, 0x18, 0xd2, 0x0f, 0x01, 0xf8,
+ 0xb2, 0xad, 0xa4, 0x79, 0xb4, 0xbb, 0x4b, 0xf4,
+ 0x54, 0x1e, 0x3f, 0x03, 0x54, 0xcf, 0x7c, 0xb6,
+ 0xb5, 0xf0, 0xfe, 0xed, 0x4b, 0x7d, 0xd7, 0x61,
+ 0xdb, 0x6d, 0xd9, 0x19, 0xe2, 0x72, 0x04, 0xaa,
+ 0x3e, 0x89, 0x26, 0x14, 0x62, 0x9a, 0x6c, 0x11,
+ 0x0b, 0x35, 0x99, 0x2c, 0x9f, 0x2c, 0x64, 0xa1,
+ 0xd9, 0xe2, 0x88, 0xce, 0xf6, 0x54, 0xfe, 0x1d,
+ 0x37, 0x5e, 0x6d, 0x73, 0x95, 0x54, 0x90, 0xf0,
+ 0x7b, 0xfa, 0xd4, 0x44, 0xac, 0xb2, 0x23, 0x9f,
+ 0x75, 0x36, 0xe2, 0x78, 0x62, 0x82, 0x80, 0xa4,
+ 0x23, 0x22, 0xc9, 0xbf, 0xc4, 0x36, 0xd1, 0x31,
+ 0x33, 0x8e, 0x64, 0xb4, 0xa9, 0x74, 0xa1, 0xcb,
+ 0x42, 0x8d, 0x60, 0xc7, 0xbb, 0x8e, 0x6e, 0x0f,
+ 0x36, 0x74, 0x8e, 0xf4, 0x08, 0x99, 0x06, 0x92,
+ 0xb1, 0x3f, 0xb3, 0xdd, 0xed, 0xf7, 0xc9, 0x02,
+ 0x03, 0x01, 0x00, 0x01,
+ /* 20 bytes dummy rendezvous cookie */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13,
+ /* 128 bytes dummy DH handshake data */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
+
+static void do_decrypt_test(uint8_t *plaintext, size_t plaintext_len);
+static void do_early_parse_test(uint8_t *plaintext, size_t plaintext_len);
+static void do_late_parse_test(uint8_t *plaintext, size_t plaintext_len);
+static void do_parse_test(uint8_t *plaintext, size_t plaintext_len, int phase);
+static ssize_t make_intro_from_plaintext(
+ void *buf, size_t len, crypto_pk_t *key, void **cell_out);
+
+#define EARLY_PARSE_ONLY 1
+#define DECRYPT_ONLY 2
+#define ALL_PARSING 3
+
+static void
+do_early_parse_test(uint8_t *plaintext, size_t plaintext_len)
+{
+ do_parse_test(plaintext, plaintext_len, EARLY_PARSE_ONLY);
+}
+
+static void
+do_decrypt_test(uint8_t *plaintext, size_t plaintext_len)
+{
+ do_parse_test(plaintext, plaintext_len, DECRYPT_ONLY);
+}
+
+static void
+do_late_parse_test(uint8_t *plaintext, size_t plaintext_len)
+{
+ do_parse_test(plaintext, plaintext_len, ALL_PARSING);
+}
+
+/** Test utility function: checks that the <b>plaintext_len</b>-byte string at
+ * <b>plaintext</b> is at least superficially parseable.
+ */
+static void
+do_parse_test(uint8_t *plaintext, size_t plaintext_len, int phase)
+{
+ crypto_pk_t *k = NULL;
+ ssize_t r;
+ uint8_t *cell = NULL;
+ size_t cell_len;
+ rend_intro_cell_t *parsed_req = NULL;
+ char *err_msg = NULL;
+ char digest[DIGEST_LEN];
+
+ /* Get a key */
+ k = crypto_pk_new();
+ test_assert(k);
+ r = crypto_pk_read_private_key_from_string(k, AUTHORITY_SIGNKEY_1, -1);
+ test_assert(!r);
+
+ /* Get digest for future comparison */
+ r = crypto_pk_get_digest(k, digest);
+ test_assert(r >= 0);
+
+ /* Make a cell out of it */
+ r = make_intro_from_plaintext(
+ plaintext, plaintext_len,
+ k, (void **)(&cell));
+ test_assert(r > 0);
+ test_assert(cell);
+ cell_len = r;
+
+ /* Do early parsing */
+ parsed_req = rend_service_begin_parse_intro(cell, cell_len, 2, &err_msg);
+ test_assert(parsed_req);
+ test_assert(!err_msg);
+ test_memeq(parsed_req->pk, digest, DIGEST_LEN);
+ test_assert(parsed_req->ciphertext);
+ test_assert(parsed_req->ciphertext_len > 0);
+
+ if (phase == EARLY_PARSE_ONLY)
+ goto done;
+
+ /* Do decryption */
+ r = rend_service_decrypt_intro(parsed_req, k, &err_msg);
+ test_assert(!r);
+ test_assert(!err_msg);
+ test_assert(parsed_req->plaintext);
+ test_assert(parsed_req->plaintext_len > 0);
+
+ if (phase == DECRYPT_ONLY)
+ goto done;
+
+ /* Do late parsing */
+ r = rend_service_parse_intro_plaintext(parsed_req, &err_msg);
+ test_assert(!r);
+ test_assert(!err_msg);
+ test_assert(parsed_req->parsed);
+
+ done:
+ tor_free(cell);
+ crypto_pk_free(k);
+ rend_service_free_intro(parsed_req);
+ tor_free(err_msg);
+}
+
+/** Given the plaintext of the encrypted part of an INTRODUCE1/2 and a key,
+ * construct the encrypted cell for testing.
+ */
+
+static ssize_t
+make_intro_from_plaintext(
+ void *buf, size_t len, crypto_pk_t *key, void **cell_out)
+{
+ char *cell = NULL;
+ ssize_t cell_len = -1, r;
+ /* Assemble key digest and ciphertext, then construct the cell */
+ ssize_t ciphertext_size;
+
+ if (!(buf && key && len > 0 && cell_out)) goto done;
+
+ /*
+ * Figure out an upper bound on how big the ciphertext will be
+ * (see crypto_pk_public_hybrid_encrypt())
+ */
+ ciphertext_size = PKCS1_OAEP_PADDING_OVERHEAD;
+ ciphertext_size += crypto_pk_keysize(key);
+ ciphertext_size += CIPHER_KEY_LEN;
+ ciphertext_size += len;
+
+ /*
+ * Allocate space for the cell
+ */
+ cell = tor_malloc(DIGEST_LEN + ciphertext_size);
+
+ /* Compute key digest (will be first DIGEST_LEN octets of cell) */
+ r = crypto_pk_get_digest(key, cell);
+ test_assert(r >= 0);
+
+ /* Do encryption */
+ r = crypto_pk_public_hybrid_encrypt(
+ key, cell + DIGEST_LEN, ciphertext_size,
+ buf, len,
+ PK_PKCS1_OAEP_PADDING, 0);
+ test_assert(r >= 0);
+
+ /* Figure out cell length */
+ cell_len = DIGEST_LEN + r;
+
+ /* Output the cell */
+ *cell_out = cell;
+
+ done:
+ return cell_len;
+}
+
+/** Test v0 INTRODUCE2 parsing through decryption only
+ */
+
+static void
+test_introduce_decrypt_v0(void)
+{
+ do_decrypt_test(v0_test_plaintext, sizeof(v0_test_plaintext));
+}
+
+/** Test v1 INTRODUCE2 parsing through decryption only
+ */
+
+static void
+test_introduce_decrypt_v1(void)
+{
+ do_decrypt_test(v1_test_plaintext, sizeof(v1_test_plaintext));
+}
+
+/** Test v2 INTRODUCE2 parsing through decryption only
+ */
+
+static void
+test_introduce_decrypt_v2(void)
+{
+ do_decrypt_test(v2_test_plaintext, sizeof(v2_test_plaintext));
+}
+
+/** Test v3 INTRODUCE2 parsing through decryption only
+ */
+
+static void
+test_introduce_decrypt_v3(void)
+{
+ do_decrypt_test(
+ v3_no_auth_test_plaintext, sizeof(v3_no_auth_test_plaintext));
+ do_decrypt_test(
+ v3_basic_auth_test_plaintext, sizeof(v3_basic_auth_test_plaintext));
+}
+
+/** Test v0 INTRODUCE2 parsing through early parsing only
+ */
+
+static void
+test_introduce_early_parse_v0(void)
+{
+ do_early_parse_test(v0_test_plaintext, sizeof(v0_test_plaintext));
+}
+
+/** Test v1 INTRODUCE2 parsing through early parsing only
+ */
+
+static void
+test_introduce_early_parse_v1(void)
+{
+ do_early_parse_test(v1_test_plaintext, sizeof(v1_test_plaintext));
+}
+
+/** Test v2 INTRODUCE2 parsing through early parsing only
+ */
+
+static void
+test_introduce_early_parse_v2(void)
+{
+ do_early_parse_test(v2_test_plaintext, sizeof(v2_test_plaintext));
+}
+
+/** Test v3 INTRODUCE2 parsing through early parsing only
+ */
+
+static void
+test_introduce_early_parse_v3(void)
+{
+ do_early_parse_test(
+ v3_no_auth_test_plaintext, sizeof(v3_no_auth_test_plaintext));
+ do_early_parse_test(
+ v3_basic_auth_test_plaintext, sizeof(v3_basic_auth_test_plaintext));
+}
+
+/** Test v0 INTRODUCE2 parsing
+ */
+
+static void
+test_introduce_late_parse_v0(void)
+{
+ do_late_parse_test(v0_test_plaintext, sizeof(v0_test_plaintext));
+}
+
+/** Test v1 INTRODUCE2 parsing
+ */
+
+static void
+test_introduce_late_parse_v1(void)
+{
+ do_late_parse_test(v1_test_plaintext, sizeof(v1_test_plaintext));
+}
+
+/** Test v2 INTRODUCE2 parsing
+ */
+
+static void
+test_introduce_late_parse_v2(void)
+{
+ do_late_parse_test(v2_test_plaintext, sizeof(v2_test_plaintext));
+}
+
+/** Test v3 INTRODUCE2 parsing
+ */
+
+static void
+test_introduce_late_parse_v3(void)
+{
+ do_late_parse_test(
+ v3_no_auth_test_plaintext, sizeof(v3_no_auth_test_plaintext));
+ do_late_parse_test(
+ v3_basic_auth_test_plaintext, sizeof(v3_basic_auth_test_plaintext));
+}
+
+#define INTRODUCE_LEGACY(name) \
+ { #name, legacy_test_helper, 0, &legacy_setup, test_introduce_ ## name }
+
+struct testcase_t introduce_tests[] = {
+ INTRODUCE_LEGACY(early_parse_v0),
+ INTRODUCE_LEGACY(early_parse_v1),
+ INTRODUCE_LEGACY(early_parse_v2),
+ INTRODUCE_LEGACY(early_parse_v3),
+ INTRODUCE_LEGACY(decrypt_v0),
+ INTRODUCE_LEGACY(decrypt_v1),
+ INTRODUCE_LEGACY(decrypt_v2),
+ INTRODUCE_LEGACY(decrypt_v3),
+ INTRODUCE_LEGACY(late_parse_v0),
+ INTRODUCE_LEGACY(late_parse_v1),
+ INTRODUCE_LEGACY(late_parse_v2),
+ INTRODUCE_LEGACY(late_parse_v3),
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_microdesc.c b/src/test/test_microdesc.c
index 89c578f4a..53a03a48a 100644
--- a/src/test/test_microdesc.c
+++ b/src/test/test_microdesc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Tor Project, Inc. */
+/* Copyright (c) 2010-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -208,11 +208,25 @@ test_md_cache(void *data)
md3 = NULL; /* it's history now! */
/* rebuild again, make sure it stays gone. */
- microdesc_cache_rebuild(mc, 1);
+ tt_int_op(microdesc_cache_rebuild(mc, 1), ==, 0);
tt_ptr_op(md1, ==, microdesc_cache_lookup_by_digest256(mc, d1));
tt_ptr_op(md2, ==, microdesc_cache_lookup_by_digest256(mc, d2));
tt_ptr_op(NULL, ==, microdesc_cache_lookup_by_digest256(mc, d3));
+ /* Re-add md3, and make sure we can rebuild the cache. */
+ added = microdescs_add_to_cache(mc, test_md3_noannotation, NULL,
+ SAVED_NOWHERE, 0, time3, NULL);
+ tt_int_op(1, ==, smartlist_len(added));
+ md3 = smartlist_get(added, 0);
+ smartlist_free(added);
+ added = NULL;
+ tt_int_op(md1->saved_location, ==, SAVED_IN_CACHE);
+ tt_int_op(md2->saved_location, ==, SAVED_IN_CACHE);
+ tt_int_op(md3->saved_location, ==, SAVED_IN_JOURNAL);
+
+ tt_int_op(microdesc_cache_rebuild(mc, 1), ==, 0);
+ tt_int_op(md3->saved_location, ==, SAVED_IN_CACHE);
+
done:
if (options)
tor_free(options->DataDirectory);
@@ -226,8 +240,53 @@ test_md_cache(void *data)
tor_free(fn);
}
+static const char truncated_md[] =
+ "@last-listed 2013-08-08 19:02:59\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAM91vLFNaM+gGhnRIdz2Cm/Kl7Xz0cOobIdVzhS3cKUJfk867hCuTipS\n"
+ "NveLBzNopvgXKruAAzEj3cACxk6Q8lv5UWOGCD1UolkgsWSE62RBjap44g+oc9J1\n"
+ "RI9968xOTZw0VaBQg9giEILNXl0djoikQ+5tQRUvLDDa67gpa5Q1AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "family @\n";
+
+static void
+test_md_cache_broken(void *data)
+{
+ or_options_t *options;
+ char *fn=NULL;
+ microdesc_cache_t *mc = NULL;
+
+ (void)data;
+
+ options = get_options_mutable();
+ tt_assert(options);
+ options->DataDirectory = tor_strdup(get_fname("md_datadir_test2"));
+
+#ifdef _WIN32
+ tt_int_op(0, ==, mkdir(options->DataDirectory));
+#else
+ tt_int_op(0, ==, mkdir(options->DataDirectory, 0700));
+#endif
+
+ tor_asprintf(&fn, "%s"PATH_SEPARATOR"cached-microdescs",
+ options->DataDirectory);
+
+ write_str_to_file(fn, truncated_md, 1);
+
+ mc = get_microdesc_cache();
+ tt_assert(mc);
+
+ done:
+ if (options)
+ tor_free(options->DataDirectory);
+ tor_free(fn);
+ microdesc_free_all();
+}
+
struct testcase_t microdesc_tests[] = {
{ "cache", test_md_cache, TT_FORK, NULL, NULL },
+ { "broken_cache", test_md_cache_broken, TT_FORK, NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_ntor_cl.c b/src/test/test_ntor_cl.c
new file mode 100644
index 000000000..f2b7a72ad
--- /dev/null
+++ b/src/test/test_ntor_cl.c
@@ -0,0 +1,170 @@
+/* Copyright (c) 2012-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+#define ONION_NTOR_PRIVATE
+#include "or.h"
+#include "util.h"
+#include "compat.h"
+#include "crypto.h"
+#include "crypto_curve25519.h"
+#include "onion_ntor.h"
+
+#ifndef CURVE25519_ENABLED
+#error "This isn't going to work without curve25519."
+#endif
+
+#define N_ARGS(n) STMT_BEGIN { \
+ if (argc < (n)) { \
+ fprintf(stderr, "%s needs %d arguments.\n",argv[1],n); \
+ return 1; \
+ } \
+ } STMT_END
+#define BASE16(idx, var, n) STMT_BEGIN { \
+ const char *s = argv[(idx)]; \
+ if (base16_decode((char*)var, n, s, strlen(s)) < 0 ) { \
+ fprintf(stderr, "couldn't decode argument %d (%s)\n",idx,s); \
+ return 1; \
+ } \
+ } STMT_END
+#define INT(idx, var) STMT_BEGIN { \
+ var = atoi(argv[(idx)]); \
+ if (var <= 0) { \
+ fprintf(stderr, "bad integer argument %d (%s)\n",idx,argv[(idx)]); \
+ } \
+ } STMT_END
+
+static int
+client1(int argc, char **argv)
+{
+ /* client1 nodeID B -> msg state */
+ curve25519_public_key_t B;
+ uint8_t node_id[DIGEST_LEN];
+ ntor_handshake_state_t *state = NULL;
+ uint8_t msg[NTOR_ONIONSKIN_LEN];
+
+ char buf[1024];
+
+ N_ARGS(4);
+ BASE16(2, node_id, DIGEST_LEN);
+ BASE16(3, B.public_key, CURVE25519_PUBKEY_LEN);
+
+ if (onion_skin_ntor_create(node_id, &B, &state, msg)<0) {
+ fprintf(stderr, "handshake failed");
+ return 2;
+ }
+
+ base16_encode(buf, sizeof(buf), (const char*)msg, sizeof(msg));
+ printf("%s\n", buf);
+ base16_encode(buf, sizeof(buf), (void*)state, sizeof(*state));
+ printf("%s\n", buf);
+
+ ntor_handshake_state_free(state);
+ return 0;
+}
+
+static int
+server1(int argc, char **argv)
+{
+ uint8_t msg_in[NTOR_ONIONSKIN_LEN];
+ curve25519_keypair_t kp;
+ di_digest256_map_t *keymap=NULL;
+ uint8_t node_id[DIGEST_LEN];
+ int keybytes;
+
+ uint8_t msg_out[NTOR_REPLY_LEN];
+ uint8_t *keys = NULL;
+ char *hexkeys = NULL;
+ int result = 0;
+
+ char buf[256];
+
+ /* server1: b nodeID msg N -> msg keys */
+ N_ARGS(6);
+ BASE16(2, kp.seckey.secret_key, CURVE25519_SECKEY_LEN);
+ BASE16(3, node_id, DIGEST_LEN);
+ BASE16(4, msg_in, NTOR_ONIONSKIN_LEN);
+ INT(5, keybytes);
+
+ curve25519_public_key_generate(&kp.pubkey, &kp.seckey);
+ dimap_add_entry(&keymap, kp.pubkey.public_key, &kp);
+
+ keys = tor_malloc(keybytes);
+ hexkeys = tor_malloc(keybytes*2+1);
+ if (onion_skin_ntor_server_handshake(
+ msg_in, keymap, NULL, node_id, msg_out, keys,
+ (size_t)keybytes)<0) {
+ fprintf(stderr, "handshake failed");
+ result = 2;
+ goto done;
+ }
+
+ base16_encode(buf, sizeof(buf), (const char*)msg_out, sizeof(msg_out));
+ printf("%s\n", buf);
+ base16_encode(hexkeys, keybytes*2+1, (const char*)keys, keybytes);
+ printf("%s\n", hexkeys);
+
+ done:
+ tor_free(keys);
+ tor_free(hexkeys);
+ return result;
+}
+
+static int
+client2(int argc, char **argv)
+{
+ struct ntor_handshake_state_t state;
+ uint8_t msg[NTOR_REPLY_LEN];
+ int keybytes;
+ uint8_t *keys;
+ char *hexkeys;
+ int result = 0;
+
+ N_ARGS(5);
+ BASE16(2, (&state), sizeof(state));
+ BASE16(3, msg, sizeof(msg));
+ INT(4, keybytes);
+
+ keys = tor_malloc(keybytes);
+ hexkeys = tor_malloc(keybytes*2+1);
+ if (onion_skin_ntor_client_handshake(&state, msg, keys, keybytes)<0) {
+ fprintf(stderr, "handshake failed");
+ result = 2;
+ goto done;
+ }
+
+ base16_encode(hexkeys, keybytes*2+1, (const char*)keys, keybytes);
+ printf("%s\n", hexkeys);
+
+ done:
+ tor_free(keys);
+ tor_free(hexkeys);
+ return result;
+}
+
+int
+main(int argc, char **argv)
+{
+ /*
+ client1: nodeID B -> msg state
+ server1: b nodeID msg N -> msg keys
+ client2: state msg N -> keys
+ */
+ if (argc < 2) {
+ fprintf(stderr, "I need arguments. Read source for more info.\n");
+ return 1;
+ } else if (!strcmp(argv[1], "client1")) {
+ return client1(argc, argv);
+ } else if (!strcmp(argv[1], "server1")) {
+ return server1(argc, argv);
+ } else if (!strcmp(argv[1], "client2")) {
+ return client2(argc, argv);
+ } else {
+ fprintf(stderr, "What's a %s?\n", argv[1]);
+ return 1;
+ }
+}
+
diff --git a/src/test/test_pt.c b/src/test/test_pt.c
index d3dadb9bf..80707f437 100644
--- a/src/test/test_pt.c
+++ b/src/test/test_pt.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_replay.c b/src/test/test_replay.c
new file mode 100644
index 000000000..de841ad59
--- /dev/null
+++ b/src/test/test_replay.c
@@ -0,0 +1,178 @@
+/* Copyright (c) 2012-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#define REPLAYCACHE_PRIVATE
+
+#include "orconfig.h"
+#include "or.h"
+#include "replaycache.h"
+#include "test.h"
+
+static const char *test_buffer =
+ "Lorem ipsum dolor sit amet, consectetur adipisici elit, sed do eiusmod"
+ " tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim"
+ " veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea"
+ " commodo consequat. Duis aute irure dolor in reprehenderit in voluptate"
+ " velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint"
+ " occaecat cupidatat non proident, sunt in culpa qui officia deserunt"
+ " mollit anim id est laborum.";
+
+static void
+test_replaycache_alloc(void)
+{
+ replaycache_t *r = NULL;
+
+ r = replaycache_new(600, 300);
+ test_assert(r != NULL);
+
+ done:
+ if (r) replaycache_free(r);
+
+ return;
+}
+
+static void
+test_replaycache_miss(void)
+{
+ replaycache_t *r = NULL;
+ int result;
+
+ r = replaycache_new(600, 300);
+ test_assert(r != NULL);
+
+ result =
+ replaycache_add_and_test_internal(1200, r, test_buffer,
+ (int)strlen(test_buffer), NULL);
+ test_eq(result, 0);
+
+ done:
+ if (r) replaycache_free(r);
+
+ return;
+}
+
+static void
+test_replaycache_hit(void)
+{
+ replaycache_t *r = NULL;
+ int result;
+
+ r = replaycache_new(600, 300);
+ test_assert(r != NULL);
+
+ result =
+ replaycache_add_and_test_internal(1200, r, test_buffer,
+ (int)strlen(test_buffer), NULL);
+ test_eq(result, 0);
+
+ result =
+ replaycache_add_and_test_internal(1300, r, test_buffer,
+ (int)strlen(test_buffer), NULL);
+ test_eq(result, 1);
+
+ done:
+ if (r) replaycache_free(r);
+
+ return;
+}
+
+static void
+test_replaycache_age(void)
+{
+ replaycache_t *r = NULL;
+ int result;
+
+ r = replaycache_new(600, 300);
+ test_assert(r != NULL);
+
+ result =
+ replaycache_add_and_test_internal(1200, r, test_buffer,
+ (int)strlen(test_buffer), NULL);
+ test_eq(result, 0);
+
+ result =
+ replaycache_add_and_test_internal(1300, r, test_buffer,
+ (int)strlen(test_buffer), NULL);
+ test_eq(result, 1);
+
+ result =
+ replaycache_add_and_test_internal(3000, r, test_buffer,
+ (int)strlen(test_buffer), NULL);
+ test_eq(result, 0);
+
+ done:
+ if (r) replaycache_free(r);
+
+ return;
+}
+
+static void
+test_replaycache_elapsed(void)
+{
+ replaycache_t *r = NULL;
+ int result;
+ time_t elapsed;
+
+ r = replaycache_new(600, 300);
+ test_assert(r != NULL);
+
+ result =
+ replaycache_add_and_test_internal(1200, r, test_buffer,
+ (int)strlen(test_buffer), NULL);
+ test_eq(result, 0);
+
+ result =
+ replaycache_add_and_test_internal(1300, r, test_buffer,
+ (int)strlen(test_buffer), &elapsed);
+ test_eq(result, 1);
+ test_eq(elapsed, 100);
+
+ done:
+ if (r) replaycache_free(r);
+
+ return;
+}
+
+static void
+test_replaycache_noexpire(void)
+{
+ replaycache_t *r = NULL;
+ int result;
+
+ r = replaycache_new(0, 0);
+ test_assert(r != NULL);
+
+ result =
+ replaycache_add_and_test_internal(1200, r, test_buffer,
+ (int)strlen(test_buffer), NULL);
+ test_eq(result, 0);
+
+ result =
+ replaycache_add_and_test_internal(1300, r, test_buffer,
+ (int)strlen(test_buffer), NULL);
+ test_eq(result, 1);
+
+ result =
+ replaycache_add_and_test_internal(3000, r, test_buffer,
+ (int)strlen(test_buffer), NULL);
+ test_eq(result, 1);
+
+ 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(miss),
+ REPLAYCACHE_LEGACY(hit),
+ REPLAYCACHE_LEGACY(age),
+ REPLAYCACHE_LEGACY(elapsed),
+ REPLAYCACHE_LEGACY(noexpire),
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_util.c b/src/test/test_util.c
index 6c72247e9..65d9d2f87 100644
--- a/src/test/test_util.c
+++ b/src/test/test_util.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2012, The Tor Project, Inc. */
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -17,6 +17,7 @@
#ifdef _WIN32
#include <tchar.h>
#endif
+#include <math.h>
/* XXXX this is a minimal wrapper to make the unit tests compile with the
* changed tor_timegm interface. */
@@ -32,6 +33,75 @@ tor_timegm_wrapper(const struct tm *tm)
#define tor_timegm tor_timegm_wrapper
static void
+test_util_read_until_eof_impl(const char *fname, size_t file_len,
+ size_t read_limit)
+{
+ char *fifo_name = NULL;
+ char *test_str = NULL;
+ char *str = NULL;
+ size_t sz = 9999999;
+ int fd = -1;
+ int r;
+
+ fifo_name = tor_strdup(get_fname(fname));
+ test_str = tor_malloc(file_len);
+ crypto_rand(test_str, file_len);
+
+ r = write_bytes_to_file(fifo_name, test_str, file_len, 1);
+ tt_int_op(r, ==, 0);
+
+ fd = open(fifo_name, O_RDONLY|O_BINARY);
+ tt_int_op(fd, >=, 0);
+ str = read_file_to_str_until_eof(fd, read_limit, &sz);
+ tt_assert(str != NULL);
+
+ if (read_limit < file_len)
+ tt_int_op(sz, ==, read_limit);
+ else
+ tt_int_op(sz, ==, file_len);
+
+ test_mem_op(test_str, ==, str, sz);
+ test_assert(str[sz] == '\0');
+
+ done:
+ unlink(fifo_name);
+ tor_free(fifo_name);
+ tor_free(test_str);
+ tor_free(str);
+ if (fd >= 0)
+ close(fd);
+}
+
+static void
+test_util_read_file_eof_tiny_limit(void *arg)
+{
+ (void)arg;
+ // purposely set limit shorter than what we wrote to the FIFO to
+ // test the maximum, and that it puts the NUL in the right spot
+
+ test_util_read_until_eof_impl("tor_test_fifo_tiny", 5, 4);
+}
+
+static void
+test_util_read_file_eof_two_loops(void *arg)
+{
+ (void)arg;
+ // write more than 1024 bytes to the FIFO to test two passes through
+ // the loop in the method; if the re-alloc size is changed this
+ // should be updated as well.
+
+ test_util_read_until_eof_impl("tor_test_fifo_2k", 2048, 10000);
+}
+
+static void
+test_util_read_file_eof_zero_bytes(void *arg)
+{
+ (void)arg;
+ // zero-byte fifo
+ test_util_read_until_eof_impl("tor_test_fifo_empty", 0, 10000);
+}
+
+static void
test_util_time(void)
{
struct timeval start, end;
@@ -152,6 +222,7 @@ test_util_time(void)
test_eq(-1, parse_iso_time("2011-03-30 23:59:62 GMT", &t_res));
test_eq(-1, parse_iso_time("1969-03-30 23:59:59 GMT", &t_res));
test_eq(-1, parse_iso_time("2011-00-30 23:59:59 GMT", &t_res));
+ test_eq(-1, parse_iso_time("2147483647-08-29 14:00:00", &t_res));
test_eq(-1, parse_iso_time("2011-03-30 23:59", &t_res));
/* Test tor_gettimeofday */
@@ -731,7 +802,7 @@ test_util_strmisc(void)
{
char buf[1024];
int i;
- char *cp;
+ char *cp, *cp_tmp = NULL;
/* Test strl operations */
test_eq(5, strlcpy(buf, "Hello", 0));
@@ -934,20 +1005,20 @@ test_util_strmisc(void)
/* Test strndup and memdup */
{
const char *s = "abcdefghijklmnopqrstuvwxyz";
- cp = tor_strndup(s, 30);
- test_streq(cp, s); /* same string, */
- test_neq(cp, s); /* but different pointers. */
- tor_free(cp);
+ cp_tmp = tor_strndup(s, 30);
+ test_streq(cp_tmp, s); /* same string, */
+ test_neq_ptr(cp_tmp, s); /* but different pointers. */
+ tor_free(cp_tmp);
- cp = tor_strndup(s, 5);
- test_streq(cp, "abcde");
- tor_free(cp);
+ cp_tmp = tor_strndup(s, 5);
+ test_streq(cp_tmp, "abcde");
+ tor_free(cp_tmp);
s = "a\0b\0c\0d\0e\0";
- cp = tor_memdup(s,10);
- test_memeq(cp, s, 10); /* same ram, */
- test_neq(cp, s); /* but different pointers. */
- tor_free(cp);
+ cp_tmp = tor_memdup(s,10);
+ test_memeq(cp_tmp, s, 10); /* same ram, */
+ test_neq_ptr(cp_tmp, s); /* but different pointers. */
+ tor_free(cp_tmp);
}
/* Test str-foo functions */
@@ -983,79 +1054,6 @@ test_util_strmisc(void)
test_assert(!tor_memstr(haystack, 7, "ababcade"));
}
- /* Test wrap_string */
- {
- smartlist_t *sl = smartlist_new();
- wrap_string(sl,
- "This is a test of string wrapping functionality: woot. "
- "a functionality? w00t w00t...!",
- 10, "", "");
- cp = smartlist_join_strings(sl, "", 0, NULL);
- test_streq(cp,
- "This is a\ntest of\nstring\nwrapping\nfunctional\nity: woot.\n"
- "a\nfunctional\nity? w00t\nw00t...!\n");
- tor_free(cp);
- SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
- smartlist_clear(sl);
-
- wrap_string(sl, "This is a test of string wrapping functionality: woot.",
- 16, "### ", "# ");
- cp = smartlist_join_strings(sl, "", 0, NULL);
- test_streq(cp,
- "### This is a\n# test of string\n# wrapping\n# functionality:\n"
- "# woot.\n");
- tor_free(cp);
- SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
- smartlist_clear(sl);
-
- wrap_string(sl, "A test of string wrapping...", 6, "### ", "# ");
- cp = smartlist_join_strings(sl, "", 0, NULL);
- test_streq(cp,
- "### A\n# test\n# of\n# stri\n# ng\n# wrap\n# ping\n# ...\n");
- tor_free(cp);
- SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
- smartlist_clear(sl);
-
- wrap_string(sl, "Wrapping test", 6, "#### ", "# ");
- cp = smartlist_join_strings(sl, "", 0, NULL);
- test_streq(cp, "#### W\n# rapp\n# ing\n# test\n");
- tor_free(cp);
- SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
- smartlist_clear(sl);
-
- wrap_string(sl, "Small test", 6, "### ", "#### ");
- cp = smartlist_join_strings(sl, "", 0, NULL);
- test_streq(cp, "### Sm\n#### a\n#### l\n#### l\n#### t\n#### e"
- "\n#### s\n#### t\n");
- tor_free(cp);
- SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
- smartlist_clear(sl);
-
- wrap_string(sl, "First null", 6, NULL, "> ");
- cp = smartlist_join_strings(sl, "", 0, NULL);
- test_streq(cp, "First\n> null\n");
- tor_free(cp);
- SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
- smartlist_clear(sl);
-
- wrap_string(sl, "Second null", 6, "> ", NULL);
- cp = smartlist_join_strings(sl, "", 0, NULL);
- test_streq(cp, "> Seco\nnd\nnull\n");
- tor_free(cp);
- SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
- smartlist_clear(sl);
-
- wrap_string(sl, "Both null", 6, NULL, NULL);
- cp = smartlist_join_strings(sl, "", 0, NULL);
- test_streq(cp, "Both\nnull\n");
- tor_free(cp);
- SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
- smartlist_free(sl);
-
- /* Can't test prefixes that have the same length as the line width, because
- the function has an assert */
- }
-
/* Test hex_str */
{
char binary_data[68];
@@ -1099,7 +1097,7 @@ test_util_strmisc(void)
tt_int_op(strcmp_len("blah", "", 0), ==, 0);
done:
- ;
+ tor_free(cp_tmp);
}
static void
@@ -1109,6 +1107,7 @@ test_util_pow2(void)
test_eq(tor_log2(64), 6);
test_eq(tor_log2(65), 6);
test_eq(tor_log2(63), 5);
+ test_eq(tor_log2(0), 0); /* incorrect mathematically, but as specified */
test_eq(tor_log2(1), 0);
test_eq(tor_log2(2), 1);
test_eq(tor_log2(3), 1);
@@ -1123,26 +1122,35 @@ test_util_pow2(void)
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(0), 2);
+ test_eq(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);
done:
;
}
/** mutex for thread test to stop the threads hitting data at the same time. */
-static tor_mutex_t *_thread_test_mutex = NULL;
+static tor_mutex_t *thread_test_mutex_ = NULL;
/** mutexes for the thread test to make sure that the threads have to
* interleave somewhat. */
-static tor_mutex_t *_thread_test_start1 = NULL,
- *_thread_test_start2 = NULL;
+static tor_mutex_t *thread_test_start1_ = NULL,
+ *thread_test_start2_ = NULL;
/** Shared strmap for the thread test. */
-static strmap_t *_thread_test_strmap = NULL;
+static strmap_t *thread_test_strmap_ = NULL;
/** The name of thread1 for the thread test */
-static char *_thread1_name = NULL;
+static char *thread1_name_ = NULL;
/** The name of thread2 for the thread test */
-static char *_thread2_name = NULL;
+static char *thread2_name_ = NULL;
-static void _thread_test_func(void* _s) ATTR_NORETURN;
+static void thread_test_func_(void* _s) ATTR_NORETURN;
/** How many iterations have the threads in the unit test run? */
static int t1_count = 0, t2_count = 0;
@@ -1150,9 +1158,9 @@ static int t1_count = 0, t2_count = 0;
/** Helper function for threading unit tests: This function runs in a
* subthread. It grabs its own mutex (start1 or start2) to make sure that it
* should start, then it repeatedly alters _test_thread_strmap protected by
- * _thread_test_mutex. */
+ * thread_test_mutex_. */
static void
-_thread_test_func(void* _s)
+thread_test_func_(void* _s)
{
char *s = _s;
int i, *count;
@@ -1160,12 +1168,12 @@ _thread_test_func(void* _s)
char buf[64];
char **cp;
if (!strcmp(s, "thread 1")) {
- m = _thread_test_start1;
- cp = &_thread1_name;
+ m = thread_test_start1_;
+ cp = &thread1_name_;
count = &t1_count;
} else {
- m = _thread_test_start2;
- cp = &_thread2_name;
+ m = thread_test_start2_;
+ cp = &thread2_name_;
count = &t2_count;
}
@@ -1175,14 +1183,14 @@ _thread_test_func(void* _s)
tor_mutex_acquire(m);
for (i=0; i<10000; ++i) {
- tor_mutex_acquire(_thread_test_mutex);
- strmap_set(_thread_test_strmap, "last to run", *cp);
+ tor_mutex_acquire(thread_test_mutex_);
+ strmap_set(thread_test_strmap_, "last to run", *cp);
++*count;
- tor_mutex_release(_thread_test_mutex);
+ tor_mutex_release(thread_test_mutex_);
}
- tor_mutex_acquire(_thread_test_mutex);
- strmap_set(_thread_test_strmap, s, *cp);
- tor_mutex_release(_thread_test_mutex);
+ tor_mutex_acquire(thread_test_mutex_);
+ strmap_set(thread_test_strmap_, s, *cp);
+ tor_mutex_release(thread_test_mutex_);
tor_mutex_release(m);
@@ -1207,67 +1215,67 @@ test_util_threads(void)
if (1)
return;
#endif
- _thread_test_mutex = tor_mutex_new();
- _thread_test_start1 = tor_mutex_new();
- _thread_test_start2 = tor_mutex_new();
- _thread_test_strmap = strmap_new();
+ thread_test_mutex_ = tor_mutex_new();
+ thread_test_start1_ = tor_mutex_new();
+ thread_test_start2_ = tor_mutex_new();
+ thread_test_strmap_ = strmap_new();
s1 = tor_strdup("thread 1");
s2 = tor_strdup("thread 2");
- tor_mutex_acquire(_thread_test_start1);
- tor_mutex_acquire(_thread_test_start2);
- spawn_func(_thread_test_func, s1);
- spawn_func(_thread_test_func, s2);
- tor_mutex_release(_thread_test_start2);
- tor_mutex_release(_thread_test_start1);
+ tor_mutex_acquire(thread_test_start1_);
+ tor_mutex_acquire(thread_test_start2_);
+ spawn_func(thread_test_func_, s1);
+ spawn_func(thread_test_func_, s2);
+ tor_mutex_release(thread_test_start2_);
+ tor_mutex_release(thread_test_start1_);
started = time(NULL);
while (!done) {
- tor_mutex_acquire(_thread_test_mutex);
- strmap_assert_ok(_thread_test_strmap);
- if (strmap_get(_thread_test_strmap, "thread 1") &&
- strmap_get(_thread_test_strmap, "thread 2")) {
+ tor_mutex_acquire(thread_test_mutex_);
+ strmap_assert_ok(thread_test_strmap_);
+ if (strmap_get(thread_test_strmap_, "thread 1") &&
+ strmap_get(thread_test_strmap_, "thread 2")) {
done = 1;
} else if (time(NULL) > started + 150) {
timedout = done = 1;
}
- tor_mutex_release(_thread_test_mutex);
+ tor_mutex_release(thread_test_mutex_);
#ifndef _WIN32
/* Prevent the main thread from starving the worker threads. */
select(0, NULL, NULL, NULL, &tv);
#endif
}
- tor_mutex_acquire(_thread_test_start1);
- tor_mutex_release(_thread_test_start1);
- tor_mutex_acquire(_thread_test_start2);
- tor_mutex_release(_thread_test_start2);
+ tor_mutex_acquire(thread_test_start1_);
+ tor_mutex_release(thread_test_start1_);
+ tor_mutex_acquire(thread_test_start2_);
+ tor_mutex_release(thread_test_start2_);
- tor_mutex_free(_thread_test_mutex);
+ tor_mutex_free(thread_test_mutex_);
if (timedout) {
printf("\nTimed out: %d %d", t1_count, t2_count);
- test_assert(strmap_get(_thread_test_strmap, "thread 1"));
- test_assert(strmap_get(_thread_test_strmap, "thread 2"));
+ test_assert(strmap_get(thread_test_strmap_, "thread 1"));
+ test_assert(strmap_get(thread_test_strmap_, "thread 2"));
test_assert(!timedout);
}
/* different thread IDs. */
- test_assert(strcmp(strmap_get(_thread_test_strmap, "thread 1"),
- strmap_get(_thread_test_strmap, "thread 2")));
- test_assert(!strcmp(strmap_get(_thread_test_strmap, "thread 1"),
- strmap_get(_thread_test_strmap, "last to run")) ||
- !strcmp(strmap_get(_thread_test_strmap, "thread 2"),
- strmap_get(_thread_test_strmap, "last to run")));
+ test_assert(strcmp(strmap_get(thread_test_strmap_, "thread 1"),
+ strmap_get(thread_test_strmap_, "thread 2")));
+ test_assert(!strcmp(strmap_get(thread_test_strmap_, "thread 1"),
+ strmap_get(thread_test_strmap_, "last to run")) ||
+ !strcmp(strmap_get(thread_test_strmap_, "thread 2"),
+ strmap_get(thread_test_strmap_, "last to run")));
done:
tor_free(s1);
tor_free(s2);
- tor_free(_thread1_name);
- tor_free(_thread2_name);
- if (_thread_test_strmap)
- strmap_free(_thread_test_strmap, NULL);
- if (_thread_test_start1)
- tor_mutex_free(_thread_test_start1);
- if (_thread_test_start2)
- tor_mutex_free(_thread_test_start2);
+ tor_free(thread1_name_);
+ tor_free(thread2_name_);
+ if (thread_test_strmap_)
+ strmap_free(thread_test_strmap_, NULL);
+ if (thread_test_start1_)
+ tor_mutex_free(thread_test_start1_);
+ if (thread_test_start2_)
+ tor_mutex_free(thread_test_start2_);
}
/** Run unit tests for compression functions */
@@ -1416,7 +1424,7 @@ test_util_mmap(void)
/* Now a zero-length file. */
write_str_to_file(fname1, "", 1);
mapping = tor_mmap_file(fname1);
- test_eq(mapping, NULL);
+ test_eq_ptr(mapping, NULL);
test_eq(ERANGE, errno);
unlink(fname1);
@@ -1474,12 +1482,28 @@ test_util_control_formats(void)
tor_free(out);
}
+#define test_feq(value1,value2) do { \
+ double v1 = (value1), v2=(value2); \
+ double tf_diff = v1-v2; \
+ double tf_tolerance = ((v1+v2)/2.0)/1e8; \
+ if (tf_diff<0) tf_diff=-tf_diff; \
+ if (tf_tolerance<0) tf_tolerance=-tf_tolerance; \
+ if (tf_diff<tf_tolerance) { \
+ TT_BLATHER(("%s ~~ %s: %f ~~ %f",#value1,#value2,v1,v2)); \
+ } else { \
+ TT_FAIL(("%s ~~ %s: %f != %f",#value1,#value2,v1,v2)); \
+ } \
+ } while (0)
+
static void
test_util_sscanf(void)
{
unsigned u1, u2, u3;
char s1[20], s2[10], s3[10], ch;
int r;
+ long lng1,lng2;
+ int int1, int2;
+ double d1,d2,d3,d4;
/* Simple tests (malformed patterns, literal matching, ...) */
test_eq(-1, tor_sscanf("123", "%i", &r)); /* %i is not supported */
@@ -1608,6 +1632,65 @@ test_util_sscanf(void)
test_eq(4, tor_sscanf("1.2.3 foobar", "%u.%u.%u%c", &u1, &u2, &u3, &ch));
test_eq(' ', ch);
+ r = tor_sscanf("12345 -67890 -1", "%d %ld %d", &int1, &lng1, &int2);
+ test_eq(r,3);
+ test_eq(int1, 12345);
+ test_eq(lng1, -67890);
+ test_eq(int2, -1);
+
+#if SIZEOF_INT == 4
+ r = tor_sscanf("-2147483648. 2147483647.", "%d. %d.", &int1, &int2);
+ test_eq(r,2);
+ test_eq(int1, -2147483647-1);
+ test_eq(int2, 2147483647);
+
+ r = tor_sscanf("-2147483679.", "%d.", &int1);
+ test_eq(r,0);
+
+ r = tor_sscanf("2147483678.", "%d.", &int1);
+ test_eq(r,0);
+#elif SIZEOF_INT == 8
+ r = tor_sscanf("-9223372036854775808. 9223372036854775807.",
+ "%d. %d.", &int1, &int2);
+ test_eq(r,2);
+ test_eq(int1, -9223372036854775807-1);
+ test_eq(int2, 9223372036854775807);
+
+ r = tor_sscanf("-9223372036854775809.", "%d.", &int1);
+ test_eq(r,0);
+
+ r = tor_sscanf("9223372036854775808.", "%d.", &int1);
+ test_eq(r,0);
+#endif
+
+#if SIZEOF_LONG == 4
+ r = tor_sscanf("-2147483648. 2147483647.", "%ld. %ld.", &lng1, &lng2);
+ test_eq(r,2);
+ test_eq(lng1, -2147483647 - 1);
+ test_eq(lng2, 2147483647);
+#elif SIZEOF_LONG == 8
+ r = tor_sscanf("-9223372036854775808. 9223372036854775807.",
+ "%ld. %ld.", &lng1, &lng2);
+ test_eq(r,2);
+ test_eq(lng1, -9223372036854775807L - 1);
+ test_eq(lng2, 9223372036854775807L);
+
+ r = tor_sscanf("-9223372036854775808. 9223372036854775808.",
+ "%ld. %ld.", &lng1, &lng2);
+ test_eq(r,1);
+ r = tor_sscanf("-9223372036854775809. 9223372036854775808.",
+ "%ld. %ld.", &lng1, &lng2);
+ test_eq(r,0);
+#endif
+
+ r = tor_sscanf("123.456 .000007 -900123123.2000787 00003.2",
+ "%lf %lf %lf %lf", &d1,&d2,&d3,&d4);
+ test_eq(r,4);
+ test_feq(d1, 123.456);
+ test_feq(d2, .000007);
+ test_feq(d3, -900123123.2000787);
+ test_feq(d4, 3.2);
+
done:
;
}
@@ -1735,7 +1818,7 @@ test_util_memarea(void)
/* Make sure we don't overalign. */
p1 = memarea_alloc(area, 1);
p2 = memarea_alloc(area, 1);
- test_eq(p1+sizeof(void*), p2);
+ test_eq_ptr(p1+sizeof(void*), p2);
{
malloced_ptr = tor_malloc(64);
test_assert(!memarea_owns_ptr(area, malloced_ptr));
@@ -1780,7 +1863,7 @@ test_util_memarea(void)
memarea_clear(area);
p1 = memarea_alloc(area, 1);
- test_eq(p1, p1_orig);
+ test_eq_ptr(p1, p1_orig);
memarea_clear(area);
/* Check for running over an area's size. */
@@ -2061,13 +2144,13 @@ test_util_listdir(void *ptr)
dir_contents = tor_listdir(dirname);
test_assert(dir_contents);
/* make sure that each filename is listed. */
- test_assert(smartlist_string_isin_case(dir_contents, "hopscotch"));
- test_assert(smartlist_string_isin_case(dir_contents, "mumblety-peg"));
- test_assert(smartlist_string_isin_case(dir_contents, ".hidden-file"));
- test_assert(smartlist_string_isin_case(dir_contents, "some-directory"));
+ test_assert(smartlist_contains_string_case(dir_contents, "hopscotch"));
+ test_assert(smartlist_contains_string_case(dir_contents, "mumblety-peg"));
+ test_assert(smartlist_contains_string_case(dir_contents, ".hidden-file"));
+ test_assert(smartlist_contains_string_case(dir_contents, "some-directory"));
- test_assert(!smartlist_string_isin(dir_contents, "."));
- test_assert(!smartlist_string_isin(dir_contents, ".."));
+ test_assert(!smartlist_contains_string(dir_contents, "."));
+ test_assert(!smartlist_contains_string(dir_contents, ".."));
done:
tor_free(fname1);
@@ -2136,7 +2219,7 @@ test_util_load_win_lib(void *ptr)
tt_assert(h);
done:
if (h)
- CloseHandle(h);
+ FreeLibrary(h);
}
#endif
@@ -2558,7 +2641,7 @@ test_util_join_win_cmdline(void *ptr)
};
int i;
- char *joined_argv;
+ char *joined_argv = NULL;
(void)ptr;
@@ -2570,7 +2653,7 @@ test_util_join_win_cmdline(void *ptr)
}
done:
- ;
+ tor_free(joined_argv);
}
#define MAX_SPLIT_LINE_COUNT 4
@@ -2690,6 +2773,16 @@ test_util_di_ops(void)
test_eq(neq1, !eq1);
}
+ tt_int_op(1, ==, safe_mem_is_zero("", 0));
+ tt_int_op(1, ==, safe_mem_is_zero("", 1));
+ tt_int_op(0, ==, safe_mem_is_zero("a", 1));
+ tt_int_op(0, ==, safe_mem_is_zero("a", 2));
+ tt_int_op(0, ==, safe_mem_is_zero("\0a", 2));
+ tt_int_op(1, ==, safe_mem_is_zero("\0\0a", 2));
+ tt_int_op(1, ==, safe_mem_is_zero("\0\0\0\0\0\0\0\0", 8));
+ tt_int_op(1, ==, safe_mem_is_zero("\0\0\0\0\0\0\0\0a", 8));
+ tt_int_op(0, ==, safe_mem_is_zero("\0\0\0\0\0\0\0\0a", 9));
+
done:
;
}
@@ -3045,7 +3138,7 @@ test_util_set_env_var_in_sl(void *ptr)
SMARTLIST_FOREACH(new_env_vars, char *, env_var,
set_environment_variable_in_smartlist(merged_env_vars,
env_var,
- _tor_free,
+ tor_free_,
1));
smartlist_sort_strings(merged_env_vars);
@@ -3077,6 +3170,48 @@ test_util_set_env_var_in_sl(void *ptr)
smartlist_free(expected_resulting_env_vars);
}
+static void
+test_util_weak_random(void *arg)
+{
+ int i, j, n[16];
+ tor_weak_rng_t rng;
+ (void) arg;
+
+ tor_init_weak_random(&rng, (unsigned)time(NULL));
+
+ for (i = 1; i <= 256; ++i) {
+ for (j=0;j<100;++j) {
+ int r = tor_weak_random_range(&rng, i);
+ tt_int_op(0, <=, r);
+ tt_int_op(r, <, i);
+ }
+ }
+
+ memset(n,0,sizeof(n));
+ for (j=0;j<8192;++j) {
+ n[tor_weak_random_range(&rng, 16)]++;
+ }
+
+ for (i=0;i<16;++i)
+ tt_int_op(n[i], >, 0);
+ done:
+ ;
+}
+
+static void
+test_util_mathlog(void *arg)
+{
+ double d;
+ (void) arg;
+
+ d = tor_mathlog(2.718281828);
+ tt_double_op(fabs(d - 1.0), <, .000001);
+ d = tor_mathlog(10);
+ tt_double_op(fabs(d - 2.30258509), <, .000001);
+ done:
+ ;
+}
+
#define UTIL_LEGACY(name) \
{ #name, legacy_test_helper, 0, &legacy_setup, test_util_ ## name }
@@ -3130,6 +3265,11 @@ struct testcase_t util_tests[] = {
UTIL_TEST(envnames, 0),
UTIL_TEST(make_environment, 0),
UTIL_TEST(set_env_var_in_sl, 0),
+ 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(mathlog, 0),
+ UTIL_TEST(weak_random, 0),
END_OF_TESTCASES
};
diff --git a/src/test/tinytest.c b/src/test/tinytest.c
deleted file mode 100644
index 4d9afacce..000000000
--- a/src/test/tinytest.c
+++ /dev/null
@@ -1,387 +0,0 @@
-/* tinytest.c -- Copyright 2009-2012 Nick Mathewson
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#ifdef TINYTEST_LOCAL
-#include "tinytest_local.h"
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-
-#ifdef _WIN32
-#include <windows.h>
-#else
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#endif
-
-#ifndef __GNUC__
-#define __attribute__(x)
-#endif
-
-#include "tinytest.h"
-#include "tinytest_macros.h"
-
-#define LONGEST_TEST_NAME 16384
-
-static int in_tinytest_main = 0; /**< true if we're in tinytest_main().*/
-static int n_ok = 0; /**< Number of tests that have passed */
-static int n_bad = 0; /**< Number of tests that have failed. */
-static int n_skipped = 0; /**< Number of tests that have been skipped. */
-
-static int opt_forked = 0; /**< True iff we're called from inside a win32 fork*/
-static int opt_nofork = 0; /**< Suppress calls to fork() for debugging. */
-static int opt_verbosity = 1; /**< -==quiet,0==terse,1==normal,2==verbose */
-const char *verbosity_flag = "";
-
-enum outcome { SKIP=2, OK=1, FAIL=0 };
-static enum outcome cur_test_outcome = 0;
-const char *cur_test_prefix = NULL; /**< prefix of the current test group */
-/** Name of the current test, if we haven't logged is yet. Used for --quiet */
-const char *cur_test_name = NULL;
-
-#ifdef _WIN32
-/* Copy of argv[0] for win32. */
-static char commandname[MAX_PATH+1];
-#endif
-
-static void usage(struct testgroup_t *groups, int list_groups)
- __attribute__((noreturn));
-
-static enum outcome
-testcase_run_bare_(const struct testcase_t *testcase)
-{
- void *env = NULL;
- int outcome;
- if (testcase->setup) {
- env = testcase->setup->setup_fn(testcase);
- if (!env)
- return FAIL;
- else if (env == (void*)TT_SKIP)
- return SKIP;
- }
-
- cur_test_outcome = OK;
- testcase->fn(env);
- outcome = cur_test_outcome;
-
- if (testcase->setup) {
- if (testcase->setup->cleanup_fn(testcase, env) == 0)
- outcome = FAIL;
- }
-
- return outcome;
-}
-
-#define MAGIC_EXITCODE 42
-
-static enum outcome
-testcase_run_forked_(const struct testgroup_t *group,
- const struct testcase_t *testcase)
-{
-#ifdef _WIN32
- /* Fork? On Win32? How primitive! We'll do what the smart kids do:
- we'll invoke our own exe (whose name we recall from the command
- line) with a command line that tells it to run just the test we
- want, and this time without forking.
-
- (No, threads aren't an option. The whole point of forking is to
- share no state between tests.)
- */
- int ok;
- char buffer[LONGEST_TEST_NAME+256];
- STARTUPINFOA si;
- PROCESS_INFORMATION info;
- DWORD exitcode;
-
- if (!in_tinytest_main) {
- printf("\nERROR. On Windows, testcase_run_forked_ must be"
- " called from within tinytest_main.\n");
- abort();
- }
- if (opt_verbosity>0)
- printf("[forking] ");
-
- snprintf(buffer, sizeof(buffer), "%s --RUNNING-FORKED %s %s%s",
- commandname, verbosity_flag, group->prefix, testcase->name);
-
- memset(&si, 0, sizeof(si));
- memset(&info, 0, sizeof(info));
- si.cb = sizeof(si);
-
- ok = CreateProcessA(commandname, buffer, NULL, NULL, 0,
- 0, NULL, NULL, &si, &info);
- if (!ok) {
- printf("CreateProcess failed!\n");
- return 0;
- }
- WaitForSingleObject(info.hProcess, INFINITE);
- GetExitCodeProcess(info.hProcess, &exitcode);
- CloseHandle(info.hProcess);
- CloseHandle(info.hThread);
- if (exitcode == 0)
- return OK;
- else if (exitcode == MAGIC_EXITCODE)
- return SKIP;
- else
- return FAIL;
-#else
- int outcome_pipe[2];
- pid_t pid;
- (void)group;
-
- if (pipe(outcome_pipe))
- perror("opening pipe");
-
- if (opt_verbosity>0)
- printf("[forking] ");
- pid = fork();
- if (!pid) {
- /* child. */
- int test_r, write_r;
- char b[1];
- close(outcome_pipe[0]);
- test_r = testcase_run_bare_(testcase);
- assert(0<=(int)test_r && (int)test_r<=2);
- b[0] = "NYS"[test_r];
- write_r = (int)write(outcome_pipe[1], b, 1);
- if (write_r != 1) {
- perror("write outcome to pipe");
- exit(1);
- }
- exit(0);
- return FAIL; /* unreachable */
- } else {
- /* parent */
- int status, r;
- char b[1];
- /* Close this now, so that if the other side closes it,
- * our read fails. */
- close(outcome_pipe[1]);
- r = (int)read(outcome_pipe[0], b, 1);
- if (r == 0) {
- printf("[Lost connection!] ");
- return 0;
- } else if (r != 1) {
- perror("read outcome from pipe");
- }
- waitpid(pid, &status, 0);
- close(outcome_pipe[0]);
- return b[0]=='Y' ? OK : (b[0]=='S' ? SKIP : FAIL);
- }
-#endif
-}
-
-int
-testcase_run_one(const struct testgroup_t *group,
- const struct testcase_t *testcase)
-{
- enum outcome outcome;
-
- if (testcase->flags & TT_SKIP) {
- if (opt_verbosity>0)
- printf("%s%s: SKIPPED\n",
- group->prefix, testcase->name);
- ++n_skipped;
- return SKIP;
- }
-
- if (opt_verbosity>0 && !opt_forked) {
- printf("%s%s: ", group->prefix, testcase->name);
- } else {
- if (opt_verbosity==0) printf(".");
- cur_test_prefix = group->prefix;
- cur_test_name = testcase->name;
- }
-
- if ((testcase->flags & TT_FORK) && !(opt_forked||opt_nofork)) {
- outcome = testcase_run_forked_(group, testcase);
- } else {
- outcome = testcase_run_bare_(testcase);
- }
-
- if (outcome == OK) {
- ++n_ok;
- if (opt_verbosity>0 && !opt_forked)
- puts(opt_verbosity==1?"OK":"");
- } else if (outcome == SKIP) {
- ++n_skipped;
- if (opt_verbosity>0 && !opt_forked)
- puts("SKIPPED");
- } else {
- ++n_bad;
- if (!opt_forked)
- printf("\n [%s FAILED]\n", testcase->name);
- }
-
- if (opt_forked) {
- exit(outcome==OK ? 0 : (outcome==SKIP?MAGIC_EXITCODE : 1));
- return 1; /* unreachable */
- } else {
- return (int)outcome;
- }
-}
-
-int
-tinytest_set_flag_(struct testgroup_t *groups, const char *arg, unsigned long flag)
-{
- int i, j;
- size_t length = LONGEST_TEST_NAME;
- char fullname[LONGEST_TEST_NAME];
- int found=0;
- if (strstr(arg, ".."))
- length = strstr(arg,"..")-arg;
- for (i=0; groups[i].prefix; ++i) {
- for (j=0; groups[i].cases[j].name; ++j) {
- snprintf(fullname, sizeof(fullname), "%s%s",
- groups[i].prefix, groups[i].cases[j].name);
- if (!flag) /* Hack! */
- printf(" %s\n", fullname);
- if (!strncmp(fullname, arg, length)) {
- groups[i].cases[j].flags |= flag;
- ++found;
- }
- }
- }
- return found;
-}
-
-static void
-usage(struct testgroup_t *groups, int list_groups)
-{
- puts("Options are: [--verbose|--quiet|--terse] [--no-fork]");
- puts(" Specify tests by name, or using a prefix ending with '..'");
- puts(" To skip a test, list give its name prefixed with a colon.");
- puts(" Use --list-tests for a list of tests.");
- if (list_groups) {
- puts("Known tests are:");
- tinytest_set_flag_(groups, "..", 0);
- }
- exit(0);
-}
-
-int
-tinytest_main(int c, const char **v, struct testgroup_t *groups)
-{
- int i, j, n=0;
-
-#ifdef _WIN32
- const char *sp = strrchr(v[0], '.');
- const char *extension = "";
- if (!sp || stricmp(sp, ".exe"))
- extension = ".exe"; /* Add an exe so CreateProcess will work */
- snprintf(commandname, sizeof(commandname), "%s%s", v[0], extension);
- commandname[MAX_PATH]='\0';
-#endif
- for (i=1; i<c; ++i) {
- if (v[i][0] == '-') {
- if (!strcmp(v[i], "--RUNNING-FORKED")) {
- opt_forked = 1;
- } else if (!strcmp(v[i], "--no-fork")) {
- opt_nofork = 1;
- } else if (!strcmp(v[i], "--quiet")) {
- opt_verbosity = -1;
- verbosity_flag = "--quiet";
- } else if (!strcmp(v[i], "--verbose")) {
- opt_verbosity = 2;
- verbosity_flag = "--verbose";
- } else if (!strcmp(v[i], "--terse")) {
- opt_verbosity = 0;
- verbosity_flag = "--terse";
- } else if (!strcmp(v[i], "--help")) {
- usage(groups, 0);
- } else if (!strcmp(v[i], "--list-tests")) {
- usage(groups, 1);
- } else {
- printf("Unknown option %s. Try --help\n",v[i]);
- return -1;
- }
- } else {
- const char *test = v[i];
- int flag = TT_ENABLED_;
- if (test[0] == ':') {
- ++test;
- flag = TT_SKIP;
- } else {
- ++n;
- }
- if (!tinytest_set_flag_(groups, test, flag)) {
- printf("No such test as %s!\n", v[i]);
- return -1;
- }
- }
- }
- if (!n)
- tinytest_set_flag_(groups, "..", TT_ENABLED_);
-
- setvbuf(stdout, NULL, _IONBF, 0);
-
- ++in_tinytest_main;
- for (i=0; groups[i].prefix; ++i)
- for (j=0; groups[i].cases[j].name; ++j)
- if (groups[i].cases[j].flags & TT_ENABLED_)
- testcase_run_one(&groups[i],
- &groups[i].cases[j]);
-
- --in_tinytest_main;
-
- if (opt_verbosity==0)
- puts("");
-
- if (n_bad)
- printf("%d/%d TESTS FAILED. (%d skipped)\n", n_bad,
- n_bad+n_ok,n_skipped);
- else if (opt_verbosity >= 1)
- printf("%d tests ok. (%d skipped)\n", n_ok, n_skipped);
-
- return (n_bad == 0) ? 0 : 1;
-}
-
-int
-tinytest_get_verbosity_(void)
-{
- return opt_verbosity;
-}
-
-void
-tinytest_set_test_failed_(void)
-{
- if (opt_verbosity <= 0 && cur_test_name) {
- if (opt_verbosity==0) puts("");
- printf("%s%s: ", cur_test_prefix, cur_test_name);
- cur_test_name = NULL;
- }
- cur_test_outcome = 0;
-}
-
-void
-tinytest_set_test_skipped_(void)
-{
- if (cur_test_outcome==OK)
- cur_test_outcome = SKIP;
-}
-
diff --git a/src/test/tinytest.h b/src/test/tinytest.h
deleted file mode 100644
index bcac9f079..000000000
--- a/src/test/tinytest.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/* tinytest.h -- Copyright 2009-2012 Nick Mathewson
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef TINYTEST_H_INCLUDED_
-#define TINYTEST_H_INCLUDED_
-
-/** Flag for a test that needs to run in a subprocess. */
-#define TT_FORK (1<<0)
-/** Runtime flag for a test we've decided to skip. */
-#define TT_SKIP (1<<1)
-/** Internal runtime flag for a test we've decided to run. */
-#define TT_ENABLED_ (1<<2)
-/** If you add your own flags, make them start at this point. */
-#define TT_FIRST_USER_FLAG (1<<3)
-
-typedef void (*testcase_fn)(void *);
-
-struct testcase_t;
-
-/** Functions to initialize/teardown a structure for a testcase. */
-struct testcase_setup_t {
- /** Return a new structure for use by a given testcase. */
- void *(*setup_fn)(const struct testcase_t *);
- /** Clean/free a structure from setup_fn. Return 1 if ok, 0 on err. */
- int (*cleanup_fn)(const struct testcase_t *, void *);
-};
-
-/** A single test-case that you can run. */
-struct testcase_t {
- const char *name; /**< An identifier for this case. */
- testcase_fn fn; /**< The function to run to implement this case. */
- unsigned long flags; /**< Bitfield of TT_* flags. */
- const struct testcase_setup_t *setup; /**< Optional setup/cleanup fns*/
- void *setup_data; /**< Extra data usable by setup function */
-};
-#define END_OF_TESTCASES { NULL, NULL, 0, NULL, NULL }
-
-/** A group of tests that are selectable together. */
-struct testgroup_t {
- const char *prefix; /**< Prefix to prepend to testnames. */
- struct testcase_t *cases; /** Array, ending with END_OF_TESTCASES */
-};
-#define END_OF_GROUPS { NULL, NULL}
-
-/** Implementation: called from a test to indicate failure, before logging. */
-void tinytest_set_test_failed_(void);
-/** Implementation: called from a test to indicate that we're skipping. */
-void tinytest_set_test_skipped_(void);
-/** Implementation: return 0 for quiet, 1 for normal, 2 for loud. */
-int tinytest_get_verbosity_(void);
-/** Implementation: Set a flag on tests matching a name; returns number
- * of tests that matched. */
-int tinytest_set_flag_(struct testgroup_t *, const char *, unsigned long);
-
-/** Set all tests in 'groups' matching the name 'named' to be skipped. */
-#define tinytest_skip(groups, named) \
- tinytest_set_flag_(groups, named, TT_SKIP)
-
-/** Run a single testcase in a single group. */
-int testcase_run_one(const struct testgroup_t *,const struct testcase_t *);
-/** Run a set of testcases from an END_OF_GROUPS-terminated array of groups,
- as selected from the command line. */
-int tinytest_main(int argc, const char **argv, struct testgroup_t *groups);
-
-#endif
diff --git a/src/test/tinytest_demo.c b/src/test/tinytest_demo.c
deleted file mode 100644
index be95ce4c1..000000000
--- a/src/test/tinytest_demo.c
+++ /dev/null
@@ -1,215 +0,0 @@
-/* tinytest_demo.c -- Copyright 2009-2012 Nick Mathewson
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-
-/* Welcome to the example file for tinytest! I'll show you how to set up
- * some simple and not-so-simple testcases. */
-
-/* Make sure you include these headers. */
-#include "tinytest.h"
-#include "tinytest_macros.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-
-/* ============================================================ */
-
-/* First, let's see if strcmp is working. (All your test cases should be
- * functions declared to take a single void * as an argument.) */
-void
-test_strcmp(void *data)
-{
- (void)data; /* This testcase takes no data. */
-
- /* Let's make sure the empty string is equal to itself */
- if (strcmp("","")) {
- /* This macro tells tinytest to stop the current test
- * and go straight to the "end" label. */
- tt_abort_msg("The empty string was not equal to itself");
- }
-
- /* Pretty often, calling tt_abort_msg to indicate failure is more
- heavy-weight than you want. Instead, just say: */
- tt_assert(strcmp("testcase", "testcase") == 0);
-
- /* Occasionally, you don't want to stop the current testcase just
- because a single assertion has failed. In that case, use
- tt_want: */
- tt_want(strcmp("tinytest", "testcase") > 0);
-
- /* You can use the tt_*_op family of macros to compare values and to
- fail unless they have the relationship you want. They produce
- more useful output than tt_assert, since they display the actual
- values of the failing things.
-
- Fail unless strcmp("abc, "abc") == 0 */
- tt_int_op(strcmp("abc", "abc"), ==, 0);
-
- /* Fail unless strcmp("abc, "abcd") is less than 0 */
- tt_int_op(strcmp("abc", "abcd"), < , 0);
-
- /* Incidentally, there's a test_str_op that uses strcmp internally. */
- tt_str_op("abc", <, "abcd");
-
-
- /* Every test-case function needs to finish with an "end:"
- label and (optionally) code to clean up local variables. */
- end:
- ;
-}
-
-/* ============================================================ */
-
-/* Now let's mess with setup and teardown functions! These are handy if
- you have a bunch of tests that all need a similar environment, and you
- want to reconstruct that environment freshly for each one. */
-
-/* First you declare a type to hold the environment info, and functions to
- set it up and tear it down. */
-struct data_buffer {
- /* We're just going to have couple of character buffer. Using
- setup/teardown functions is probably overkill for this case.
-
- You could also do file descriptors, complicated handles, temporary
- files, etc. */
- char buffer1[512];
- char buffer2[512];
-};
-/* The setup function needs to take a const struct testcase_t and return
- void* */
-void *
-setup_data_buffer(const struct testcase_t *testcase)
-{
- struct data_buffer *db = malloc(sizeof(struct data_buffer));
-
- /* If you had a complicated set of setup rules, you might behave
- differently here depending on testcase->flags or
- testcase->setup_data or even or testcase->name. */
-
- /* Returning a NULL here would mean that we couldn't set up for this
- test, so we don't need to test db for null. */
- return db;
-}
-/* The clean function deallocates storage carefully and returns true on
- success. */
-int
-clean_data_buffer(const struct testcase_t *testcase, void *ptr)
-{
- struct data_buffer *db = ptr;
-
- if (db) {
- free(db);
- return 1;
- }
- return 0;
-}
-/* Finally, declare a testcase_setup_t with these functions. */
-struct testcase_setup_t data_buffer_setup = {
- setup_data_buffer, clean_data_buffer
-};
-
-
-/* Now let's write our test. */
-void
-test_memcpy(void *ptr)
-{
- /* This time, we use the argument. */
- struct data_buffer *db = ptr;
-
- /* We'll also introduce a local variable that might need cleaning up. */
- char *mem = NULL;
-
- /* Let's make sure that memcpy does what we'd like. */
- strcpy(db->buffer1, "String 0");
- memcpy(db->buffer2, db->buffer1, sizeof(db->buffer1));
- tt_str_op(db->buffer1, ==, db->buffer2);
-
- /* Now we've allocated memory that's referenced by a local variable.
- The end block of the function will clean it up. */
- mem = strdup("Hello world.");
- tt_assert(mem);
-
- /* Another rather trivial test. */
- tt_str_op(db->buffer1, !=, mem);
-
- end:
- /* This time our end block has something to do. */
- if (mem)
- free(mem);
-}
-
-/* ============================================================ */
-
-/* Now we need to make sure that our tests get invoked. First, you take
- a bunch of related tests and put them into an array of struct testcase_t.
-*/
-
-struct testcase_t demo_tests[] = {
- /* Here's a really simple test: it has a name you can refer to it
- with, and a function to invoke it. */
- { "strcmp", test_strcmp, },
-
- /* The second test has a flag, "TT_FORK", to make it run in a
- subprocess, and a pointer to the testcase_setup_t that configures
- its environment. */
- { "memcpy", test_memcpy, TT_FORK, &data_buffer_setup },
-
- /* The array has to end with END_OF_TESTCASES. */
- END_OF_TESTCASES
-};
-
-/* Next, we make an array of testgroups. This is mandatory. Unlike more
- heavy-duty testing frameworks, groups can't nest. */
-struct testgroup_t groups[] = {
-
- /* Every group has a 'prefix', and an array of tests. That's it. */
- { "demo/", demo_tests },
-
- END_OF_GROUPS
-};
-
-
-int
-main(int c, const char **v)
-{
- /* Finally, just call tinytest_main(). It lets you specify verbose
- or quiet output with --verbose and --quiet. You can list
- specific tests:
-
- tinytest-demo demo/memcpy
-
- or use a ..-wildcard to select multiple tests with a common
- prefix:
-
- tinytest-demo demo/..
-
- If you list no tests, you get them all by default, so that
- "tinytest-demo" and "tinytest-demo .." mean the same thing.
-
- */
- return tinytest_main(c, v, groups);
-}
diff --git a/src/test/tinytest_macros.h b/src/test/tinytest_macros.h
deleted file mode 100644
index 9ff69b1d5..000000000
--- a/src/test/tinytest_macros.h
+++ /dev/null
@@ -1,184 +0,0 @@
-/* tinytest_macros.h -- Copyright 2009-2012 Nick Mathewson
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef TINYTEST_MACROS_H_INCLUDED_
-#define TINYTEST_MACROS_H_INCLUDED_
-
-/* Helpers for defining statement-like macros */
-#define TT_STMT_BEGIN do {
-#define TT_STMT_END } while (0)
-
-/* Redefine this if your test functions want to abort with something besides
- * "goto end;" */
-#ifndef TT_EXIT_TEST_FUNCTION
-#define TT_EXIT_TEST_FUNCTION TT_STMT_BEGIN goto end; TT_STMT_END
-#endif
-
-/* Redefine this if you want to note success/failure in some different way. */
-#ifndef TT_DECLARE
-#define TT_DECLARE(prefix, args) \
- TT_STMT_BEGIN \
- printf("\n %s %s:%d: ",prefix,__FILE__,__LINE__); \
- printf args ; \
- TT_STMT_END
-#endif
-
-/* Announce a failure. Args are parenthesized printf args. */
-#define TT_GRIPE(args) TT_DECLARE("FAIL", args)
-
-/* Announce a non-failure if we're verbose. */
-#define TT_BLATHER(args) \
- TT_STMT_BEGIN \
- if (tinytest_get_verbosity_()>1) TT_DECLARE(" OK", args); \
- TT_STMT_END
-
-#define TT_DIE(args) \
- TT_STMT_BEGIN \
- tinytest_set_test_failed_(); \
- TT_GRIPE(args); \
- TT_EXIT_TEST_FUNCTION; \
- TT_STMT_END
-
-#define TT_FAIL(args) \
- TT_STMT_BEGIN \
- tinytest_set_test_failed_(); \
- TT_GRIPE(args); \
- TT_STMT_END
-
-/* Fail and abort the current test for the reason in msg */
-#define tt_abort_printf(msg) TT_DIE(msg)
-#define tt_abort_perror(op) TT_DIE(("%s: %s [%d]",(op),strerror(errno), errno))
-#define tt_abort_msg(msg) TT_DIE(("%s", msg))
-#define tt_abort() TT_DIE(("%s", "(Failed.)"))
-
-/* Fail but do not abort the current test for the reason in msg. */
-#define tt_failprint_f(msg) TT_FAIL(msg)
-#define tt_fail_perror(op) TT_FAIL(("%s: %s [%d]",(op),strerror(errno), errno))
-#define tt_fail_msg(msg) TT_FAIL(("%s", msg))
-#define tt_fail() TT_FAIL(("%s", "(Failed.)"))
-
-/* End the current test, and indicate we are skipping it. */
-#define tt_skip() \
- TT_STMT_BEGIN \
- tinytest_set_test_skipped_(); \
- TT_EXIT_TEST_FUNCTION; \
- TT_STMT_END
-
-#define tt_want_(b, msg, fail) \
- TT_STMT_BEGIN \
- if (!(b)) { \
- tinytest_set_test_failed_(); \
- TT_GRIPE(("%s",msg)); \
- fail; \
- } else { \
- TT_BLATHER(("%s",msg)); \
- } \
- TT_STMT_END
-
-/* Assert b, but do not stop the test if b fails. Log msg on failure. */
-#define tt_want_msg(b, msg) \
- tt_want_(b, msg, );
-
-/* Assert b and stop the test if b fails. Log msg on failure. */
-#define tt_assert_msg(b, msg) \
- tt_want_(b, msg, TT_EXIT_TEST_FUNCTION);
-
-/* Assert b, but do not stop the test if b fails. */
-#define tt_want(b) tt_want_msg( (b), "want("#b")")
-/* Assert b, and stop the test if b fails. */
-#define tt_assert(b) tt_assert_msg((b), "assert("#b")")
-
-#define tt_assert_test_fmt_type(a,b,str_test,type,test,printf_type,printf_fmt, \
- setup_block,cleanup_block,die_on_fail) \
- TT_STMT_BEGIN \
- type val1_ = (type)(a); \
- type val2_ = (type)(b); \
- int tt_status_ = (test); \
- if (!tt_status_ || tinytest_get_verbosity_()>1) { \
- printf_type print_; \
- printf_type print1_; \
- printf_type print2_; \
- type value_ = val1_; \
- setup_block; \
- print1_ = print_; \
- value_ = val2_; \
- setup_block; \
- print2_ = print_; \
- TT_DECLARE(tt_status_?" OK":"FAIL", \
- ("assert(%s): "printf_fmt" vs "printf_fmt, \
- str_test, print1_, print2_)); \
- print_ = print1_; \
- cleanup_block; \
- print_ = print2_; \
- cleanup_block; \
- if (!tt_status_) { \
- tinytest_set_test_failed_(); \
- die_on_fail ; \
- } \
- } \
- TT_STMT_END
-
-#define tt_assert_test_type(a,b,str_test,type,test,fmt,die_on_fail) \
- tt_assert_test_fmt_type(a,b,str_test,type,test,type,fmt, \
- {print_=value_;},{},die_on_fail)
-
-/* Helper: assert that a op b, when cast to type. Format the values with
- * printf format fmt on failure. */
-#define tt_assert_op_type(a,op,b,type,fmt) \
- tt_assert_test_type(a,b,#a" "#op" "#b,type,(val1_ op val2_),fmt, \
- TT_EXIT_TEST_FUNCTION)
-
-#define tt_int_op(a,op,b) \
- tt_assert_test_type(a,b,#a" "#op" "#b,long,(val1_ op val2_), \
- "%ld",TT_EXIT_TEST_FUNCTION)
-
-#define tt_uint_op(a,op,b) \
- tt_assert_test_type(a,b,#a" "#op" "#b,unsigned long, \
- (val1_ op val2_),"%lu",TT_EXIT_TEST_FUNCTION)
-
-#define tt_ptr_op(a,op,b) \
- tt_assert_test_type(a,b,#a" "#op" "#b,void*, \
- (val1_ op val2_),"%p",TT_EXIT_TEST_FUNCTION)
-
-#define tt_str_op(a,op,b) \
- tt_assert_test_type(a,b,#a" "#op" "#b,const char *, \
- (strcmp(val1_,val2_) op 0),"<%s>",TT_EXIT_TEST_FUNCTION)
-
-#define tt_want_int_op(a,op,b) \
- tt_assert_test_type(a,b,#a" "#op" "#b,long,(val1_ op val2_),"%ld",(void)0)
-
-#define tt_want_uint_op(a,op,b) \
- tt_assert_test_type(a,b,#a" "#op" "#b,unsigned long, \
- (val1_ op val2_),"%lu",(void)0)
-
-#define tt_want_ptr_op(a,op,b) \
- tt_assert_test_type(a,b,#a" "#op" "#b,void*, \
- (val1_ op val2_),"%p",(void)0)
-
-#define tt_want_str_op(a,op,b) \
- tt_assert_test_type(a,b,#a" "#op" "#b,const char *, \
- (strcmp(val1_,val2_) op 0),"<%s>",(void)0)
-
-#endif