aboutsummaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
Diffstat (limited to 'src/test')
-rw-r--r--src/test/Makefile.nmake2
-rw-r--r--src/test/bench.c25
-rwxr-xr-xsrc/test/bt_test.py2
-rw-r--r--src/test/ed25519_exts_ref.py2
-rw-r--r--src/test/fakechans.h2
-rw-r--r--src/test/fuzz/dict/http2
-rw-r--r--src/test/fuzz/fuzz_consensus.c2
-rw-r--r--src/test/fuzz/fuzz_descriptor.c2
-rw-r--r--src/test/fuzz/fuzz_diff.c67
-rw-r--r--src/test/fuzz/fuzz_diff_apply.c65
-rw-r--r--src/test/fuzz/fuzz_extrainfo.c2
-rw-r--r--src/test/fuzz/fuzz_hsdescv2.c2
-rw-r--r--src/test/fuzz/fuzz_http.c6
-rw-r--r--src/test/fuzz/fuzz_iptsv2.c2
-rw-r--r--src/test/fuzz/fuzz_microdesc.c2
-rw-r--r--src/test/fuzz/fuzz_vrs.c2
-rw-r--r--src/test/fuzz/fuzzing.h2
-rw-r--r--src/test/fuzz/fuzzing_common.c3
-rw-r--r--src/test/fuzz/include.am134
-rwxr-xr-xsrc/test/fuzz_static_testcases.sh2
-rw-r--r--src/test/hs_ntor_ref.py408
-rw-r--r--src/test/include.am44
-rw-r--r--src/test/log_test_helpers.c2
-rw-r--r--src/test/log_test_helpers.h6
-rwxr-xr-xsrc/test/ntor_ref.py2
-rw-r--r--src/test/rend_test_helpers.c2
-rw-r--r--src/test/rend_test_helpers.h2
-rw-r--r--src/test/test-child.c2
-rwxr-xr-xsrc/test/test-network.sh187
-rw-r--r--src/test/test-timers.c2
-rw-r--r--src/test/test.c10
-rw-r--r--src/test/test.h8
-rw-r--r--src/test/test_addr.c2
-rw-r--r--src/test/test_address.c2
-rw-r--r--src/test/test_bt_cl.c2
-rw-r--r--src/test/test_buffers.c178
-rw-r--r--src/test/test_cell_formats.c2
-rw-r--r--src/test/test_cell_queue.c2
-rw-r--r--src/test/test_channel.c2
-rw-r--r--src/test/test_channeltls.c2
-rw-r--r--src/test/test_checkdir.c2
-rw-r--r--src/test/test_circuitbuild.c133
-rw-r--r--src/test/test_circuitlist.c139
-rw-r--r--src/test/test_circuitmux.c2
-rw-r--r--src/test/test_circuituse.c2
-rw-r--r--src/test/test_compat_libevent.c2
-rw-r--r--src/test/test_config.c2
-rw-r--r--src/test/test_connection.c4
-rw-r--r--src/test/test_conscache.c340
-rw-r--r--src/test/test_consdiff.c1168
-rw-r--r--src/test/test_consdiffmgr.c890
-rw-r--r--src/test/test_containers.c2
-rw-r--r--src/test/test_controller.c2
-rw-r--r--src/test/test_controller_events.c2
-rw-r--r--src/test/test_crypto.c76
-rw-r--r--src/test/test_crypto_openssl.c107
-rw-r--r--src/test/test_crypto_slow.c5
-rw-r--r--src/test/test_data.c2
-rw-r--r--src/test/test_dir.c246
-rw-r--r--src/test/test_dir_common.c2
-rw-r--r--src/test/test_dir_common.h2
-rw-r--r--src/test/test_dir_handle_get.c73
-rw-r--r--src/test/test_entryconn.c2
-rw-r--r--src/test/test_entrynodes.c5
-rw-r--r--src/test/test_extorport.c6
-rw-r--r--src/test/test_guardfraction.c2
-rw-r--r--src/test/test_handles.c2
-rw-r--r--src/test/test_helpers.c6
-rw-r--r--src/test/test_helpers.h4
-rw-r--r--src/test/test_hs.c22
-rw-r--r--src/test/test_hs_cache.c8
-rw-r--r--src/test/test_hs_descriptor.c148
-rw-r--r--src/test/test_hs_intropoint.c123
-rwxr-xr-xsrc/test/test_hs_ntor.sh11
-rw-r--r--src/test/test_hs_ntor_cl.c255
-rw-r--r--src/test/test_hs_service.c155
-rw-r--r--src/test/test_introduce.c2
-rw-r--r--src/test/test_keypin.c2
-rw-r--r--src/test/test_link_handshake.c26
-rw-r--r--src/test/test_logging.c2
-rw-r--r--src/test/test_microdesc.c8
-rw-r--r--src/test/test_nodelist.c2
-rw-r--r--src/test/test_ntor_cl.c2
-rw-r--r--src/test/test_oom.c2
-rw-r--r--src/test/test_oos.c2
-rw-r--r--src/test/test_options.c121
-rw-r--r--src/test/test_policy.c2
-rw-r--r--src/test/test_procmon.c2
-rw-r--r--src/test/test_protover.c2
-rw-r--r--src/test/test_pt.c8
-rw-r--r--src/test/test_pubsub.c2
-rw-r--r--src/test/test_relay.c2
-rw-r--r--src/test/test_relaycell.c2
-rw-r--r--src/test/test_rendcache.c3
-rw-r--r--src/test/test_replay.c2
-rw-r--r--src/test/test_routerkeys.c2
-rw-r--r--src/test/test_routerlist.c2
-rw-r--r--src/test/test_scheduler.c2
-rw-r--r--src/test/test_slow.c2
-rw-r--r--src/test/test_socks.c2
-rw-r--r--src/test/test_storagedir.c375
-rw-r--r--src/test/test_switch_id.c2
-rw-r--r--src/test/test_threads.c2
-rw-r--r--src/test/test_tortls.c3
-rw-r--r--src/test/test_util.c359
-rw-r--r--src/test/test_util_format.c70
-rw-r--r--src/test/test_util_process.c2
-rw-r--r--src/test/test_util_slow.c6
-rw-r--r--src/test/test_workqueue.c2
-rw-r--r--src/test/testing_common.c8
-rw-r--r--src/test/testing_rsakeys.c2
111 files changed, 5339 insertions, 843 deletions
diff --git a/src/test/Makefile.nmake b/src/test/Makefile.nmake
index 0ba56d7036..575198388b 100644
--- a/src/test/Makefile.nmake
+++ b/src/test/Makefile.nmake
@@ -12,7 +12,7 @@ LIBS = ..\..\..\build-alpha\lib\libevent.lib \
crypt32.lib gdi32.lib user32.lib
TEST_OBJECTS = test.obj test_addr.obj test_channel.obj test_channeltls.obj \
- test_containers.obj \
+ test_consdiff.obj test_containers.obj \
test_controller_events.obj test_crypto.obj test_data.obj test_dir.obj \
test_checkdir.obj test_microdesc.obj test_pt.obj test_util.obj \
test_config.obj test_connection.obj \
diff --git a/src/test/bench.c b/src/test/bench.c
index 99bc686f30..a44dc94a61 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-2016, The Tor Project, Inc. */
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
extern const char tor_git_revision[];
@@ -28,6 +28,7 @@ const char tor_git_revision[] = "";
#include "crypto_curve25519.h"
#include "onion_ntor.h"
#include "crypto_ed25519.h"
+#include "consdiff.h"
#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_PROCESS_CPUTIME_ID)
static uint64_t nanostart;
@@ -673,6 +674,28 @@ main(int argc, const char **argv)
or_options_t *options;
tor_threads_init();
+ tor_compress_init();
+
+ if (argc == 4 && !strcmp(argv[1], "diff")) {
+ init_logging(1);
+ const int N = 200;
+ char *f1 = read_file_to_str(argv[2], RFTS_BIN, NULL);
+ char *f2 = read_file_to_str(argv[3], RFTS_BIN, NULL);
+ if (! f1 || ! f2) {
+ perror("X");
+ return 1;
+ }
+ for (i = 0; i < N; ++i) {
+ char *diff = consensus_diff_generate(f1, f2);
+ tor_free(diff);
+ }
+ char *diff = consensus_diff_generate(f1, f2);
+ printf("%s", diff);
+ tor_free(f1);
+ tor_free(f2);
+ tor_free(diff);
+ return 0;
+ }
for (i = 1; i < argc; ++i) {
if (!strcmp(argv[i], "--list")) {
diff --git a/src/test/bt_test.py b/src/test/bt_test.py
index 30591453b9..4cb3326042 100755
--- a/src/test/bt_test.py
+++ b/src/test/bt_test.py
@@ -1,4 +1,4 @@
-# Copyright 2013-2015, The Tor Project, Inc
+# Copyright 2013-2017, The Tor Project, Inc
# See LICENSE for licensing information
"""
diff --git a/src/test/ed25519_exts_ref.py b/src/test/ed25519_exts_ref.py
index d5a3a79910..af5010415e 100644
--- a/src/test/ed25519_exts_ref.py
+++ b/src/test/ed25519_exts_ref.py
@@ -1,5 +1,5 @@
#!/usr/bin/python
-# Copyright 2014-2015, The Tor Project, Inc
+# Copyright 2014-2017, The Tor Project, Inc
# See LICENSE for licensing information
"""
diff --git a/src/test/fakechans.h b/src/test/fakechans.h
index fa0e37dbe6..c0de430e3d 100644
--- a/src/test/fakechans.h
+++ b/src/test/fakechans.h
@@ -1,4 +1,4 @@
- /* Copyright (c) 2014-2016, The Tor Project, Inc. */
+ /* Copyright (c) 2014-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_FAKECHANS_H
diff --git a/src/test/fuzz/dict/http b/src/test/fuzz/dict/http
index 1a7b61e8d4..3b0531579d 100644
--- a/src/test/fuzz/dict/http
+++ b/src/test/fuzz/dict/http
@@ -4,7 +4,7 @@
#
# Extracted from directory_handle_command() in the tor source code
#
-# Copyright (c) 2016, The Tor Project, Inc.
+# Copyright (c) 2016-2017, The Tor Project, Inc.
# See LICENSE for licensing information
#
# Usage:
diff --git a/src/test/fuzz/fuzz_consensus.c b/src/test/fuzz/fuzz_consensus.c
index f5d22f69ae..6610ade7ad 100644
--- a/src/test/fuzz/fuzz_consensus.c
+++ b/src/test/fuzz/fuzz_consensus.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Tor Project, Inc. */
+/* Copyright (c) 2016-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define ROUTERPARSE_PRIVATE
#include "or.h"
diff --git a/src/test/fuzz/fuzz_descriptor.c b/src/test/fuzz/fuzz_descriptor.c
index d19386d77f..1a50beae17 100644
--- a/src/test/fuzz/fuzz_descriptor.c
+++ b/src/test/fuzz/fuzz_descriptor.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Tor Project, Inc. */
+/* Copyright (c) 2016-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define ROUTERPARSE_PRIVATE
#include "or.h"
diff --git a/src/test/fuzz/fuzz_diff.c b/src/test/fuzz/fuzz_diff.c
new file mode 100644
index 0000000000..c241f63dc4
--- /dev/null
+++ b/src/test/fuzz/fuzz_diff.c
@@ -0,0 +1,67 @@
+/* Copyright (c) 2016, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#define CONSDIFF_PRIVATE
+
+#include "orconfig.h"
+#include "or.h"
+#include "consdiff.h"
+
+#include "fuzzing.h"
+
+static int
+mock_consensus_compute_digest_(const char *c, consensus_digest_t *d)
+{
+ (void)c;
+ memset(d->sha3_256, 3, sizeof(d->sha3_256));
+ return 0;
+}
+
+int
+fuzz_init(void)
+{
+ MOCK(consensus_compute_digest, mock_consensus_compute_digest_);
+ return 0;
+}
+
+int
+fuzz_cleanup(void)
+{
+ UNMOCK(consensus_compute_digest);
+ return 0;
+}
+
+int
+fuzz_main(const uint8_t *stdin_buf, size_t data_size)
+{
+#define SEP "=====\n"
+#define SEPLEN strlen(SEP)
+ const uint8_t *separator = tor_memmem(stdin_buf, data_size, SEP, SEPLEN);
+ if (! separator)
+ return 0;
+ size_t c1_len = separator - stdin_buf;
+ char *c1 = tor_memdup_nulterm(stdin_buf, c1_len);
+ size_t c2_len = data_size - c1_len - SEPLEN;
+ char *c2 = tor_memdup_nulterm(separator + SEPLEN, c2_len);
+
+ char *c3 = consensus_diff_generate(c1, c2);
+
+ if (c3) {
+ char *c4 = consensus_diff_apply(c1, c3);
+ tor_assert(c4);
+ if (strcmp(c2, c4)) {
+ printf("%s\n", escaped(c1));
+ printf("%s\n", escaped(c2));
+ printf("%s\n", escaped(c3));
+ printf("%s\n", escaped(c4));
+ }
+ tor_assert(! strcmp(c2, c4));
+ tor_free(c3);
+ tor_free(c4);
+ }
+ tor_free(c1);
+ tor_free(c2);
+
+ return 0;
+}
+
diff --git a/src/test/fuzz/fuzz_diff_apply.c b/src/test/fuzz/fuzz_diff_apply.c
new file mode 100644
index 0000000000..8d7bf751bf
--- /dev/null
+++ b/src/test/fuzz/fuzz_diff_apply.c
@@ -0,0 +1,65 @@
+/* Copyright (c) 2016, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#define CONSDIFF_PRIVATE
+
+#include "orconfig.h"
+#include "or.h"
+#include "consdiff.h"
+
+#include "fuzzing.h"
+
+static int
+mock_consensus_compute_digest_(const char *c, consensus_digest_t *d)
+{
+ (void)c;
+ memset(d->sha3_256, 3, sizeof(d->sha3_256));
+ return 0;
+}
+
+static int
+mock_consensus_digest_eq_(const uint8_t *a, const uint8_t *b)
+{
+ (void)a;
+ (void)b;
+ return 1;
+}
+
+int
+fuzz_init(void)
+{
+ MOCK(consensus_compute_digest, mock_consensus_compute_digest_);
+ MOCK(consensus_digest_eq, mock_consensus_digest_eq_);
+ return 0;
+}
+
+int
+fuzz_cleanup(void)
+{
+ UNMOCK(consensus_compute_digest);
+ UNMOCK(consensus_digest_eq);
+ return 0;
+}
+
+int
+fuzz_main(const uint8_t *stdin_buf, size_t data_size)
+{
+#define SEP "=====\n"
+#define SEPLEN strlen(SEP)
+ const uint8_t *separator = tor_memmem(stdin_buf, data_size, SEP, SEPLEN);
+ if (! separator)
+ return 0;
+ size_t c1_len = separator - stdin_buf;
+ char *c1 = tor_memdup_nulterm(stdin_buf, c1_len);
+ size_t c2_len = data_size - c1_len - SEPLEN;
+ char *c2 = tor_memdup_nulterm(separator + SEPLEN, c2_len);
+
+ char *c3 = consensus_diff_apply(c1, c2);
+
+ tor_free(c1);
+ tor_free(c2);
+ tor_free(c3);
+
+ return 0;
+}
+
diff --git a/src/test/fuzz/fuzz_extrainfo.c b/src/test/fuzz/fuzz_extrainfo.c
index 6251e606d0..2a3de7ecf7 100644
--- a/src/test/fuzz/fuzz_extrainfo.c
+++ b/src/test/fuzz/fuzz_extrainfo.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Tor Project, Inc. */
+/* Copyright (c) 2016-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define ROUTERPARSE_PRIVATE
#include "or.h"
diff --git a/src/test/fuzz/fuzz_hsdescv2.c b/src/test/fuzz/fuzz_hsdescv2.c
index 53b7cbe2f7..19db265716 100644
--- a/src/test/fuzz/fuzz_hsdescv2.c
+++ b/src/test/fuzz/fuzz_hsdescv2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Tor Project, Inc. */
+/* Copyright (c) 2016-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define ROUTERPARSE_PRIVATE
#include "or.h"
diff --git a/src/test/fuzz/fuzz_http.c b/src/test/fuzz/fuzz_http.c
index 01c3815f18..2ffeb60244 100644
--- a/src/test/fuzz/fuzz_http.c
+++ b/src/test/fuzz/fuzz_http.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Tor Project, Inc. */
+/* Copyright (c) 2016-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -18,10 +18,10 @@
static void
mock_connection_write_to_buf_impl_(const char *string, size_t len,
- connection_t *conn, int zlib)
+ connection_t *conn, int compressed)
{
log_debug(LD_GENERAL, "%sResponse:\n%u\nConnection: %p\n%s\n",
- zlib ? "Compressed " : "", (unsigned)len, conn, string);
+ compressed ? "Compressed " : "", (unsigned)len, conn, string);
}
static int
diff --git a/src/test/fuzz/fuzz_iptsv2.c b/src/test/fuzz/fuzz_iptsv2.c
index 341d4880bd..4abde0c16d 100644
--- a/src/test/fuzz/fuzz_iptsv2.c
+++ b/src/test/fuzz/fuzz_iptsv2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Tor Project, Inc. */
+/* Copyright (c) 2016-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define ROUTERPARSE_PRIVATE
#include "or.h"
diff --git a/src/test/fuzz/fuzz_microdesc.c b/src/test/fuzz/fuzz_microdesc.c
index bb89546191..396115026e 100644
--- a/src/test/fuzz/fuzz_microdesc.c
+++ b/src/test/fuzz/fuzz_microdesc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Tor Project, Inc. */
+/* Copyright (c) 2016-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define ROUTERPARSE_PRIVATE
#include "or.h"
diff --git a/src/test/fuzz/fuzz_vrs.c b/src/test/fuzz/fuzz_vrs.c
index 9301a9bcc8..baf0610a0b 100644
--- a/src/test/fuzz/fuzz_vrs.c
+++ b/src/test/fuzz/fuzz_vrs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Tor Project, Inc. */
+/* Copyright (c) 2016-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define ROUTERPARSE_PRIVATE
#define NETWORKSTATUS_PRIVATE
diff --git a/src/test/fuzz/fuzzing.h b/src/test/fuzz/fuzzing.h
index 4295743458..aecdbb4e52 100644
--- a/src/test/fuzz/fuzzing.h
+++ b/src/test/fuzz/fuzzing.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Tor Project, Inc. */
+/* Copyright (c) 2016-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef FUZZING_H
#define FUZZING_H
diff --git a/src/test/fuzz/fuzzing_common.c b/src/test/fuzz/fuzzing_common.c
index e4920d3ee7..7aee92df63 100644
--- a/src/test/fuzz/fuzzing_common.c
+++ b/src/test/fuzz/fuzzing_common.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Tor Project, Inc. */
+/* Copyright (c) 2016-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CRYPTO_ED25519_PRIVATE
#include "orconfig.h"
@@ -96,6 +96,7 @@ static void
global_init(void)
{
tor_threads_init();
+ tor_compress_init();
{
struct sipkey sipkey = { 1337, 7331 };
siphash_set_global_key(&sipkey);
diff --git a/src/test/fuzz/include.am b/src/test/fuzz/include.am
index 806710879b..500377f6d7 100644
--- a/src/test/fuzz/include.am
+++ b/src/test/fuzz/include.am
@@ -1,4 +1,5 @@
-
+# This file was generated by fuzzing_include_am.py; do not hand-edit unless
+# you enjoy having your changes erased.
FUZZING_CPPFLAGS = \
$(src_test_AM_CPPFLAGS) $(TEST_CPPFLAGS)
FUZZING_CFLAGS = \
@@ -17,7 +18,9 @@ FUZZING_LIBS = \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \
@TOR_LIBEVENT_LIBS@ \
@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ \
- @TOR_SYSTEMD_LIBS@
+ @TOR_SYSTEMD_LIBS@ \
+ @TOR_LZMA_LIBS@ \
+ @TOR_ZSTD_LIBS@
oss-fuzz-prereqs: \
src/or/libtor-testing.a \
@@ -32,6 +35,16 @@ oss-fuzz-prereqs: \
noinst_HEADERS += \
src/test/fuzz/fuzzing.h
+LIBFUZZER = /home/nickm/build/libfuzz/libFuzzer.a
+LIBFUZZER_CPPFLAGS = $(FUZZING_CPPFLAGS) -DLLVM_FUZZ
+LIBFUZZER_CFLAGS = $(FUZZING_CFLAGS)
+LIBFUZZER_LDFLAG = $(FUZZING_LDFLAG)
+LIBFUZZER_LIBS = $(FUZZING_LIBS) $(LIBFUZZER) -lstdc++
+
+LIBOSS_FUZZ_CPPFLAGS = $(FUZZING_CPPFLAGS) -DLLVM_FUZZ
+LIBOSS_FUZZ_CFLAGS = $(FUZZING_CFLAGS)
+
+# ===== AFL fuzzers
src_test_fuzz_fuzz_consensus_SOURCES = \
src/test/fuzz/fuzzing_common.c \
src/test/fuzz/fuzz_consensus.c
@@ -48,13 +61,29 @@ src_test_fuzz_fuzz_descriptor_CFLAGS = $(FUZZING_CFLAGS)
src_test_fuzz_fuzz_descriptor_LDFLAGS = $(FUZZING_LDFLAG)
src_test_fuzz_fuzz_descriptor_LDADD = $(FUZZING_LIBS)
-src_test_fuzz_fuzz_http_SOURCES = \
+src_test_fuzz_fuzz_diff_SOURCES = \
src/test/fuzz/fuzzing_common.c \
- src/test/fuzz/fuzz_http.c
-src_test_fuzz_fuzz_http_CPPFLAGS = $(FUZZING_CPPFLAGS)
-src_test_fuzz_fuzz_http_CFLAGS = $(FUZZING_CFLAGS)
-src_test_fuzz_fuzz_http_LDFLAGS = $(FUZZING_LDFLAG)
-src_test_fuzz_fuzz_http_LDADD = $(FUZZING_LIBS)
+ src/test/fuzz/fuzz_diff.c
+src_test_fuzz_fuzz_diff_CPPFLAGS = $(FUZZING_CPPFLAGS)
+src_test_fuzz_fuzz_diff_CFLAGS = $(FUZZING_CFLAGS)
+src_test_fuzz_fuzz_diff_LDFLAGS = $(FUZZING_LDFLAG)
+src_test_fuzz_fuzz_diff_LDADD = $(FUZZING_LIBS)
+
+src_test_fuzz_fuzz_diff_apply_SOURCES = \
+ src/test/fuzz/fuzzing_common.c \
+ src/test/fuzz/fuzz_diff_apply.c
+src_test_fuzz_fuzz_diff_apply_CPPFLAGS = $(FUZZING_CPPFLAGS)
+src_test_fuzz_fuzz_diff_apply_CFLAGS = $(FUZZING_CFLAGS)
+src_test_fuzz_fuzz_diff_apply_LDFLAGS = $(FUZZING_LDFLAG)
+src_test_fuzz_fuzz_diff_apply_LDADD = $(FUZZING_LIBS)
+
+src_test_fuzz_fuzz_extrainfo_SOURCES = \
+ src/test/fuzz/fuzzing_common.c \
+ src/test/fuzz/fuzz_extrainfo.c
+src_test_fuzz_fuzz_extrainfo_CPPFLAGS = $(FUZZING_CPPFLAGS)
+src_test_fuzz_fuzz_extrainfo_CFLAGS = $(FUZZING_CFLAGS)
+src_test_fuzz_fuzz_extrainfo_LDFLAGS = $(FUZZING_LDFLAG)
+src_test_fuzz_fuzz_extrainfo_LDADD = $(FUZZING_LIBS)
src_test_fuzz_fuzz_hsdescv2_SOURCES = \
src/test/fuzz/fuzzing_common.c \
@@ -64,6 +93,14 @@ src_test_fuzz_fuzz_hsdescv2_CFLAGS = $(FUZZING_CFLAGS)
src_test_fuzz_fuzz_hsdescv2_LDFLAGS = $(FUZZING_LDFLAG)
src_test_fuzz_fuzz_hsdescv2_LDADD = $(FUZZING_LIBS)
+src_test_fuzz_fuzz_http_SOURCES = \
+ src/test/fuzz/fuzzing_common.c \
+ src/test/fuzz/fuzz_http.c
+src_test_fuzz_fuzz_http_CPPFLAGS = $(FUZZING_CPPFLAGS)
+src_test_fuzz_fuzz_http_CFLAGS = $(FUZZING_CFLAGS)
+src_test_fuzz_fuzz_http_LDFLAGS = $(FUZZING_LDFLAG)
+src_test_fuzz_fuzz_http_LDADD = $(FUZZING_LIBS)
+
src_test_fuzz_fuzz_iptsv2_SOURCES = \
src/test/fuzz/fuzzing_common.c \
src/test/fuzz/fuzz_iptsv2.c
@@ -72,14 +109,6 @@ src_test_fuzz_fuzz_iptsv2_CFLAGS = $(FUZZING_CFLAGS)
src_test_fuzz_fuzz_iptsv2_LDFLAGS = $(FUZZING_LDFLAG)
src_test_fuzz_fuzz_iptsv2_LDADD = $(FUZZING_LIBS)
-src_test_fuzz_fuzz_extrainfo_SOURCES = \
- src/test/fuzz/fuzzing_common.c \
- src/test/fuzz/fuzz_extrainfo.c
-src_test_fuzz_fuzz_extrainfo_CPPFLAGS = $(FUZZING_CPPFLAGS)
-src_test_fuzz_fuzz_extrainfo_CFLAGS = $(FUZZING_CFLAGS)
-src_test_fuzz_fuzz_extrainfo_LDFLAGS = $(FUZZING_LDFLAG)
-src_test_fuzz_fuzz_extrainfo_LDADD = $(FUZZING_LIBS)
-
src_test_fuzz_fuzz_microdesc_SOURCES = \
src/test/fuzz/fuzzing_common.c \
src/test/fuzz/fuzz_microdesc.c
@@ -99,19 +128,16 @@ src_test_fuzz_fuzz_vrs_LDADD = $(FUZZING_LIBS)
FUZZERS = \
src/test/fuzz/fuzz-consensus \
src/test/fuzz/fuzz-descriptor \
+ src/test/fuzz/fuzz-diff \
+ src/test/fuzz/fuzz-diff-apply \
src/test/fuzz/fuzz-extrainfo \
- src/test/fuzz/fuzz-http \
src/test/fuzz/fuzz-hsdescv2 \
+ src/test/fuzz/fuzz-http \
src/test/fuzz/fuzz-iptsv2 \
src/test/fuzz/fuzz-microdesc \
src/test/fuzz/fuzz-vrs
-
-LIBFUZZER = /home/nickm/build/libfuzz/libFuzzer.a
-LIBFUZZER_CPPFLAGS = $(FUZZING_CPPFLAGS) -DLLVM_FUZZ
-LIBFUZZER_CFLAGS = $(FUZZING_CFLAGS)
-LIBFUZZER_LDFLAG = $(FUZZING_LDFLAG)
-LIBFUZZER_LIBS = $(FUZZING_LIBS) $(LIBFUZZER) -lstdc++
+# ===== libfuzzer
if LIBFUZZER_ENABLED
src_test_fuzz_lf_fuzz_consensus_SOURCES = \
@@ -128,6 +154,20 @@ src_test_fuzz_lf_fuzz_descriptor_CFLAGS = $(LIBFUZZER_CFLAGS)
src_test_fuzz_lf_fuzz_descriptor_LDFLAGS = $(LIBFUZZER_LDFLAG)
src_test_fuzz_lf_fuzz_descriptor_LDADD = $(LIBFUZZER_LIBS)
+src_test_fuzz_lf_fuzz_diff_SOURCES = \
+ $(src_test_fuzz_fuzz_diff_SOURCES)
+src_test_fuzz_lf_fuzz_diff_CPPFLAGS = $(LIBFUZZER_CPPFLAGS)
+src_test_fuzz_lf_fuzz_diff_CFLAGS = $(LIBFUZZER_CFLAGS)
+src_test_fuzz_lf_fuzz_diff_LDFLAGS = $(LIBFUZZER_LDFLAG)
+src_test_fuzz_lf_fuzz_diff_LDADD = $(LIBFUZZER_LIBS)
+
+src_test_fuzz_lf_fuzz_diff_apply_SOURCES = \
+ $(src_test_fuzz_fuzz_diff_apply_SOURCES)
+src_test_fuzz_lf_fuzz_diff_apply_CPPFLAGS = $(LIBFUZZER_CPPFLAGS)
+src_test_fuzz_lf_fuzz_diff_apply_CFLAGS = $(LIBFUZZER_CFLAGS)
+src_test_fuzz_lf_fuzz_diff_apply_LDFLAGS = $(LIBFUZZER_LDFLAG)
+src_test_fuzz_lf_fuzz_diff_apply_LDADD = $(LIBFUZZER_LIBS)
+
src_test_fuzz_lf_fuzz_extrainfo_SOURCES = \
$(src_test_fuzz_fuzz_extrainfo_SOURCES)
src_test_fuzz_lf_fuzz_extrainfo_CPPFLAGS = $(LIBFUZZER_CPPFLAGS)
@@ -135,13 +175,6 @@ src_test_fuzz_lf_fuzz_extrainfo_CFLAGS = $(LIBFUZZER_CFLAGS)
src_test_fuzz_lf_fuzz_extrainfo_LDFLAGS = $(LIBFUZZER_LDFLAG)
src_test_fuzz_lf_fuzz_extrainfo_LDADD = $(LIBFUZZER_LIBS)
-src_test_fuzz_lf_fuzz_http_SOURCES = \
- $(src_test_fuzz_fuzz_http_SOURCES)
-src_test_fuzz_lf_fuzz_http_CPPFLAGS = $(LIBFUZZER_CPPFLAGS)
-src_test_fuzz_lf_fuzz_http_CFLAGS = $(LIBFUZZER_CFLAGS)
-src_test_fuzz_lf_fuzz_http_LDFLAGS = $(LIBFUZZER_LDFLAG)
-src_test_fuzz_lf_fuzz_http_LDADD = $(LIBFUZZER_LIBS)
-
src_test_fuzz_lf_fuzz_hsdescv2_SOURCES = \
$(src_test_fuzz_fuzz_hsdescv2_SOURCES)
src_test_fuzz_lf_fuzz_hsdescv2_CPPFLAGS = $(LIBFUZZER_CPPFLAGS)
@@ -149,6 +182,13 @@ src_test_fuzz_lf_fuzz_hsdescv2_CFLAGS = $(LIBFUZZER_CFLAGS)
src_test_fuzz_lf_fuzz_hsdescv2_LDFLAGS = $(LIBFUZZER_LDFLAG)
src_test_fuzz_lf_fuzz_hsdescv2_LDADD = $(LIBFUZZER_LIBS)
+src_test_fuzz_lf_fuzz_http_SOURCES = \
+ $(src_test_fuzz_fuzz_http_SOURCES)
+src_test_fuzz_lf_fuzz_http_CPPFLAGS = $(LIBFUZZER_CPPFLAGS)
+src_test_fuzz_lf_fuzz_http_CFLAGS = $(LIBFUZZER_CFLAGS)
+src_test_fuzz_lf_fuzz_http_LDFLAGS = $(LIBFUZZER_LDFLAG)
+src_test_fuzz_lf_fuzz_http_LDADD = $(LIBFUZZER_LIBS)
+
src_test_fuzz_lf_fuzz_iptsv2_SOURCES = \
$(src_test_fuzz_fuzz_iptsv2_SOURCES)
src_test_fuzz_lf_fuzz_iptsv2_CPPFLAGS = $(LIBFUZZER_CPPFLAGS)
@@ -173,9 +213,11 @@ src_test_fuzz_lf_fuzz_vrs_LDADD = $(LIBFUZZER_LIBS)
LIBFUZZER_FUZZERS = \
src/test/fuzz/lf-fuzz-consensus \
src/test/fuzz/lf-fuzz-descriptor \
+ src/test/fuzz/lf-fuzz-diff \
+ src/test/fuzz/lf-fuzz-diff-apply \
src/test/fuzz/lf-fuzz-extrainfo \
- src/test/fuzz/lf-fuzz-http \
src/test/fuzz/lf-fuzz-hsdescv2 \
+ src/test/fuzz/lf-fuzz-http \
src/test/fuzz/lf-fuzz-iptsv2 \
src/test/fuzz/lf-fuzz-microdesc \
src/test/fuzz/lf-fuzz-vrs
@@ -184,10 +226,9 @@ else
LIBFUZZER_FUZZERS =
endif
-if OSS_FUZZ_ENABLED
-LIBOSS_FUZZ_CPPFLAGS = $(FUZZING_CPPFLAGS) -DLLVM_FUZZ
-LIBOSS_FUZZ_CFLAGS = $(FUZZING_CFLAGS)
+# ===== oss-fuzz
+if OSS_FUZZ_ENABLED
src_test_fuzz_liboss_fuzz_consensus_a_SOURCES = \
$(src_test_fuzz_fuzz_consensus_SOURCES)
src_test_fuzz_liboss_fuzz_consensus_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS)
@@ -198,21 +239,31 @@ src_test_fuzz_liboss_fuzz_descriptor_a_SOURCES = \
src_test_fuzz_liboss_fuzz_descriptor_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS)
src_test_fuzz_liboss_fuzz_descriptor_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS)
+src_test_fuzz_liboss_fuzz_diff_a_SOURCES = \
+ $(src_test_fuzz_fuzz_diff_SOURCES)
+src_test_fuzz_liboss_fuzz_diff_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS)
+src_test_fuzz_liboss_fuzz_diff_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS)
+
+src_test_fuzz_liboss_fuzz_diff_apply_a_SOURCES = \
+ $(src_test_fuzz_fuzz_diff_apply_SOURCES)
+src_test_fuzz_liboss_fuzz_diff_apply_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS)
+src_test_fuzz_liboss_fuzz_diff_apply_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS)
+
src_test_fuzz_liboss_fuzz_extrainfo_a_SOURCES = \
$(src_test_fuzz_fuzz_extrainfo_SOURCES)
src_test_fuzz_liboss_fuzz_extrainfo_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS)
src_test_fuzz_liboss_fuzz_extrainfo_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS)
-src_test_fuzz_liboss_fuzz_http_a_SOURCES = \
- $(src_test_fuzz_fuzz_http_SOURCES)
-src_test_fuzz_liboss_fuzz_http_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS)
-src_test_fuzz_liboss_fuzz_http_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS)
-
src_test_fuzz_liboss_fuzz_hsdescv2_a_SOURCES = \
$(src_test_fuzz_fuzz_hsdescv2_SOURCES)
src_test_fuzz_liboss_fuzz_hsdescv2_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS)
src_test_fuzz_liboss_fuzz_hsdescv2_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS)
+src_test_fuzz_liboss_fuzz_http_a_SOURCES = \
+ $(src_test_fuzz_fuzz_http_SOURCES)
+src_test_fuzz_liboss_fuzz_http_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS)
+src_test_fuzz_liboss_fuzz_http_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS)
+
src_test_fuzz_liboss_fuzz_iptsv2_a_SOURCES = \
$(src_test_fuzz_fuzz_iptsv2_SOURCES)
src_test_fuzz_liboss_fuzz_iptsv2_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS)
@@ -231,12 +282,15 @@ src_test_fuzz_liboss_fuzz_vrs_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS)
OSS_FUZZ_FUZZERS = \
src/test/fuzz/liboss-fuzz-consensus.a \
src/test/fuzz/liboss-fuzz-descriptor.a \
+ src/test/fuzz/liboss-fuzz-diff.a \
+ src/test/fuzz/liboss-fuzz-diff-apply.a \
src/test/fuzz/liboss-fuzz-extrainfo.a \
- src/test/fuzz/liboss-fuzz-http.a \
src/test/fuzz/liboss-fuzz-hsdescv2.a \
+ src/test/fuzz/liboss-fuzz-http.a \
src/test/fuzz/liboss-fuzz-iptsv2.a \
src/test/fuzz/liboss-fuzz-microdesc.a \
src/test/fuzz/liboss-fuzz-vrs.a
+
else
OSS_FUZZ_FUZZERS =
endif
diff --git a/src/test/fuzz_static_testcases.sh b/src/test/fuzz_static_testcases.sh
index bfe1677573..3cb45ad5e6 100755
--- a/src/test/fuzz_static_testcases.sh
+++ b/src/test/fuzz_static_testcases.sh
@@ -1,6 +1,6 @@
#!/bin/sh
-# Copyright (c) 2016, The Tor Project, Inc.
+# Copyright (c) 2016-2017, The Tor Project, Inc.
# See LICENSE for licensing information
set -e
diff --git a/src/test/hs_ntor_ref.py b/src/test/hs_ntor_ref.py
new file mode 100644
index 0000000000..813e797828
--- /dev/null
+++ b/src/test/hs_ntor_ref.py
@@ -0,0 +1,408 @@
+#!/usr/bin/python
+# Copyright 2017, The Tor Project, Inc
+# See LICENSE for licensing information
+
+"""
+hs_ntor_ref.py
+
+This module is a reference implementation of the modified ntor protocol
+proposed for Tor hidden services in proposal 224 (Next Generation Hidden
+Services) in section [NTOR-WITH-EXTRA-DATA].
+
+The modified ntor protocol is a single-round protocol, with three steps in total:
+
+ 1: Client generates keys and sends them to service via INTRODUCE cell
+
+ 2: Service computes key material based on client's keys, and sends its own
+ keys to client via RENDEZVOUS cell
+
+ 3: Client computes key material as well.
+
+It's meant to be used to validate Tor's HS ntor implementation by conducting
+various integration tests. Specifically it conducts the following three tests:
+
+- Tests our Python implementation by running the whole protocol in Python and
+ making sure that results are consistent.
+
+- Tests little-t-tor ntor implementation. We use this Python code to instrument
+ little-t-tor and carry out the handshake by using little-t-tor code. The
+ small C wrapper at src/test/test-hs-ntor-cl is used for this Python module to
+ interface with little-t-tor.
+
+- Cross-tests Python and little-t-tor implementation by running half of the
+ protocol in Python code and the other in little-t-tor. This is actually two
+ tests so that all parts of the protocol are run both by little-t-tor and
+ Python.
+
+It requires the curve25519 python module from the curve25519-donna package.
+
+The whole logic and concept for this test suite was taken from ntor_ref.py.
+
+ *** DO NOT USE THIS IN PRODUCTION. ***
+"""
+
+import struct
+import os, sys
+import binascii
+import subprocess
+
+try:
+ import curve25519
+ curve25519mod = curve25519.keys
+except ImportError:
+ curve25519 = None
+ import slownacl_curve25519
+ curve25519mod = slownacl_curve25519
+
+try:
+ import sha3
+except ImportError:
+ # error code 77 tells automake to skip this test
+ sys.exit(77)
+
+# Import Nick's ntor reference implementation in Python
+# We are gonna use a few of its utilities.
+from ntor_ref import hash_nil
+from ntor_ref import PrivateKey
+
+# String constants used in this protocol
+PROTOID = "tor-hs-ntor-curve25519-sha3-256-1"
+T_HSENC = PROTOID + ":hs_key_extract"
+T_HSVERIFY = PROTOID + ":hs_verify"
+T_HSMAC = PROTOID + ":hs_mac"
+M_HSEXPAND = PROTOID + ":hs_key_expand"
+
+INTRO_SECRET_LEN = 161
+REND_SECRET_LEN = 225
+AUTH_INPUT_LEN = 199
+
+# Implements MAC(k,m) = H(htonll(len(k)) | k | m)
+def mac(k,m):
+ def htonll(num):
+ return struct.pack('!q', num)
+
+ s = sha3.SHA3256()
+ s.update(htonll(len(k)))
+ s.update(k)
+ s.update(m)
+ return s.digest()
+
+######################################################################
+
+# Functions that implement the modified HS ntor protocol
+
+"""As client compute key material for INTRODUCE cell as follows:
+
+ intro_secret_hs_input = EXP(B,x) | AUTH_KEY | X | B | PROTOID
+ info = m_hsexpand | subcredential
+ hs_keys = KDF(intro_secret_hs_input | t_hsenc | info, S_KEY_LEN+MAC_LEN)
+ ENC_KEY = hs_keys[0:S_KEY_LEN]
+ MAC_KEY = hs_keys[S_KEY_LEN:S_KEY_LEN+MAC_KEY_LEN]
+"""
+def intro2_ntor_client(intro_auth_pubkey_str, intro_enc_pubkey,
+ client_ephemeral_enc_pubkey, client_ephemeral_enc_privkey, subcredential):
+
+ dh_result = client_ephemeral_enc_privkey.get_shared_key(intro_enc_pubkey, hash_nil)
+ secret = dh_result + intro_auth_pubkey_str + client_ephemeral_enc_pubkey.serialize() + intro_enc_pubkey.serialize() + PROTOID
+ assert(len(secret) == INTRO_SECRET_LEN)
+ info = M_HSEXPAND + subcredential
+
+ kdf = sha3.SHAKE256()
+ kdf.update(secret + T_HSENC + info)
+ key_material = kdf.squeeze(64*8)
+
+ enc_key = key_material[0:32]
+ mac_key = key_material[32:64]
+
+ return enc_key, mac_key
+
+"""Wrapper over intro2_ntor_client()"""
+def client_part1(intro_auth_pubkey_str, intro_enc_pubkey,
+ client_ephemeral_enc_pubkey, client_ephemeral_enc_privkey, subcredential):
+ enc_key, mac_key = intro2_ntor_client(intro_auth_pubkey_str, intro_enc_pubkey, client_ephemeral_enc_pubkey, client_ephemeral_enc_privkey, subcredential)
+ assert(enc_key)
+ assert(mac_key)
+
+ return enc_key, mac_key
+
+"""As service compute key material for INTRODUCE cell as follows:
+
+ intro_secret_hs_input = EXP(X,b) | AUTH_KEY | X | B | PROTOID
+ info = m_hsexpand | subcredential
+ hs_keys = KDF(intro_secret_hs_input | t_hsenc | info, S_KEY_LEN+MAC_LEN)
+ HS_DEC_KEY = hs_keys[0:S_KEY_LEN]
+ HS_MAC_KEY = hs_keys[S_KEY_LEN:S_KEY_LEN+MAC_KEY_LEN]
+"""
+def intro2_ntor_service(intro_auth_pubkey_str, client_enc_pubkey, service_enc_privkey, service_enc_pubkey, subcredential):
+ dh_result = service_enc_privkey.get_shared_key(client_enc_pubkey, hash_nil)
+ secret = dh_result + intro_auth_pubkey_str + client_enc_pubkey.serialize() + service_enc_pubkey.serialize() + PROTOID
+ assert(len(secret) == INTRO_SECRET_LEN)
+ info = M_HSEXPAND + subcredential
+
+ kdf = sha3.SHAKE256()
+ kdf.update(secret + T_HSENC + info)
+ key_material = kdf.squeeze(64*8)
+
+ enc_key = key_material[0:32]
+ mac_key = key_material[32:64]
+
+ return enc_key, mac_key
+
+"""As service compute key material for INTRODUCE and REDNEZVOUS cells.
+
+ Use intro2_ntor_service() to calculate the INTRODUCE key material, and use
+ the following computations to do the RENDEZVOUS ones:
+
+ rend_secret_hs_input = EXP(X,y) | EXP(X,b) | AUTH_KEY | B | X | Y | PROTOID
+ NTOR_KEY_SEED = MAC(rend_secret_hs_input, t_hsenc)
+ verify = MAC(rend_secret_hs_input, t_hsverify)
+ auth_input = verify | AUTH_KEY | B | Y | X | PROTOID | "Server"
+ AUTH_INPUT_MAC = MAC(auth_input, t_hsmac)
+"""
+def service_part1(intro_auth_pubkey_str, client_enc_pubkey, intro_enc_privkey, intro_enc_pubkey, subcredential):
+ intro_enc_key, intro_mac_key = intro2_ntor_service(intro_auth_pubkey_str, client_enc_pubkey, intro_enc_privkey, intro_enc_pubkey, subcredential)
+ assert(intro_enc_key)
+ assert(intro_mac_key)
+
+ service_ephemeral_privkey = PrivateKey()
+ service_ephemeral_pubkey = service_ephemeral_privkey.get_public()
+
+ dh_result1 = service_ephemeral_privkey.get_shared_key(client_enc_pubkey, hash_nil)
+ dh_result2 = intro_enc_privkey.get_shared_key(client_enc_pubkey, hash_nil)
+ rend_secret_hs_input = dh_result1 + dh_result2 + intro_auth_pubkey_str + intro_enc_pubkey.serialize() + client_enc_pubkey.serialize() + service_ephemeral_pubkey.serialize() + PROTOID
+ assert(len(rend_secret_hs_input) == REND_SECRET_LEN)
+
+ ntor_key_seed = mac(rend_secret_hs_input, T_HSENC)
+ verify = mac(rend_secret_hs_input, T_HSVERIFY)
+ auth_input = verify + intro_auth_pubkey_str + intro_enc_pubkey.serialize() + service_ephemeral_pubkey.serialize() + client_enc_pubkey.serialize() + PROTOID + "Server"
+ assert(len(auth_input) == AUTH_INPUT_LEN)
+ auth_input_mac = mac(auth_input, T_HSMAC)
+
+ assert(ntor_key_seed)
+ assert(auth_input_mac)
+ assert(service_ephemeral_pubkey)
+
+ return intro_enc_key, intro_mac_key, ntor_key_seed, auth_input_mac, service_ephemeral_pubkey
+
+"""As client compute key material for rendezvous cells as follows:
+
+ rend_secret_hs_input = EXP(Y,x) | EXP(B,x) | AUTH_KEY | B | X | Y | PROTOID
+ NTOR_KEY_SEED = MAC(ntor_secret_input, t_hsenc)
+ verify = MAC(ntor_secret_input, t_hsverify)
+ auth_input = verify | AUTH_KEY | B | Y | X | PROTOID | "Server"
+ AUTH_INPUT_MAC = MAC(auth_input, t_hsmac)
+"""
+def client_part2(intro_auth_pubkey_str, client_ephemeral_enc_pubkey, client_ephemeral_enc_privkey,
+ intro_enc_pubkey, service_ephemeral_rend_pubkey):
+ dh_result1 = client_ephemeral_enc_privkey.get_shared_key(service_ephemeral_rend_pubkey, hash_nil)
+ dh_result2 = client_ephemeral_enc_privkey.get_shared_key(intro_enc_pubkey, hash_nil)
+ rend_secret_hs_input = dh_result1 + dh_result2 + intro_auth_pubkey_str + intro_enc_pubkey.serialize() + client_ephemeral_enc_pubkey.serialize() + service_ephemeral_rend_pubkey.serialize() + PROTOID
+ assert(len(rend_secret_hs_input) == REND_SECRET_LEN)
+
+ ntor_key_seed = mac(rend_secret_hs_input, T_HSENC)
+ verify = mac(rend_secret_hs_input, T_HSVERIFY)
+ auth_input = verify + intro_auth_pubkey_str + intro_enc_pubkey.serialize() + service_ephemeral_rend_pubkey.serialize() + client_ephemeral_enc_pubkey.serialize() + PROTOID + "Server"
+ assert(len(auth_input) == AUTH_INPUT_LEN)
+ auth_input_mac = mac(auth_input, T_HSMAC)
+
+ assert(ntor_key_seed)
+ assert(auth_input_mac)
+
+ return ntor_key_seed, auth_input_mac
+
+#################################################################################
+
+"""
+Utilities for communicating with the little-t-tor ntor wrapper to conduct the
+integration tests
+"""
+
+PROG = b"./src/test/test-hs-ntor-cl"
+enhex=lambda s: binascii.b2a_hex(s)
+dehex=lambda s: binascii.a2b_hex(s.strip())
+
+def tor_client1(intro_auth_pubkey_str, intro_enc_pubkey,
+ client_ephemeral_enc_privkey, subcredential):
+ p = subprocess.Popen([PROG, "client1",
+ enhex(intro_auth_pubkey_str),
+ enhex(intro_enc_pubkey.serialize()),
+ enhex(client_ephemeral_enc_privkey.serialize()),
+ enhex(subcredential)],
+ stdout=subprocess.PIPE)
+ return map(dehex, p.stdout.readlines())
+
+def tor_server1(intro_auth_pubkey_str, intro_enc_privkey,
+ client_ephemeral_enc_pubkey, subcredential):
+ p = subprocess.Popen([PROG, "server1",
+ enhex(intro_auth_pubkey_str),
+ enhex(intro_enc_privkey.serialize()),
+ enhex(client_ephemeral_enc_pubkey.serialize()),
+ enhex(subcredential)],
+ stdout=subprocess.PIPE)
+ return map(dehex, p.stdout.readlines())
+
+def tor_client2(intro_auth_pubkey_str, client_ephemeral_enc_privkey,
+ intro_enc_pubkey, service_ephemeral_rend_pubkey, subcredential):
+ p = subprocess.Popen([PROG, "client2",
+ enhex(intro_auth_pubkey_str),
+ enhex(client_ephemeral_enc_privkey.serialize()),
+ enhex(intro_enc_pubkey.serialize()),
+ enhex(service_ephemeral_rend_pubkey.serialize()),
+ enhex(subcredential)],
+ stdout=subprocess.PIPE)
+ return map(dehex, p.stdout.readlines())
+
+##################################################################################
+
+# Perform a pure python ntor test
+def do_pure_python_ntor_test():
+ # Initialize all needed key material
+ client_ephemeral_enc_privkey = PrivateKey()
+ client_ephemeral_enc_pubkey = client_ephemeral_enc_privkey.get_public()
+ intro_enc_privkey = PrivateKey()
+ intro_enc_pubkey = intro_enc_privkey.get_public()
+ intro_auth_pubkey_str = os.urandom(32)
+ subcredential = os.urandom(32)
+
+ client_enc_key, client_mac_key = client_part1(intro_auth_pubkey_str, intro_enc_pubkey, client_ephemeral_enc_pubkey, client_ephemeral_enc_privkey, subcredential)
+
+ service_enc_key, service_mac_key, service_ntor_key_seed, service_auth_input_mac, service_ephemeral_pubkey = service_part1(intro_auth_pubkey_str, client_ephemeral_enc_pubkey, intro_enc_privkey, intro_enc_pubkey, subcredential)
+
+ assert(client_enc_key == service_enc_key)
+ assert(client_mac_key == service_mac_key)
+
+ client_ntor_key_seed, client_auth_input_mac = client_part2(intro_auth_pubkey_str, client_ephemeral_enc_pubkey, client_ephemeral_enc_privkey,
+ intro_enc_pubkey, service_ephemeral_pubkey)
+
+ assert(client_ntor_key_seed == service_ntor_key_seed)
+ assert(client_auth_input_mac == service_auth_input_mac)
+
+ print "DONE: python dance [%s]" % repr(client_auth_input_mac)
+
+# Perform a pure little-t-tor integration test.
+def do_little_t_tor_ntor_test():
+ # Initialize all needed key material
+ subcredential = os.urandom(32)
+ client_ephemeral_enc_privkey = PrivateKey()
+ client_ephemeral_enc_pubkey = client_ephemeral_enc_privkey.get_public()
+ intro_enc_privkey = PrivateKey()
+ intro_enc_pubkey = intro_enc_privkey.get_public() # service-side enc key
+ intro_auth_pubkey_str = os.urandom(32)
+
+ client_enc_key, client_mac_key = tor_client1(intro_auth_pubkey_str, intro_enc_pubkey,
+ client_ephemeral_enc_privkey, subcredential)
+ assert(client_enc_key)
+ assert(client_mac_key)
+
+ service_enc_key, service_mac_key, service_ntor_auth_mac, service_ntor_key_seed, service_eph_pubkey = tor_server1(intro_auth_pubkey_str,
+ intro_enc_privkey,
+ client_ephemeral_enc_pubkey,
+ subcredential)
+ assert(service_enc_key)
+ assert(service_mac_key)
+ assert(service_ntor_auth_mac)
+ assert(service_ntor_key_seed)
+
+ assert(client_enc_key == service_enc_key)
+ assert(client_mac_key == service_mac_key)
+
+ # Turn from bytes to key
+ service_eph_pubkey = curve25519mod.Public(service_eph_pubkey)
+
+ client_ntor_auth_mac, client_ntor_key_seed = tor_client2(intro_auth_pubkey_str, client_ephemeral_enc_privkey,
+ intro_enc_pubkey, service_eph_pubkey, subcredential)
+ assert(client_ntor_auth_mac)
+ assert(client_ntor_key_seed)
+
+ assert(client_ntor_key_seed == service_ntor_key_seed)
+ assert(client_ntor_auth_mac == service_ntor_auth_mac)
+
+ print "DONE: tor dance [%s]" % repr(client_ntor_auth_mac)
+
+"""
+Do mixed test as follows:
+ 1. C -> S (python mode)
+ 2. C <- S (tor mode)
+ 3. Client computes keys (python mode)
+"""
+def do_first_mixed_test():
+ subcredential = os.urandom(32)
+
+ client_ephemeral_enc_privkey = PrivateKey()
+ client_ephemeral_enc_pubkey = client_ephemeral_enc_privkey.get_public()
+ intro_enc_privkey = PrivateKey()
+ intro_enc_pubkey = intro_enc_privkey.get_public() # service-side enc key
+
+ intro_auth_pubkey_str = os.urandom(32)
+
+ # Let's do mixed
+ client_enc_key, client_mac_key = client_part1(intro_auth_pubkey_str, intro_enc_pubkey,
+ client_ephemeral_enc_pubkey, client_ephemeral_enc_privkey,
+ subcredential)
+
+ service_enc_key, service_mac_key, service_ntor_auth_mac, service_ntor_key_seed, service_eph_pubkey = tor_server1(intro_auth_pubkey_str,
+ intro_enc_privkey,
+ client_ephemeral_enc_pubkey,
+ subcredential)
+ assert(service_enc_key)
+ assert(service_mac_key)
+ assert(service_ntor_auth_mac)
+ assert(service_ntor_key_seed)
+ assert(service_eph_pubkey)
+
+ assert(client_enc_key == service_enc_key)
+ assert(client_mac_key == service_mac_key)
+
+ # Turn from bytes to key
+ service_eph_pubkey = curve25519mod.Public(service_eph_pubkey)
+
+ client_ntor_key_seed, client_auth_input_mac = client_part2(intro_auth_pubkey_str, client_ephemeral_enc_pubkey, client_ephemeral_enc_privkey,
+ intro_enc_pubkey, service_eph_pubkey)
+
+ assert(client_auth_input_mac == service_ntor_auth_mac)
+ assert(client_ntor_key_seed == service_ntor_key_seed)
+
+ print "DONE: 1st mixed dance [%s]" % repr(client_auth_input_mac)
+
+"""
+Do mixed test as follows:
+ 1. C -> S (tor mode)
+ 2. C <- S (python mode)
+ 3. Client computes keys (tor mode)
+"""
+def do_second_mixed_test():
+ subcredential = os.urandom(32)
+
+ client_ephemeral_enc_privkey = PrivateKey()
+ client_ephemeral_enc_pubkey = client_ephemeral_enc_privkey.get_public()
+ intro_enc_privkey = PrivateKey()
+ intro_enc_pubkey = intro_enc_privkey.get_public() # service-side enc key
+
+ intro_auth_pubkey_str = os.urandom(32)
+
+ # Let's do mixed
+ client_enc_key, client_mac_key = tor_client1(intro_auth_pubkey_str, intro_enc_pubkey,
+ client_ephemeral_enc_privkey, subcredential)
+ assert(client_enc_key)
+ assert(client_mac_key)
+
+ service_enc_key, service_mac_key, service_ntor_key_seed, service_ntor_auth_mac, service_ephemeral_pubkey = service_part1(intro_auth_pubkey_str, client_ephemeral_enc_pubkey, intro_enc_privkey, intro_enc_pubkey, subcredential)
+
+ client_ntor_auth_mac, client_ntor_key_seed = tor_client2(intro_auth_pubkey_str, client_ephemeral_enc_privkey,
+ intro_enc_pubkey, service_ephemeral_pubkey, subcredential)
+ assert(client_ntor_auth_mac)
+ assert(client_ntor_key_seed)
+
+ assert(client_ntor_key_seed == service_ntor_key_seed)
+ assert(client_ntor_auth_mac == service_ntor_auth_mac)
+
+ print "DONE: 2nd mixed dance [%s]" % repr(client_ntor_auth_mac)
+
+def do_mixed_tests():
+ do_first_mixed_test()
+ do_second_mixed_test()
+
+if __name__ == '__main__':
+ do_pure_python_ntor_test()
+ do_little_t_tor_ntor_test()
+ do_mixed_tests()
diff --git a/src/test/include.am b/src/test/include.am
index 1c0726fd3a..230a6c8bad 100644
--- a/src/test/include.am
+++ b/src/test/include.am
@@ -20,7 +20,7 @@ TESTSCRIPTS = \
src/test/test_switch_id.sh
if USEPYTHON
-TESTSCRIPTS += src/test/test_ntor.sh src/test/test_bt.sh
+TESTSCRIPTS += src/test/test_ntor.sh src/test/test_hs_ntor.sh src/test/test_bt.sh
endif
TESTS += src/test/test src/test/test-slow src/test/test-memwipe \
@@ -82,14 +82,19 @@ src_test_test_SOURCES = \
src/test/test_checkdir.c \
src/test/test_circuitlist.c \
src/test/test_circuitmux.c \
+ src/test/test_circuitbuild.c \
src/test/test_circuituse.c \
src/test/test_compat_libevent.c \
src/test/test_config.c \
src/test/test_connection.c \
+ src/test/test_conscache.c \
+ src/test/test_consdiff.c \
+ src/test/test_consdiffmgr.c \
src/test/test_containers.c \
src/test/test_controller.c \
src/test/test_controller_events.c \
src/test/test_crypto.c \
+ src/test/test_crypto_openssl.c \
src/test/test_data.c \
src/test/test_dir.c \
src/test/test_dir_common.c \
@@ -129,6 +134,7 @@ src_test_test_SOURCES = \
src/test/test_shared_random.c \
src/test/test_socks.c \
src/test/test_status.c \
+ src/test/test_storagedir.c \
src/test/test_threads.c \
src/test/test_tortls.c \
src/test/test_util.c \
@@ -174,7 +180,8 @@ src_test_test_switch_id_LDFLAGS = @TOR_LDFLAGS_zlib@
src_test_test_switch_id_LDADD = \
src/common/libor-testing.a \
src/common/libor-ctime-testing.a \
- @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@
+ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \
+ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
src_test_test_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \
@TOR_LDFLAGS_libevent@
@@ -186,9 +193,10 @@ src_test_test_LDADD = src/or/libtor-testing.a \
src/common/libor-ctime-testing.a \
src/common/libor-event-testing.a \
src/trunnel/libor-trunnel-testing.a \
+ src/trace/libor-trace.a \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ \
- @TOR_SYSTEMD_LIBS@
+ @TOR_SYSTEMD_LIBS@ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
src_test_test_slow_CPPFLAGS = $(src_test_test_CPPFLAGS)
src_test_test_slow_CFLAGS = $(src_test_test_CFLAGS)
@@ -209,9 +217,10 @@ src_test_bench_LDADD = src/or/libtor.a src/common/libor.a \
src/common/libor-ctime.a \
src/common/libor-crypto.a $(LIBKECCAK_TINY) $(LIBDONNA) \
src/common/libor-event.a src/trunnel/libor-trunnel.a \
+ src/trace/libor-trace.a \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ \
- @TOR_SYSTEMD_LIBS@
+ @TOR_SYSTEMD_LIBS@ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
src_test_test_workqueue_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \
@TOR_LDFLAGS_libevent@
@@ -220,8 +229,10 @@ src_test_test_workqueue_LDADD = src/or/libtor-testing.a \
src/common/libor-ctime-testing.a \
src/common/libor-crypto-testing.a $(LIBKECCAK_TINY) $(LIBDONNA) \
src/common/libor-event-testing.a \
+ src/trace/libor-trace.a \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
- @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
+ @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ \
+ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
src_test_test_timers_CPPFLAGS = $(src_test_test_CPPFLAGS)
src_test_test_timers_CFLAGS = $(src_test_test_CFLAGS)
@@ -231,7 +242,8 @@ src_test_test_timers_LDADD = \
src/common/libor-event-testing.a \
src/common/libor-crypto-testing.a $(LIBKECCAK_TINY) $(LIBDONNA) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
- @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
+ @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ \
+ @TOR_LZMA_LIBS@
src_test_test_timers_LDFLAGS = $(src_test_test_LDFLAGS)
noinst_HEADERS+= \
@@ -249,20 +261,35 @@ noinst_HEADERS+= \
src/test/vote_descriptors.inc
noinst_PROGRAMS+= src/test/test-ntor-cl
+noinst_PROGRAMS+= src/test/test-hs-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-ctime.a \
src/common/libor-crypto.a $(LIBKECCAK_TINY) $(LIBDONNA) \
+ src/trace/libor-trace.a \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \
- @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
+ @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ \
+ @TOR_LZMA_LIBS@
src_test_test_ntor_cl_AM_CPPFLAGS = \
-I"$(top_srcdir)/src/or"
+src_test_test_hs_ntor_cl_SOURCES = src/test/test_hs_ntor_cl.c
+src_test_test_hs_ntor_cl_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@
+src_test_test_hs_ntor_cl_LDADD = src/or/libtor.a src/common/libor.a \
+ src/common/libor-ctime.a \
+ src/common/libor-crypto.a $(LIBKECCAK_TINY) $(LIBDONNA) \
+ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \
+ @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
+src_test_test_hs_ntor_cl_AM_CPPFLAGS = \
+ -I"$(top_srcdir)/src/or"
+
+
noinst_PROGRAMS += src/test/test-bt-cl
src_test_test_bt_cl_SOURCES = src/test/test_bt_cl.c
src_test_test_bt_cl_LDADD = src/common/libor-testing.a \
src/common/libor-ctime-testing.a \
+ src/trace/libor-trace.a \
@TOR_LIB_MATH@ \
@TOR_LIB_WS32@ @TOR_LIB_GDI@
src_test_test_bt_cl_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
@@ -271,12 +298,13 @@ src_test_test_bt_cl_CPPFLAGS= $(src_test_AM_CPPFLAGS) $(TEST_CPPFLAGS)
EXTRA_DIST += \
src/test/bt_test.py \
src/test/ntor_ref.py \
+ src/test/hs_ntor_ref.py \
src/test/fuzz_static_testcases.sh \
src/test/slownacl_curve25519.py \
src/test/zero_length_keys.sh \
src/test/test_keygen.sh \
src/test/test_zero_length_keys.sh \
- src/test/test_ntor.sh src/test/test_bt.sh \
+ src/test/test_ntor.sh src/test/test_hs_ntor.sh src/test/test_bt.sh \
src/test/test-network.sh \
src/test/test_switch_id.sh \
src/test/test_workqueue_cancel.sh \
diff --git a/src/test/log_test_helpers.c b/src/test/log_test_helpers.c
index c788a33c17..d5a39cfeee 100644
--- a/src/test/log_test_helpers.c
+++ b/src/test/log_test_helpers.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Tor Project, Inc. */
+/* Copyright (c) 2015-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define LOG_PRIVATE
#include "torlog.h"
diff --git a/src/test/log_test_helpers.h b/src/test/log_test_helpers.h
index 922c68b42f..f7798c0249 100644
--- a/src/test/log_test_helpers.h
+++ b/src/test/log_test_helpers.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Tor Project, Inc. */
+/* Copyright (c) 2014-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "or.h"
@@ -71,14 +71,14 @@ void mock_dump_saved_logs(void);
\
assert_log_predicate(mock_saved_log_has_message_containing(str) && \
mock_saved_log_n_entries() == 1, \
- "expected log to contain exactly 1 message: " # str); \
+ "expected log to contain exactly 1 message " # str); \
} while (0);
#define expect_single_log_msg_containing(str) \
do { \
assert_log_predicate(mock_saved_log_has_message_containing(str)&& \
mock_saved_log_n_entries() == 1 , \
- "expected log to contain 1 message, containing" # str); \
+ "expected log to contain 1 message, containing " # str); \
} while (0);
#define expect_no_log_msg(str) \
diff --git a/src/test/ntor_ref.py b/src/test/ntor_ref.py
index df065853f3..c753588f97 100755
--- a/src/test/ntor_ref.py
+++ b/src/test/ntor_ref.py
@@ -1,5 +1,5 @@
#!/usr/bin/python
-# Copyright 2012-2015, The Tor Project, Inc
+# Copyright 2012-2017, The Tor Project, Inc
# See LICENSE for licensing information
"""
diff --git a/src/test/rend_test_helpers.c b/src/test/rend_test_helpers.c
index 377337bcb9..f7880046fb 100644
--- a/src/test/rend_test_helpers.c
+++ b/src/test/rend_test_helpers.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Tor Project, Inc. */
+/* Copyright (c) 2014-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "or.h"
diff --git a/src/test/rend_test_helpers.h b/src/test/rend_test_helpers.h
index 180a4e8fde..486adba436 100644
--- a/src/test/rend_test_helpers.h
+++ b/src/test/rend_test_helpers.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Tor Project, Inc. */
+/* Copyright (c) 2014-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "or.h"
diff --git a/src/test/test-child.c b/src/test/test-child.c
index fdf3ccec0a..f0bdb3ea26 100644
--- a/src/test/test-child.c
+++ b/src/test/test-child.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2016, The Tor Project, Inc. */
+/* Copyright (c) 2011-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test-network.sh b/src/test/test-network.sh
index 4d9776822b..6e0f286573 100755
--- a/src/test/test-network.sh
+++ b/src/test/test-network.sh
@@ -1,103 +1,45 @@
-#! /bin/sh
+#!/bin/sh
-# Please do not modify this script, it has been moved to chutney/tools
+# This script calls the equivalent script in chutney/tools
-ECHO_N="/bin/echo -n"
+# If we already know CHUTNEY_PATH, don't bother with argument parsing
+TEST_NETWORK="$CHUTNEY_PATH/tools/test-network.sh"
+# Call the chutney version of this script, if it exists, and we can find it
+if [ -d "$CHUTNEY_PATH" -a -x "$TEST_NETWORK" ]; then
+ # we can't produce any output, because we might be --quiet
+ # this preserves arguments with spaces correctly
+ exec "$TEST_NETWORK" "$@"
+fi
+
+# We need to go looking for CHUTNEY_PATH
+# Do we output anything at all?
+ECHO="${ECHO:-echo}"
# Output is prefixed with the name of the script
myname=$(basename $0)
-# We need to find CHUTNEY_PATH, so that we can call the version of this script
-# in chutney/tools. And we want to pass any arguments to that script as well.
-# So we source this script, which processes its arguments to find CHUTNEY_PATH.
-
-# Avoid recursively sourcing this script, and don't call the chutney version
-# while recursing, either
-if [ "$TEST_NETWORK_RECURSING" != true ]; then
- # Process the arguments into environmental variables with this script
- # to make sure $CHUTNEY_PATH is set
- # When we switch to using test-network.sh in chutney/tools, --dry-run
- # can be removed, because this script will find chutney, then pass all
- # arguments to chutney's test-network.sh
- echo "$myname: Parsing command-line arguments to find \$CHUTNEY_PATH"
- export TEST_NETWORK_RECURSING=true
- . "$0" --dry-run "$@"
-
- # Call the chutney version of this script, if it exists, and we can find it
- if [ -d "$CHUTNEY_PATH" -a -x "$CHUTNEY_PATH/tools/test-network.sh" ]; then
- unset NETWORK_DRY_RUN
- echo "$myname: Calling newer chutney script \
-$CHUTNEY_PATH/tools/test-network.sh"
- "$CHUTNEY_PATH/tools/test-network.sh" "$@"
- exit $?
- else
- echo "$myname: This script has moved to chutney/tools."
- echo "$myname: Please update your chutney using 'git pull'."
- # When we switch to using test-network.sh in chutney/tools, we should
- # exit with a very loud failure here
- echo "$myname: Falling back to the old tor version of the script."
- fi
-fi
+# Save the arguments before we destroy them
+# This might not preserve arguments with spaces in them
+ORIGINAL_ARGS="$@"
+# We need to find CHUTNEY_PATH, so that we can call the version of this script
+# in chutney/tools with the same arguments. We also need to respect --quiet.
until [ -z "$1" ]
do
case "$1" in
--chutney-path)
- export CHUTNEY_PATH="$2"
+ CHUTNEY_PATH="$2"
shift
;;
--tor-path)
- export TOR_DIR="$2"
- shift
- ;;
- # When we switch to using test-network.sh in chutney/tools, only the
- # --chutney-path and --tor-path arguments need to be processed by this
- # script, everything else can be handled by chutney's test-network.sh
- --flavor|--flavour|--network-flavor|--network-flavour)
- export NETWORK_FLAVOUR="$2"
- shift
- ;;
- --delay|--sleep|--bootstrap-time|--time)
- export BOOTSTRAP_TIME="$2"
- shift
- ;;
- # Environmental variables used by chutney verify performance tests
- # Send this many bytes per client connection (10 KBytes)
- --data|--data-bytes|--data-byte|--bytes|--byte)
- export CHUTNEY_DATA_BYTES="$2"
+ TOR_DIR="$2"
shift
;;
- # Make this many connections per client (1)
- # Note: If you create 7 or more connections to a hidden service from
- # a single Tor 0.2.7 client, you'll likely get a verification failure due
- # to #15937. This is fixed in 0.2.8.
- --connections|--connection|--connection-count|--count)
- export CHUTNEY_CONNECTIONS="$2"
- shift
+ --quiet)
+ ECHO=true
;;
- # Make each client connect to each HS (0)
- # 0 means a single client connects to each HS
- # 1 means every client connects to every HS
- --hs-multi-client|--hs-multi-clients|--hs-client|--hs-clients)
- export CHUTNEY_HS_MULTI_CLIENT="$2"
- shift
- ;;
- --coverage)
- export USE_COVERAGE_BINARY=true
- ;;
- --dry-run)
- # process arguments, but don't call any other scripts
- export NETWORK_DRY_RUN=true
- ;;
*)
- echo "$myname: Sorry, I don't know what to do with '$1'."
- echo "$myname: Maybe chutney's test-network.sh understands '$1'."
- echo "$myname: Please update your chutney using 'git pull', and set \
-\$CHUTNEY_PATH"
- # continue processing arguments during a dry run
- if [ "$NETWORK_DRY_RUN" != true ]; then
- exit 2
- fi
+ # maybe chutney's test-network.sh can handle it
;;
esac
shift
@@ -106,22 +48,22 @@ done
# optional: $TOR_DIR is the tor build directory
# it's used to find the location of tor binaries
# if it's not set:
-# - set it ro $BUILDDIR, or
+# - set it to $BUILDDIR, or
# - if $PWD looks like a tor build directory, set it to $PWD, or
# - unset $TOR_DIR, and let chutney fall back to finding tor binaries in $PATH
if [ ! -d "$TOR_DIR" ]; then
if [ -d "$BUILDDIR/src/or" -a -d "$BUILDDIR/src/tools" ]; then
# Choose the build directory
# But only if it looks like one
- echo "$myname: \$TOR_DIR not set, trying \$BUILDDIR"
- export TOR_DIR="$BUILDDIR"
+ $ECHO "$myname: \$TOR_DIR not set, trying \$BUILDDIR"
+ TOR_DIR="$BUILDDIR"
elif [ -d "$PWD/src/or" -a -d "$PWD/src/tools" ]; then
# Guess the tor directory is the current directory
# But only if it looks like one
- echo "$myname: \$TOR_DIR not set, trying \$PWD"
- export TOR_DIR="$PWD"
+ $ECHO "$myname: \$TOR_DIR not set, trying \$PWD"
+ TOR_DIR="$PWD"
else
- echo "$myname: no \$TOR_DIR, chutney will use \$PATH for tor binaries"
+ $ECHO "$myname: no \$TOR_DIR, chutney will use \$PATH for tor binaries"
unset TOR_DIR
fi
fi
@@ -133,63 +75,34 @@ fi
# - fail and tell the user how to clone the chutney repository
if [ ! -d "$CHUTNEY_PATH" -o ! -x "$CHUTNEY_PATH/chutney" ]; then
if [ -x "$PWD/chutney" ]; then
- echo "$myname: \$CHUTNEY_PATH not valid, trying \$PWD"
- export CHUTNEY_PATH="$PWD"
+ $ECHO "$myname: \$CHUTNEY_PATH not valid, trying \$PWD"
+ CHUTNEY_PATH="$PWD"
elif [ -d "$TOR_DIR" -a -d "$TOR_DIR/../chutney" -a \
-x "$TOR_DIR/../chutney/chutney" ]; then
- echo "$myname: \$CHUTNEY_PATH not valid, trying \$TOR_DIR/../chutney"
- export CHUTNEY_PATH="$TOR_DIR/../chutney"
+ $ECHO "$myname: \$CHUTNEY_PATH not valid, trying \$TOR_DIR/../chutney"
+ CHUTNEY_PATH="$TOR_DIR/../chutney"
else
- # TODO: work out how to package and install chutney,
- # so users can find it in $PATH
- echo "$myname: missing 'chutney' in \$CHUTNEY_PATH ($CHUTNEY_PATH)"
- echo "$myname: Get chutney: git clone https://git.torproject.org/\
+ $ECHO "$myname: missing 'chutney' in \$CHUTNEY_PATH ($CHUTNEY_PATH)"
+ $ECHO "$myname: Get chutney: git clone https://git.torproject.org/\
chutney.git"
- echo "$myname: Set \$CHUTNEY_PATH to a non-standard location: export \
+ $ECHO "$myname: Set \$CHUTNEY_PATH to a non-standard location: export \
CHUTNEY_PATH=\`pwd\`/chutney"
unset CHUTNEY_PATH
exit 1
fi
fi
-# When we switch to using test-network.sh in chutney/tools, this comment and
-# everything below it can be removed
-
-# For picking up the right tor binaries.
-# If these varibles aren't set, chutney looks for tor binaries in $PATH
-if [ -d "$TOR_DIR" ]; then
- tor_name=tor
- tor_gencert_name=tor-gencert
- if [ "$USE_COVERAGE_BINARY" = true ]; then
- tor_name=tor-cov
- fi
- export CHUTNEY_TOR="${TOR_DIR}/src/or/${tor_name}"
- export CHUTNEY_TOR_GENCERT="${TOR_DIR}/src/tools/${tor_gencert_name}"
-fi
-
-# Set the variables for the chutney network flavour
-export NETWORK_FLAVOUR=${NETWORK_FLAVOUR:-"bridges+hs"}
-export CHUTNEY_NETWORK=networks/$NETWORK_FLAVOUR
-
-# And finish up if we're doing a dry run
-if [ "$NETWORK_DRY_RUN" = true ]; then
- # we can't exit here, it breaks argument processing
- return
+TEST_NETWORK="$CHUTNEY_PATH/tools/test-network.sh"
+# Call the chutney version of this script, if it exists, and we can find it
+if [ -d "$CHUTNEY_PATH" -a -x "$TEST_NETWORK" ]; then
+ $ECHO "$myname: Calling newer chutney script $TEST_NETWORK"
+ # this may fail if some arguments have spaces in them
+ # if so, set CHUTNEY_PATH before calling test-network.sh, and spaces
+ # will be handled correctly
+ exec "$TEST_NETWORK" $ORIGINAL_ARGS
+else
+ $ECHO "$myname: Could not find tools/test-network.sh in CHUTNEY_PATH."
+ $ECHO "$myname: Please update your chutney using 'git pull'."
+ # We have failed to do what the user asked
+ exit 1
fi
-
-cd "$CHUTNEY_PATH"
-./tools/bootstrap-network.sh $NETWORK_FLAVOUR || exit 2
-
-# Sleep some, waiting for the network to bootstrap.
-# TODO: Add chutney command 'bootstrap-status' and use that instead.
-BOOTSTRAP_TIME=${BOOTSTRAP_TIME:-35}
-$ECHO_N "$myname: sleeping for $BOOTSTRAP_TIME seconds"
-n=$BOOTSTRAP_TIME; while [ $n -gt 0 ]; do
- sleep 1; n=$(expr $n - 1); $ECHO_N .
-done; echo ""
-./chutney verify $CHUTNEY_NETWORK
-VERIFY_EXIT_STATUS=$?
-# work around a bug/feature in make -j2 (or more)
-# where make hangs if any child processes are still alive
-./chutney stop $CHUTNEY_NETWORK
-exit $VERIFY_EXIT_STATUS
diff --git a/src/test/test-timers.c b/src/test/test-timers.c
index b5fcade7f8..99715f4333 100644
--- a/src/test/test-timers.c
+++ b/src/test/test-timers.c
@@ -1,4 +1,4 @@
-/* Copyright 2016, The Tor Project, Inc. */
+/* Copyright 2016-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test.c b/src/test/test.c
index 866408e856..4d2cf1536b 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-2016, The Tor Project, Inc. */
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -44,13 +44,13 @@ double fabs(double x);
#include "buffers.h"
#include "circuitlist.h"
#include "circuitstats.h"
+#include "compress.h"
#include "config.h"
#include "connection_edge.h"
#include "geoip.h"
#include "rendcommon.h"
#include "rendcache.h"
#include "test.h"
-#include "torgzip.h"
#include "main.h"
#include "memarea.h"
#include "onion.h"
@@ -1188,16 +1188,21 @@ struct testgroup_t testgroups[] = {
{ "channel/", channel_tests },
{ "channeltls/", channeltls_tests },
{ "checkdir/", checkdir_tests },
+ { "circuitbuild/", circuitbuild_tests },
{ "circuitlist/", circuitlist_tests },
{ "circuitmux/", circuitmux_tests },
{ "circuituse/", circuituse_tests },
{ "compat/libevent/", compat_libevent_tests },
{ "config/", config_tests },
{ "connection/", connection_tests },
+ { "conscache/", conscache_tests },
+ { "consdiff/", consdiff_tests },
+ { "consdiffmgr/", consdiffmgr_tests },
{ "container/", container_tests },
{ "control/", controller_tests },
{ "control/event/", controller_event_tests },
{ "crypto/", crypto_tests },
+ { "crypto/openssl/", crypto_openssl_tests },
{ "dir/", dir_tests },
{ "dir_handle_get/", dir_handle_get_tests },
{ "dir/md/", microdesc_tests },
@@ -1232,6 +1237,7 @@ struct testgroup_t testgroups[] = {
{ "socks/", socks_tests },
{ "shared-random/", sr_tests },
{ "status/" , status_tests },
+ { "storagedir/", storagedir_tests },
{ "tortls/", tortls_tests },
{ "util/", util_tests },
{ "util/format/", util_format_tests },
diff --git a/src/test/test.h b/src/test/test.h
index 2bd58f51c8..3d7d05e771 100644
--- a/src/test/test.h
+++ b/src/test/test.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2003, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2016, The Tor Project, Inc. */
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_TEST_H
@@ -183,16 +183,21 @@ extern struct testcase_t cell_queue_tests[];
extern struct testcase_t channel_tests[];
extern struct testcase_t channeltls_tests[];
extern struct testcase_t checkdir_tests[];
+extern struct testcase_t circuitbuild_tests[];
extern struct testcase_t circuitlist_tests[];
extern struct testcase_t circuitmux_tests[];
extern struct testcase_t circuituse_tests[];
extern struct testcase_t compat_libevent_tests[];
extern struct testcase_t config_tests[];
extern struct testcase_t connection_tests[];
+extern struct testcase_t conscache_tests[];
+extern struct testcase_t consdiff_tests[];
+extern struct testcase_t consdiffmgr_tests[];
extern struct testcase_t container_tests[];
extern struct testcase_t controller_tests[];
extern struct testcase_t controller_event_tests[];
extern struct testcase_t crypto_tests[];
+extern struct testcase_t crypto_openssl_tests[];
extern struct testcase_t dir_tests[];
extern struct testcase_t dir_handle_get_tests[];
extern struct testcase_t entryconn_tests[];
@@ -227,6 +232,7 @@ extern struct testcase_t routerkeys_tests[];
extern struct testcase_t routerlist_tests[];
extern struct testcase_t routerset_tests[];
extern struct testcase_t scheduler_tests[];
+extern struct testcase_t storagedir_tests[];
extern struct testcase_t socks_tests[];
extern struct testcase_t status_tests[];
extern struct testcase_t thread_tests[];
diff --git a/src/test/test_addr.c b/src/test/test_addr.c
index 49e248014f..b6d2445bad 100644
--- a/src/test/test_addr.c
+++ b/src/test/test_addr.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2016, The Tor Project, Inc. */
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define ADDRESSMAP_PRIVATE
diff --git a/src/test/test_address.c b/src/test/test_address.c
index 0d142ad483..50a0574522 100644
--- a/src/test/test_address.c
+++ b/src/test/test_address.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Tor Project, Inc. */
+/* Copyright (c) 2014-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define ADDRESS_PRIVATE
diff --git a/src/test/test_bt_cl.c b/src/test/test_bt_cl.c
index 709d599f52..ed588ecc5b 100644
--- a/src/test/test_bt_cl.c
+++ b/src/test/test_bt_cl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Tor Project, Inc. */
+/* Copyright (c) 2012-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_buffers.c b/src/test/test_buffers.c
index 9e7bdb8911..07114a8571 100644
--- a/src/test/test_buffers.c
+++ b/src/test/test_buffers.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2016, The Tor Project, Inc. */
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define BUFFERS_PRIVATE
@@ -578,120 +578,150 @@ test_buffer_time_tracking(void *arg)
}
static void
-test_buffers_zlib_impl(int finalize_with_nil)
+test_buffers_compress_fin_at_chunk_end_impl(compress_method_t method,
+ compression_level_t level)
{
char *msg = NULL;
char *contents = NULL;
char *expanded = NULL;
buf_t *buf = NULL;
- tor_zlib_state_t *zlib_state = NULL;
+ tor_compress_state_t *compress_state = NULL;
size_t out_len, in_len;
- int done;
+ size_t sz, headerjunk;
buf = buf_new_with_capacity(128); /* will round up */
- zlib_state = tor_zlib_new(1, ZLIB_METHOD, HIGH_COMPRESSION);
+ sz = buf_get_default_chunk_size(buf);
+ msg = tor_malloc_zero(sz);
- msg = tor_malloc(512);
- crypto_rand(msg, 512);
- tt_int_op(write_to_buf_zlib(buf, zlib_state, msg, 128, 0), OP_EQ, 0);
- tt_int_op(write_to_buf_zlib(buf, zlib_state, msg+128, 128, 0), OP_EQ, 0);
- tt_int_op(write_to_buf_zlib(buf, zlib_state, msg+256, 256, 0), OP_EQ, 0);
- done = !finalize_with_nil;
- tt_int_op(write_to_buf_zlib(buf, zlib_state, "all done", 9, done), OP_EQ, 0);
- if (finalize_with_nil) {
- tt_int_op(write_to_buf_zlib(buf, zlib_state, "", 0, 1), OP_EQ, 0);
- }
+ write_to_buf(msg, 1, buf);
+ tt_assert(buf->head);
+
+ /* Fill up the chunk so the compression stuff won't fit in one chunk. */
+ tt_uint_op(buf->head->memlen, OP_LT, sz);
+ headerjunk = buf->head->memlen - 7;
+ write_to_buf(msg, headerjunk-1, buf);
+ tt_uint_op(buf->head->datalen, OP_EQ, headerjunk);
+ tt_uint_op(buf_datalen(buf), OP_EQ, headerjunk);
+ /* Write an empty string, with finalization on. */
+ compress_state = tor_compress_new(1, method, level);
+ tt_int_op(write_to_buf_compress(buf, compress_state, "", 0, 1), OP_EQ, 0);
in_len = buf_datalen(buf);
contents = tor_malloc(in_len);
tt_int_op(fetch_from_buf(contents, in_len, buf), OP_EQ, 0);
- tt_int_op(0, OP_EQ, tor_gzip_uncompress(&expanded, &out_len,
- contents, in_len,
- ZLIB_METHOD, 1,
- LOG_WARN));
+ if (method == NO_METHOD) {
+ tt_uint_op(in_len, OP_EQ, headerjunk);
+ } else {
+ tt_uint_op(in_len, OP_GT, headerjunk);
+ }
- tt_int_op(out_len, OP_GE, 128);
- tt_mem_op(msg, OP_EQ, expanded, 128);
- tt_int_op(out_len, OP_GE, 512);
- tt_mem_op(msg, OP_EQ, expanded, 512);
- tt_int_op(out_len, OP_EQ, 512+9);
- tt_mem_op("all done", OP_EQ, expanded+512, 9);
+ tt_int_op(0, OP_EQ, tor_uncompress(&expanded, &out_len,
+ contents + headerjunk,
+ in_len - headerjunk,
+ method, 1,
+ LOG_WARN));
+
+ tt_int_op(out_len, OP_EQ, 0);
+ tt_assert(expanded);
done:
buf_free(buf);
- tor_zlib_free(zlib_state);
+ tor_compress_free(compress_state);
tor_free(contents);
tor_free(expanded);
tor_free(msg);
}
static void
-test_buffers_zlib(void *arg)
-{
- (void) arg;
- test_buffers_zlib_impl(0);
-}
-static void
-test_buffers_zlib_fin_with_nil(void *arg)
-{
- (void) arg;
- test_buffers_zlib_impl(1);
-}
-
-static void
-test_buffers_zlib_fin_at_chunk_end(void *arg)
+test_buffers_compress_impl(compress_method_t method,
+ compression_level_t level,
+ int finalize_with_nil)
{
char *msg = NULL;
char *contents = NULL;
char *expanded = NULL;
buf_t *buf = NULL;
- tor_zlib_state_t *zlib_state = NULL;
+ tor_compress_state_t *compress_state = NULL;
size_t out_len, in_len;
- size_t sz, headerjunk;
- (void) arg;
+ int done;
buf = buf_new_with_capacity(128); /* will round up */
- sz = buf_get_default_chunk_size(buf);
- msg = tor_malloc_zero(sz);
-
- write_to_buf(msg, 1, buf);
- tt_assert(buf->head);
+ compress_state = tor_compress_new(1, method, level);
- /* Fill up the chunk so the zlib stuff won't fit in one chunk. */
- tt_uint_op(buf->head->memlen, OP_LT, sz);
- headerjunk = buf->head->memlen - 7;
- write_to_buf(msg, headerjunk-1, buf);
- tt_uint_op(buf->head->datalen, OP_EQ, headerjunk);
- tt_uint_op(buf_datalen(buf), OP_EQ, headerjunk);
- /* Write an empty string, with finalization on. */
- zlib_state = tor_zlib_new(1, ZLIB_METHOD, HIGH_COMPRESSION);
- tt_int_op(write_to_buf_zlib(buf, zlib_state, "", 0, 1), OP_EQ, 0);
+ msg = tor_malloc(512);
+ crypto_rand(msg, 512);
+ tt_int_op(write_to_buf_compress(buf, compress_state,
+ msg, 128, 0), OP_EQ, 0);
+ tt_int_op(write_to_buf_compress(buf, compress_state,
+ msg+128, 128, 0), OP_EQ, 0);
+ tt_int_op(write_to_buf_compress(buf, compress_state,
+ msg+256, 256, 0), OP_EQ, 0);
+ done = !finalize_with_nil;
+ tt_int_op(write_to_buf_compress(buf, compress_state,
+ "all done", 9, done), OP_EQ, 0);
+ if (finalize_with_nil) {
+ tt_int_op(write_to_buf_compress(buf, compress_state, "", 0, 1), OP_EQ, 0);
+ }
in_len = buf_datalen(buf);
contents = tor_malloc(in_len);
tt_int_op(fetch_from_buf(contents, in_len, buf), OP_EQ, 0);
- tt_uint_op(in_len, OP_GT, headerjunk);
-
- tt_int_op(0, OP_EQ, tor_gzip_uncompress(&expanded, &out_len,
- contents + headerjunk, in_len - headerjunk,
- ZLIB_METHOD, 1,
- LOG_WARN));
+ tt_int_op(0, OP_EQ, tor_uncompress(&expanded, &out_len,
+ contents, in_len,
+ method, 1,
+ LOG_WARN));
- tt_int_op(out_len, OP_EQ, 0);
- tt_assert(expanded);
+ tt_int_op(out_len, OP_GE, 128);
+ tt_mem_op(msg, OP_EQ, expanded, 128);
+ tt_int_op(out_len, OP_GE, 512);
+ tt_mem_op(msg, OP_EQ, expanded, 512);
+ tt_int_op(out_len, OP_EQ, 512+9);
+ tt_mem_op("all done", OP_EQ, expanded+512, 9);
done:
buf_free(buf);
- tor_zlib_free(zlib_state);
+ tor_compress_free(compress_state);
tor_free(contents);
tor_free(expanded);
tor_free(msg);
}
+static void
+test_buffers_compress(void *arg)
+{
+ const char *methodname = arg;
+ tt_assert(methodname);
+
+ compress_method_t method = compression_method_get_by_name(methodname);
+ tt_int_op(method, OP_NE, UNKNOWN_METHOD);
+
+ if (! tor_compress_supports_method(method)) {
+ tt_skip();
+ }
+
+ compression_level_t levels[] = {
+ BEST_COMPRESSION,
+ HIGH_COMPRESSION,
+ MEDIUM_COMPRESSION,
+ LOW_COMPRESSION
+ };
+
+ for (unsigned l = 0; l < ARRAY_LENGTH(levels); ++l) {
+ compression_level_t level = levels[l];
+
+ test_buffers_compress_impl(method, level, 0);
+ test_buffers_compress_impl(method, level, 1);
+ test_buffers_compress_fin_at_chunk_end_impl(method, level);
+ }
+
+ done:
+ ;
+}
+
static const uint8_t *tls_read_ptr;
static int n_remaining;
static int next_reply_val[16];
@@ -816,14 +846,22 @@ struct testcase_t buffer_tests[] = {
{ "allocation_tracking", test_buffer_allocation_tracking, TT_FORK,
NULL, NULL },
{ "time_tracking", test_buffer_time_tracking, TT_FORK, NULL, NULL },
- { "zlib", test_buffers_zlib, TT_FORK, NULL, NULL },
- { "zlib_fin_with_nil", test_buffers_zlib_fin_with_nil, TT_FORK, NULL, NULL },
- { "zlib_fin_at_chunk_end", test_buffers_zlib_fin_at_chunk_end, TT_FORK,
- NULL, NULL},
{ "tls_read_mocked", test_buffers_tls_read_mocked, 0,
NULL, NULL },
{ "chunk_size", test_buffers_chunk_size, 0, NULL, NULL },
{ "find_contentlen", test_buffers_find_contentlen, 0, NULL, NULL },
+
+ { "compress/zlib", test_buffers_compress, TT_FORK,
+ &passthrough_setup, (char*)"deflate" },
+ { "compress/gzip", test_buffers_compress, TT_FORK,
+ &passthrough_setup, (char*)"gzip" },
+ { "compress/zstd", test_buffers_compress, TT_FORK,
+ &passthrough_setup, (char*)"x-zstd" },
+ { "compress/lzma", test_buffers_compress, TT_FORK,
+ &passthrough_setup, (char*)"x-tor-lzma" },
+ { "compress/none", test_buffers_compress, TT_FORK,
+ &passthrough_setup, (char*)"identity" },
+
END_OF_TESTCASES
};
diff --git a/src/test/test_cell_formats.c b/src/test/test_cell_formats.c
index 22c34b6d6c..007f7e3d3e 100644
--- a/src/test/test_cell_formats.c
+++ b/src/test/test_cell_formats.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2016, The Tor Project, Inc. */
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_cell_queue.c b/src/test/test_cell_queue.c
index 93ac9854d8..69e89b69b0 100644
--- a/src/test/test_cell_queue.c
+++ b/src/test/test_cell_queue.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2016, The Tor Project, Inc. */
+/* Copyright (c) 2013-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CIRCUITLIST_PRIVATE
diff --git a/src/test/test_channel.c b/src/test/test_channel.c
index 862bd6dfa6..f5999b8e67 100644
--- a/src/test/test_channel.c
+++ b/src/test/test_channel.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2016, The Tor Project, Inc. */
+/* Copyright (c) 2013-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define TOR_CHANNEL_INTERNAL_
diff --git a/src/test/test_channeltls.c b/src/test/test_channeltls.c
index fd98ee40fb..96c5eba9a5 100644
--- a/src/test/test_channeltls.c
+++ b/src/test/test_channeltls.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Tor Project, Inc. */
+/* Copyright (c) 2014-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_checkdir.c b/src/test/test_checkdir.c
index fbb33f87f6..38f3360b61 100644
--- a/src/test/test_checkdir.c
+++ b/src/test/test_checkdir.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Tor Project, Inc. */
+/* Copyright (c) 2014-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_circuitbuild.c b/src/test/test_circuitbuild.c
new file mode 100644
index 0000000000..a5282df69d
--- /dev/null
+++ b/src/test/test_circuitbuild.c
@@ -0,0 +1,133 @@
+/* Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2016, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#define CIRCUITBUILD_PRIVATE
+
+#include "or.h"
+#include "test.h"
+#include "test_helpers.h"
+#include "log_test_helpers.h"
+#include "config.h"
+#include "circuitbuild.h"
+
+/* Dummy nodes smartlist for testing */
+static smartlist_t dummy_nodes;
+/* Dummy exit extend_info for testing */
+static extend_info_t dummy_ei;
+
+static int
+mock_count_acceptable_nodes(smartlist_t *nodes)
+{
+ (void)nodes;
+
+ return DEFAULT_ROUTE_LEN + 1;
+}
+
+/* Test route lengths when the caller of new_route_len() doesn't
+ * specify exit_ei. */
+static void
+test_new_route_len_noexit(void *arg)
+{
+ int r;
+
+ (void)arg;
+ MOCK(count_acceptable_nodes, mock_count_acceptable_nodes);
+
+ r = new_route_len(CIRCUIT_PURPOSE_C_GENERAL, NULL, &dummy_nodes);
+ tt_int_op(DEFAULT_ROUTE_LEN, OP_EQ, r);
+
+ r = new_route_len(CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT, NULL, &dummy_nodes);
+ tt_int_op(DEFAULT_ROUTE_LEN, OP_EQ, r);
+
+ r = new_route_len(CIRCUIT_PURPOSE_S_CONNECT_REND, NULL, &dummy_nodes);
+ tt_int_op(DEFAULT_ROUTE_LEN, OP_EQ, r);
+
+ done:
+ UNMOCK(count_acceptable_nodes);
+}
+
+/* Test route lengths where someone else chose the "exit" node, which
+ * require an extra hop for safety. */
+static void
+test_new_route_len_unsafe_exit(void *arg)
+{
+ int r;
+
+ (void)arg;
+ MOCK(count_acceptable_nodes, mock_count_acceptable_nodes);
+
+ /* connecting to hidden service directory */
+ r = new_route_len(CIRCUIT_PURPOSE_C_GENERAL, &dummy_ei, &dummy_nodes);
+ tt_int_op(DEFAULT_ROUTE_LEN + 1, OP_EQ, r);
+
+ /* client connecting to introduction point */
+ r = new_route_len(CIRCUIT_PURPOSE_C_INTRODUCING, &dummy_ei, &dummy_nodes);
+ tt_int_op(DEFAULT_ROUTE_LEN + 1, OP_EQ, r);
+
+ /* hidden service connecting to rendezvous point */
+ r = new_route_len(CIRCUIT_PURPOSE_S_CONNECT_REND, &dummy_ei, &dummy_nodes);
+ tt_int_op(DEFAULT_ROUTE_LEN + 1, OP_EQ, r);
+
+ done:
+ UNMOCK(count_acceptable_nodes);
+}
+
+/* Test route lengths where we chose the "exit" node, which don't
+ * require an extra hop for safety. */
+static void
+test_new_route_len_safe_exit(void *arg)
+{
+ int r;
+
+ (void)arg;
+ MOCK(count_acceptable_nodes, mock_count_acceptable_nodes);
+
+ /* hidden service connecting to introduction point */
+ r = new_route_len(CIRCUIT_PURPOSE_S_ESTABLISH_INTRO, &dummy_ei,
+ &dummy_nodes);
+ tt_int_op(DEFAULT_ROUTE_LEN, OP_EQ, r);
+
+ /* router testing its own reachability */
+ r = new_route_len(CIRCUIT_PURPOSE_TESTING, &dummy_ei, &dummy_nodes);
+ tt_int_op(DEFAULT_ROUTE_LEN, OP_EQ, r);
+
+ done:
+ UNMOCK(count_acceptable_nodes);
+}
+
+/* Make sure a non-fatal assertion fails when new_route_len() gets an
+ * unexpected circuit purpose. */
+static void
+test_new_route_len_unhandled_exit(void *arg)
+{
+ int r;
+
+ (void)arg;
+ MOCK(count_acceptable_nodes, mock_count_acceptable_nodes);
+
+ tor_capture_bugs_(1);
+ setup_full_capture_of_logs(LOG_WARN);
+ r = new_route_len(CIRCUIT_PURPOSE_CONTROLLER, &dummy_ei, &dummy_nodes);
+ tt_int_op(DEFAULT_ROUTE_LEN + 1, OP_EQ, r);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1);
+ tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ,
+ "!(exit_ei && !known_purpose)");
+ expect_single_log_msg_containing("Unhandled purpose");
+ expect_single_log_msg_containing("with a chosen exit; assuming routelen");
+ teardown_capture_of_logs();
+ tor_end_capture_bugs_();
+
+ done:
+ UNMOCK(count_acceptable_nodes);
+}
+
+struct testcase_t circuitbuild_tests[] = {
+ { "noexit", test_new_route_len_noexit, 0, NULL, NULL },
+ { "safe_exit", test_new_route_len_safe_exit, 0, NULL, NULL },
+ { "unsafe_exit", test_new_route_len_unsafe_exit, 0, NULL, NULL },
+ { "unhandled_exit", test_new_route_len_unhandled_exit, 0, NULL, NULL },
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_circuitlist.c b/src/test/test_circuitlist.c
index 7eed5fe225..344ab27921 100644
--- a/src/test/test_circuitlist.c
+++ b/src/test/test_circuitlist.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2016, The Tor Project, Inc. */
+/* Copyright (c) 2013-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define TOR_CHANNEL_INTERNAL_
@@ -201,68 +201,68 @@ test_rend_token_maps(void *arg)
tt_int_op(tok3[REND_TOKEN_LEN-1], OP_EQ, '.');
/* No maps; nothing there. */
- tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ(tok1));
- tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok1));
+ tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok1));
+ tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok1));
- hs_circuitmap_register_rend_circ(c1, tok1);
- hs_circuitmap_register_intro_circ_v2(c2, tok2);
+ hs_circuitmap_register_rend_circ_relay_side(c1, tok1);
+ hs_circuitmap_register_intro_circ_v2_relay_side(c2, tok2);
- tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ(tok3));
- tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok3));
- tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ(tok2));
- tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok1));
+ tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok3));
+ tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok3));
+ tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok2));
+ tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok1));
/* Without purpose set, we don't get the circuits */
- tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ(tok1));
- tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok2));
+ tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok1));
+ tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok2));
c1->base_.purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING;
c2->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT;
/* Okay, make sure they show up now. */
- tt_ptr_op(c1, OP_EQ, hs_circuitmap_get_rend_circ(tok1));
- tt_ptr_op(c2, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok2));
+ tt_ptr_op(c1, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok1));
+ tt_ptr_op(c2, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok2));
/* Two items at the same place with the same token. */
c3->base_.purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING;
- hs_circuitmap_register_rend_circ(c3, tok2);
- tt_ptr_op(c2, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok2));
- tt_ptr_op(c3, OP_EQ, hs_circuitmap_get_rend_circ(tok2));
+ hs_circuitmap_register_rend_circ_relay_side(c3, tok2);
+ tt_ptr_op(c2, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok2));
+ tt_ptr_op(c3, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok2));
/* Marking a circuit makes it not get returned any more */
circuit_mark_for_close(TO_CIRCUIT(c1), END_CIRC_REASON_FINISHED);
- tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ(tok1));
+ tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok1));
circuit_free(TO_CIRCUIT(c1));
c1 = NULL;
/* Freeing a circuit makes it not get returned any more. */
circuit_free(TO_CIRCUIT(c2));
c2 = NULL;
- tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok2));
+ tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok2));
/* c3 -- are you still there? */
- tt_ptr_op(c3, OP_EQ, hs_circuitmap_get_rend_circ(tok2));
+ tt_ptr_op(c3, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok2));
/* Change its cookie. This never happens in Tor per se, but hey. */
c3->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT;
- hs_circuitmap_register_intro_circ_v2(c3, tok3);
+ hs_circuitmap_register_intro_circ_v2_relay_side(c3, tok3);
- tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ(tok2));
- tt_ptr_op(c3, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok3));
+ tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok2));
+ tt_ptr_op(c3, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok3));
/* Now replace c3 with c4. */
c4->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT;
- hs_circuitmap_register_intro_circ_v2(c4, tok3);
+ hs_circuitmap_register_intro_circ_v2_relay_side(c4, tok3);
- tt_ptr_op(c4, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok3));
+ tt_ptr_op(c4, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok3));
- tt_ptr_op(c3->hs_token, OP_EQ, NULL);
- tt_ptr_op(c4->hs_token, OP_NE, NULL);
- tt_mem_op(c4->hs_token->token, OP_EQ, tok3, REND_TOKEN_LEN);
+ tt_ptr_op(TO_CIRCUIT(c3)->hs_token, OP_EQ, NULL);
+ tt_ptr_op(TO_CIRCUIT(c4)->hs_token, OP_NE, NULL);
+ tt_mem_op(TO_CIRCUIT(c4)->hs_token->token, OP_EQ, tok3, REND_TOKEN_LEN);
/* Now clear c4's cookie. */
- hs_circuitmap_remove_circuit(c4);
- tt_ptr_op(c4->hs_token, OP_EQ, NULL);
- tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok3));
+ hs_circuitmap_remove_circuit(TO_CIRCUIT(c4));
+ tt_ptr_op(TO_CIRCUIT(c4)->hs_token, OP_EQ, NULL);
+ tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok3));
done:
if (c1)
@@ -370,10 +370,89 @@ test_pick_circid(void *arg)
UNMOCK(channel_dump_statistics);
}
+/** Test that the circuit pools of our HS circuitmap are isolated based on
+ * their token type. */
+static void
+test_hs_circuitmap_isolation(void *arg)
+{
+ or_circuit_t *circ1 = NULL;
+ origin_circuit_t *circ2 = NULL;
+ or_circuit_t *circ3 = NULL;
+ origin_circuit_t *circ4 = NULL;
+
+ (void)arg;
+
+ hs_circuitmap_init();
+
+ {
+ const uint8_t tok1[REND_TOKEN_LEN] = "bet i got some of th";
+
+ circ1 = or_circuit_new(0, NULL);
+ tt_assert(circ1);
+ circ1->base_.purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING;
+
+ /* check that circuitmap is empty right? */
+ tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok1));
+
+ /* Register circ1 with tok1 as relay-side rend circ */
+ hs_circuitmap_register_rend_circ_relay_side(circ1, tok1);
+
+ /* check that service-side getters don't work */
+ tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ_service_side(tok1));
+ tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2_service_side(tok1));
+
+ /* Check that the right getter works. */
+ tt_ptr_op(circ1, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok1));
+ }
+
+ {
+ const uint8_t tok2[REND_TOKEN_LEN] = "you dont know anythi";
+
+ circ2 = origin_circuit_new();
+ tt_assert(circ2);
+ circ2->base_.purpose = CIRCUIT_PURPOSE_S_ESTABLISH_INTRO;
+ circ3 = or_circuit_new(0, NULL);
+ tt_assert(circ3);
+ circ3->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT;
+ circ4 = origin_circuit_new();
+ tt_assert(circ4);
+ circ4->base_.purpose = CIRCUIT_PURPOSE_S_ESTABLISH_INTRO;
+
+ /* Register circ2 with tok2 as service-side intro v2 circ */
+ hs_circuitmap_register_intro_circ_v2_service_side(circ2, tok2);
+ /* Register circ3 with tok2 again but for different purpose */
+ hs_circuitmap_register_intro_circ_v2_relay_side(circ3, tok2);
+
+ /* Check that the getters work */
+ tt_ptr_op(circ2, OP_EQ,
+ hs_circuitmap_get_intro_circ_v2_service_side(tok2));
+ tt_ptr_op(circ3, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok2));
+
+ /* Register circ4 with tok2: it should override circ2 */
+ hs_circuitmap_register_intro_circ_v2_service_side(circ4, tok2);
+
+ /* check that relay-side getters don't work */
+ tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok2));
+
+ /* Check that the getter returns circ4; the last circuit registered with
+ * that token. */
+ tt_ptr_op(circ4, OP_EQ,
+ hs_circuitmap_get_intro_circ_v2_service_side(tok2));
+ }
+
+ done:
+ circuit_free(TO_CIRCUIT(circ1));
+ circuit_free(TO_CIRCUIT(circ2));
+ circuit_free(TO_CIRCUIT(circ3));
+ circuit_free(TO_CIRCUIT(circ4));
+}
+
struct testcase_t circuitlist_tests[] = {
{ "maps", test_clist_maps, TT_FORK, NULL, NULL },
{ "rend_token_maps", test_rend_token_maps, TT_FORK, NULL, NULL },
{ "pick_circid", test_pick_circid, TT_FORK, NULL, NULL },
+ { "hs_circuitmap_isolation", test_hs_circuitmap_isolation,
+ TT_FORK, NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_circuitmux.c b/src/test/test_circuitmux.c
index 9e8fb54964..779783299d 100644
--- a/src/test/test_circuitmux.c
+++ b/src/test/test_circuitmux.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2016, The Tor Project, Inc. */
+/* Copyright (c) 2013-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define TOR_CHANNEL_INTERNAL_
diff --git a/src/test/test_circuituse.c b/src/test/test_circuituse.c
index 27a87660ff..5cc9fe571e 100644
--- a/src/test/test_circuituse.c
+++ b/src/test/test_circuituse.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2016, The Tor Project, Inc. */
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CIRCUITLIST_PRIVATE
diff --git a/src/test/test_compat_libevent.c b/src/test/test_compat_libevent.c
index 0443cc0b1c..7dd8e65194 100644
--- a/src/test/test_compat_libevent.c
+++ b/src/test/test_compat_libevent.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2016, The Tor Project, Inc. */
+/* Copyright (c) 2010-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define COMPAT_LIBEVENT_PRIVATE
diff --git a/src/test/test_config.c b/src/test/test_config.c
index 3b19cad036..f0874e0e0b 100644
--- a/src/test/test_config.c
+++ b/src/test/test_config.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2016, The Tor Project, Inc. */
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_connection.c b/src/test/test_connection.c
index 5cda4f3175..7e5193b203 100644
--- a/src/test/test_connection.c
+++ b/src/test/test_connection.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Tor Project, Inc. */
+/* Copyright (c) 2015-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -265,7 +265,7 @@ test_conn_get_rend_setup(const struct testcase_t *tc)
rend_cache_init();
- /* TODO: use directory_initiate_command_rend() to do this - maybe? */
+ /* TODO: use directory_initiate_request() to do this - maybe? */
tor_assert(strlen(TEST_CONN_REND_ADDR) == REND_SERVICE_ID_LEN_BASE32);
conn->rend_data = rend_data_client_create(TEST_CONN_REND_ADDR, NULL, NULL,
REND_NO_AUTH);
diff --git a/src/test/test_conscache.c b/src/test/test_conscache.c
new file mode 100644
index 0000000000..aee1ba8a06
--- /dev/null
+++ b/src/test/test_conscache.c
@@ -0,0 +1,340 @@
+/* Copyright (c) 2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "or.h"
+#include "config.h"
+#include "conscache.h"
+#include "test.h"
+
+#ifdef HAVE_UTIME_H
+#include <utime.h>
+#endif
+
+static void
+test_conscache_open_failure(void *arg)
+{
+ (void) arg;
+ /* Try opening a directory that doesn't exist and which we shouldn't be
+ * able to create. */
+ consensus_cache_t *cache = consensus_cache_open("a/b/c/d/e/f/g", 128);
+ tt_ptr_op(cache, OP_EQ, NULL);
+
+ done:
+ ;
+}
+
+static void
+test_conscache_simple_usage(void *arg)
+{
+ (void)arg;
+ consensus_cache_entry_t *ent = NULL, *ent2 = NULL;
+
+ /* Make a temporary datadir for these tests */
+ char *ddir_fname = tor_strdup(get_fname_rnd("datadir_cache"));
+ tor_free(get_options_mutable()->DataDirectory);
+ get_options_mutable()->DataDirectory = tor_strdup(ddir_fname);
+ check_private_dir(ddir_fname, CPD_CREATE, NULL);
+ consensus_cache_t *cache = consensus_cache_open("cons", 128);
+
+ tt_assert(cache);
+
+ /* Create object; make sure it exists. */
+ config_line_t *labels = NULL;
+ config_line_append(&labels, "Hello", "world");
+ config_line_append(&labels, "Adios", "planetas");
+ ent = consensus_cache_add(cache,
+ labels, (const uint8_t *)"A\0B\0C", 5);
+ config_free_lines(labels);
+ labels = NULL;
+ tt_assert(ent);
+
+ /* Make a second object */
+ config_line_append(&labels, "Hello", "mundo");
+ config_line_append(&labels, "Adios", "planets");
+ ent2 = consensus_cache_add(cache,
+ labels, (const uint8_t *)"xyzzy", 5);
+ config_free_lines(labels);
+ labels = NULL;
+ tt_assert(ent2);
+ tt_assert(! consensus_cache_entry_is_mapped(ent2));
+ consensus_cache_entry_decref(ent2);
+ ent2 = NULL;
+
+ /* Check get_value */
+ tt_ptr_op(NULL, OP_EQ, consensus_cache_entry_get_value(ent, "hebbo"));
+ tt_str_op("world", OP_EQ, consensus_cache_entry_get_value(ent, "Hello"));
+
+ /* Check find_first */
+ ent2 = consensus_cache_find_first(cache, "Hello", "world!");
+ tt_ptr_op(ent2, OP_EQ, NULL);
+ ent2 = consensus_cache_find_first(cache, "Hello", "world");
+ tt_ptr_op(ent2, OP_EQ, ent);
+ ent2 = consensus_cache_find_first(cache, "Hello", "mundo");
+ tt_ptr_op(ent2, OP_NE, ent);
+
+ tt_assert(! consensus_cache_entry_is_mapped(ent));
+
+ /* Check get_body */
+ const uint8_t *bp = NULL;
+ size_t sz = 0;
+ int r = consensus_cache_entry_get_body(ent, &bp, &sz);
+ tt_int_op(r, OP_EQ, 0);
+ tt_u64_op(sz, OP_EQ, 5);
+ tt_mem_op(bp, OP_EQ, "A\0B\0C", 5);
+ tt_assert(consensus_cache_entry_is_mapped(ent));
+
+ /* Free and re-create the cache, to rescan the directory. */
+ consensus_cache_free(cache);
+ consensus_cache_entry_decref(ent);
+ cache = consensus_cache_open("cons", 128);
+
+ /* Make sure the entry is still there */
+ ent = consensus_cache_find_first(cache, "Hello", "mundo");
+ tt_assert(ent);
+ ent2 = consensus_cache_find_first(cache, "Adios", "planets");
+ tt_ptr_op(ent, OP_EQ, ent2);
+ consensus_cache_entry_incref(ent);
+ tt_assert(! consensus_cache_entry_is_mapped(ent));
+ r = consensus_cache_entry_get_body(ent, &bp, &sz);
+ tt_int_op(r, OP_EQ, 0);
+ tt_u64_op(sz, OP_EQ, 5);
+ tt_mem_op(bp, OP_EQ, "xyzzy", 5);
+ tt_assert(consensus_cache_entry_is_mapped(ent));
+
+ /* There should be two entries total. */
+ smartlist_t *entries = smartlist_new();
+ consensus_cache_find_all(entries, cache, NULL, NULL);
+ int n = smartlist_len(entries);
+ smartlist_free(entries);
+ tt_int_op(n, OP_EQ, 2);
+
+ done:
+ consensus_cache_entry_decref(ent);
+ tor_free(ddir_fname);
+ consensus_cache_free(cache);
+}
+
+static void
+test_conscache_cleanup(void *arg)
+{
+ (void)arg;
+ const int N = 20;
+ consensus_cache_entry_t **ents =
+ tor_calloc(N, sizeof(consensus_cache_entry_t*));
+
+ /* Make a temporary datadir for these tests */
+ char *ddir_fname = tor_strdup(get_fname_rnd("datadir_cache"));
+ tor_free(get_options_mutable()->DataDirectory);
+ get_options_mutable()->DataDirectory = tor_strdup(ddir_fname);
+ check_private_dir(ddir_fname, CPD_CREATE, NULL);
+ consensus_cache_t *cache = consensus_cache_open("cons", 128);
+
+ tt_assert(cache);
+
+ /* Create a bunch of entries. */
+ int i;
+ for (i = 0; i < N; ++i) {
+ config_line_t *labels = NULL;
+ char num[8];
+ tor_snprintf(num, sizeof(num), "%d", i);
+ config_line_append(&labels, "test-id", "cleanup");
+ config_line_append(&labels, "index", num);
+ size_t bodylen = i * 3;
+ uint8_t *body = tor_malloc(bodylen);
+ memset(body, i, bodylen);
+ ents[i] = consensus_cache_add(cache, labels, body, bodylen);
+ tor_free(body);
+ config_free_lines(labels);
+ tt_assert(ents[i]);
+ /* We're still holding a reference to each entry at this point. */
+ }
+
+ /* Page all of the entries into RAM */
+ for (i = 0; i < N; ++i) {
+ const uint8_t *bp;
+ size_t sz;
+ tt_assert(! consensus_cache_entry_is_mapped(ents[i]));
+ consensus_cache_entry_get_body(ents[i], &bp, &sz);
+ tt_assert(consensus_cache_entry_is_mapped(ents[i]));
+ }
+
+ /* Mark some of the entries as deletable. */
+ for (i = 7; i < N; i += 7) {
+ consensus_cache_entry_mark_for_removal(ents[i]);
+ tt_assert(consensus_cache_entry_is_mapped(ents[i]));
+ }
+
+ /* Mark some of the entries as aggressively unpaged. */
+ for (i = 3; i < N; i += 3) {
+ consensus_cache_entry_mark_for_aggressive_release(ents[i]);
+ tt_assert(consensus_cache_entry_is_mapped(ents[i]));
+ }
+
+ /* Incref some of the entries again */
+ for (i = 0; i < N; i += 2) {
+ consensus_cache_entry_incref(ents[i]);
+ }
+
+ /* Now we're going to decref everything. We do so at a specific time. I'm
+ * picking the moment when I was writing this test, at 2017-04-05 12:16:48
+ * UTC. */
+ const time_t example_time = 1491394608;
+ update_approx_time(example_time);
+ for (i = 0; i < N; ++i) {
+ consensus_cache_entry_decref(ents[i]);
+ if (i % 2) {
+ ents[i] = NULL; /* We're no longer holding any reference here. */
+ }
+ }
+
+ /* At this point, the aggressively-released items with refcount 1 should
+ * be unmapped. Nothing should be deleted. */
+ consensus_cache_entry_t *e_tmp;
+ e_tmp = consensus_cache_find_first(cache, "index", "3");
+ tt_assert(e_tmp);
+ tt_assert(! consensus_cache_entry_is_mapped(e_tmp));
+ e_tmp = consensus_cache_find_first(cache, "index", "5");
+ tt_assert(e_tmp);
+ tt_assert(consensus_cache_entry_is_mapped(e_tmp));
+ e_tmp = consensus_cache_find_first(cache, "index", "6");
+ tt_assert(e_tmp);
+ tt_assert(consensus_cache_entry_is_mapped(e_tmp));
+ e_tmp = consensus_cache_find_first(cache, "index", "7");
+ tt_assert(e_tmp == NULL); // not found because pending deletion.
+
+ /* Delete the pending-deletion items. */
+ consensus_cache_delete_pending(cache, 0);
+ {
+ smartlist_t *entries = smartlist_new();
+ consensus_cache_find_all(entries, cache, NULL, NULL);
+ int n = smartlist_len(entries);
+ smartlist_free(entries);
+ tt_int_op(n, OP_EQ, 20 - 2); /* 1 entry was deleted; 1 is not-found. */
+ }
+ e_tmp = consensus_cache_find_first(cache, "index", "7"); // refcnt == 1...
+ tt_assert(e_tmp == NULL); // so deleted.
+ e_tmp = consensus_cache_find_first(cache, "index", "14"); // refcnt == 2
+ tt_assert(e_tmp == NULL); // not deleted; but not found.
+
+ /* Now do lazy unmapping. */
+ // should do nothing.
+ consensus_cache_unmap_lazy(cache, example_time - 10);
+ e_tmp = consensus_cache_find_first(cache, "index", "11");
+ tt_assert(e_tmp);
+ tt_assert(consensus_cache_entry_is_mapped(e_tmp));
+ // should actually unmap
+ consensus_cache_unmap_lazy(cache, example_time + 10);
+ e_tmp = consensus_cache_find_first(cache, "index", "11");
+ tt_assert(e_tmp);
+ tt_assert(! consensus_cache_entry_is_mapped(e_tmp));
+ // This one will still be mapped, since it has a reference.
+ e_tmp = consensus_cache_find_first(cache, "index", "16");
+ tt_assert(e_tmp);
+ tt_assert(consensus_cache_entry_is_mapped(e_tmp));
+
+ for (i = 0; i < N; ++i) {
+ consensus_cache_entry_decref(ents[i]);
+ ents[i] = NULL;
+ }
+
+ /* Free and re-create the cache, to rescan the directory. Make sure the
+ * deleted thing is still deleted, along with the other deleted thing. */
+ consensus_cache_free(cache);
+ cache = consensus_cache_open("cons", 128);
+ {
+ smartlist_t *entries = smartlist_new();
+ consensus_cache_find_all(entries, cache, NULL, NULL);
+ int n = smartlist_len(entries);
+ smartlist_free(entries);
+ tt_int_op(n, OP_EQ, 18);
+ }
+
+ done:
+ for (i = 0; i < N; ++i) {
+ consensus_cache_entry_decref(ents[i]);
+ }
+ tor_free(ents);
+ tor_free(ddir_fname);
+ consensus_cache_free(cache);
+}
+
+static void
+test_conscache_filter(void *arg)
+{
+ (void)arg;
+ const int N = 30;
+ smartlist_t *lst = NULL;
+
+ /* Make a temporary datadir for these tests */
+ char *ddir_fname = tor_strdup(get_fname_rnd("datadir_cache"));
+ tor_free(get_options_mutable()->DataDirectory);
+ get_options_mutable()->DataDirectory = tor_strdup(ddir_fname);
+ check_private_dir(ddir_fname, CPD_CREATE, NULL);
+ consensus_cache_t *cache = consensus_cache_open("cons", 128);
+
+ tt_assert(cache);
+
+ /* Create a bunch of entries with different labels */
+ int i;
+ for (i = 0; i < N; ++i) {
+ config_line_t *labels = NULL;
+ char num[8];
+ tor_snprintf(num, sizeof(num), "%d", i);
+ config_line_append(&labels, "test-id", "filter");
+ config_line_append(&labels, "index", num);
+ tor_snprintf(num, sizeof(num), "%d", i % 3);
+ config_line_append(&labels, "mod3", num);
+ tor_snprintf(num, sizeof(num), "%d", i % 5);
+ config_line_append(&labels, "mod5", num);
+
+ size_t bodylen = i * 3;
+ uint8_t *body = tor_malloc(bodylen);
+ memset(body, i, bodylen);
+ consensus_cache_entry_t *ent =
+ consensus_cache_add(cache, labels, body, bodylen);
+ tor_free(body);
+ config_free_lines(labels);
+ tt_assert(ent);
+ consensus_cache_entry_decref(ent);
+ }
+
+ lst = smartlist_new();
+ /* Find nothing. */
+ consensus_cache_find_all(lst, cache, "mod5", "5");
+ tt_int_op(smartlist_len(lst), OP_EQ, 0);
+ /* Find everything. */
+ consensus_cache_find_all(lst, cache, "test-id", "filter");
+ tt_int_op(smartlist_len(lst), OP_EQ, N);
+
+ /* Now filter to find the entries that have i%3 == 1 */
+ consensus_cache_filter_list(lst, "mod3", "1");
+ tt_int_op(smartlist_len(lst), OP_EQ, 10);
+ /* Now filter to find the entries that also have i%5 == 3 */
+ consensus_cache_filter_list(lst, "mod5", "3");
+ tt_int_op(smartlist_len(lst), OP_EQ, 2);
+ /* So now we have those entries for which i%15 == 13. */
+
+ consensus_cache_entry_t *ent1 = smartlist_get(lst, 0);
+ consensus_cache_entry_t *ent2 = smartlist_get(lst, 1);
+ const char *idx1 = consensus_cache_entry_get_value(ent1, "index");
+ const char *idx2 = consensus_cache_entry_get_value(ent2, "index");
+ tt_assert( (!strcmp(idx1, "28") && !strcmp(idx2, "13")) ||
+ (!strcmp(idx1, "13") && !strcmp(idx2, "28")) );
+
+ done:
+ tor_free(ddir_fname);
+ consensus_cache_free(cache);
+ smartlist_free(lst);
+}
+
+#define ENT(name) \
+ { #name, test_conscache_ ## name, TT_FORK, NULL, NULL }
+
+struct testcase_t conscache_tests[] = {
+ ENT(open_failure),
+ ENT(simple_usage),
+ ENT(cleanup),
+ ENT(filter),
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_consdiff.c b/src/test/test_consdiff.c
new file mode 100644
index 0000000000..2f826b5ef7
--- /dev/null
+++ b/src/test/test_consdiff.c
@@ -0,0 +1,1168 @@
+/* Copyright (c) 2014, Daniel Martí
+ * Copyright (c) 2014, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#define CONSDIFF_PRIVATE
+
+#include "or.h"
+#include "test.h"
+
+#include "consdiff.h"
+#include "memarea.h"
+#include "log_test_helpers.h"
+
+#define tt_str_eq_line(a,b) \
+ tt_assert(line_str_eq((b),(a)))
+
+static void
+test_consdiff_smartlist_slice(void *arg)
+{
+ smartlist_t *sl = smartlist_new();
+ smartlist_slice_t *sls;
+
+ /* Create a regular smartlist. */
+ (void)arg;
+ smartlist_add(sl, (void*)1);
+ smartlist_add(sl, (void*)2);
+ smartlist_add(sl, (void*)3);
+ smartlist_add(sl, (void*)4);
+ smartlist_add(sl, (void*)5);
+
+ /* See if the slice was done correctly. */
+ sls = smartlist_slice(sl, 2, 5);
+ tt_ptr_op(sl, OP_EQ, sls->list);
+ tt_ptr_op((void*)3, OP_EQ, smartlist_get(sls->list, sls->offset));
+ tt_ptr_op((void*)5, OP_EQ,
+ smartlist_get(sls->list, sls->offset + (sls->len-1)));
+ tor_free(sls);
+
+ /* See that using -1 as the end does get to the last element. */
+ sls = smartlist_slice(sl, 2, -1);
+ tt_ptr_op(sl, OP_EQ, sls->list);
+ tt_ptr_op((void*)3, OP_EQ, smartlist_get(sls->list, sls->offset));
+ tt_ptr_op((void*)5, OP_EQ,
+ smartlist_get(sls->list, sls->offset + (sls->len-1)));
+
+ done:
+ tor_free(sls);
+ smartlist_free(sl);
+}
+
+static void
+test_consdiff_smartlist_slice_string_pos(void *arg)
+{
+ smartlist_t *sl = smartlist_new();
+ smartlist_slice_t *sls;
+ memarea_t *area = memarea_new();
+
+ /* Create a regular smartlist. */
+ (void)arg;
+ consensus_split_lines(sl, "a\nd\nc\na\nb\n", area);
+
+ /* See that smartlist_slice_string_pos respects the bounds of the slice. */
+ sls = smartlist_slice(sl, 2, 5);
+ cdline_t a_line = { "a", 1 };
+ tt_int_op(3, OP_EQ, smartlist_slice_string_pos(sls, &a_line));
+ cdline_t d_line = { "d", 1 };
+ tt_int_op(-1, OP_EQ, smartlist_slice_string_pos(sls, &d_line));
+
+ done:
+ tor_free(sls);
+ smartlist_free(sl);
+ memarea_drop_all(area);
+}
+
+static void
+test_consdiff_lcs_lengths(void *arg)
+{
+ smartlist_t *sl1 = smartlist_new();
+ smartlist_t *sl2 = smartlist_new();
+ smartlist_slice_t *sls1, *sls2;
+ int *lengths1, *lengths2;
+ memarea_t *area = memarea_new();
+
+ /* Expected lcs lengths in regular and reverse order. */
+ int e_lengths1[] = { 0, 1, 2, 3, 3, 4 };
+ int e_lengths2[] = { 0, 1, 1, 2, 3, 4 };
+
+ (void)arg;
+ consensus_split_lines(sl1, "a\nb\nc\nd\ne\n", area);
+ consensus_split_lines(sl2, "a\nc\nd\ni\ne\n", area);
+
+ sls1 = smartlist_slice(sl1, 0, -1);
+ sls2 = smartlist_slice(sl2, 0, -1);
+
+ lengths1 = lcs_lengths(sls1, sls2, 1);
+ lengths2 = lcs_lengths(sls1, sls2, -1);
+ tt_mem_op(e_lengths1, OP_EQ, lengths1, sizeof(int) * 6);
+ tt_mem_op(e_lengths2, OP_EQ, lengths2, sizeof(int) * 6);
+
+ done:
+ tor_free(lengths1);
+ tor_free(lengths2);
+ tor_free(sls1);
+ tor_free(sls2);
+ smartlist_free(sl1);
+ smartlist_free(sl2);
+ memarea_drop_all(area);
+}
+
+static void
+test_consdiff_trim_slices(void *arg)
+{
+ smartlist_t *sl1 = smartlist_new();
+ smartlist_t *sl2 = smartlist_new();
+ smartlist_t *sl3 = smartlist_new();
+ smartlist_t *sl4 = smartlist_new();
+ smartlist_slice_t *sls1, *sls2, *sls3, *sls4;
+ memarea_t *area = memarea_new();
+
+ (void)arg;
+ consensus_split_lines(sl1, "a\nb\nb\nb\nd\n", area);
+ consensus_split_lines(sl2, "a\nc\nc\nc\nd\n", area);
+ consensus_split_lines(sl3, "a\nb\nb\nb\na\n", area);
+ consensus_split_lines(sl4, "c\nb\nb\nb\nc\n", area);
+ sls1 = smartlist_slice(sl1, 0, -1);
+ sls2 = smartlist_slice(sl2, 0, -1);
+ sls3 = smartlist_slice(sl3, 0, -1);
+ sls4 = smartlist_slice(sl4, 0, -1);
+
+ /* They should be trimmed by one line at each end. */
+ tt_int_op(5, OP_EQ, sls1->len);
+ tt_int_op(5, OP_EQ, sls2->len);
+ trim_slices(sls1, sls2);
+ tt_int_op(3, OP_EQ, sls1->len);
+ tt_int_op(3, OP_EQ, sls2->len);
+
+ /* They should not be trimmed at all. */
+ tt_int_op(5, OP_EQ, sls3->len);
+ tt_int_op(5, OP_EQ, sls4->len);
+ trim_slices(sls3, sls4);
+ tt_int_op(5, OP_EQ, sls3->len);
+ tt_int_op(5, OP_EQ, sls4->len);
+
+ done:
+ tor_free(sls1);
+ tor_free(sls2);
+ tor_free(sls3);
+ tor_free(sls4);
+ smartlist_free(sl1);
+ smartlist_free(sl2);
+ smartlist_free(sl3);
+ smartlist_free(sl4);
+ memarea_drop_all(area);
+}
+
+static void
+test_consdiff_set_changed(void *arg)
+{
+ smartlist_t *sl1 = smartlist_new();
+ smartlist_t *sl2 = smartlist_new();
+ bitarray_t *changed1 = bitarray_init_zero(4);
+ bitarray_t *changed2 = bitarray_init_zero(4);
+ smartlist_slice_t *sls1, *sls2;
+ memarea_t *area = memarea_new();
+
+ (void)arg;
+ consensus_split_lines(sl1, "a\nb\na\na\n", area);
+ consensus_split_lines(sl2, "a\na\na\na\n", area);
+
+ /* Length of sls1 is 0. */
+ sls1 = smartlist_slice(sl1, 0, 0);
+ sls2 = smartlist_slice(sl2, 1, 3);
+ set_changed(changed1, changed2, sls1, sls2);
+
+ /* The former is not changed, the latter changes all of its elements. */
+ tt_assert(!bitarray_is_set(changed1, 0));
+ tt_assert(!bitarray_is_set(changed1, 1));
+ tt_assert(!bitarray_is_set(changed1, 2));
+ tt_assert(!bitarray_is_set(changed1, 3));
+
+ tt_assert(!bitarray_is_set(changed2, 0));
+ tt_assert(bitarray_is_set(changed2, 1));
+ tt_assert(bitarray_is_set(changed2, 2));
+ tt_assert(!bitarray_is_set(changed2, 3));
+ bitarray_clear(changed2, 1);
+ bitarray_clear(changed2, 2);
+
+ /* Length of sls1 is 1 and its element is in sls2. */
+ tor_free(sls1);
+ sls1 = smartlist_slice(sl1, 0, 1);
+ set_changed(changed1, changed2, sls1, sls2);
+
+ /* The latter changes all elements but the (first) common one. */
+ tt_assert(!bitarray_is_set(changed1, 0));
+ tt_assert(!bitarray_is_set(changed1, 1));
+ tt_assert(!bitarray_is_set(changed1, 2));
+ tt_assert(!bitarray_is_set(changed1, 3));
+
+ tt_assert(!bitarray_is_set(changed2, 0));
+ tt_assert(!bitarray_is_set(changed2, 1));
+ tt_assert(bitarray_is_set(changed2, 2));
+ tt_assert(!bitarray_is_set(changed2, 3));
+ bitarray_clear(changed2, 2);
+
+ /* Length of sls1 is 1 and its element is not in sls2. */
+ tor_free(sls1);
+ sls1 = smartlist_slice(sl1, 1, 2);
+ set_changed(changed1, changed2, sls1, sls2);
+
+ /* The former changes its element, the latter changes all elements. */
+ tt_assert(!bitarray_is_set(changed1, 0));
+ tt_assert(bitarray_is_set(changed1, 1));
+ tt_assert(!bitarray_is_set(changed1, 2));
+ tt_assert(!bitarray_is_set(changed1, 3));
+
+ tt_assert(!bitarray_is_set(changed2, 0));
+ tt_assert(bitarray_is_set(changed2, 1));
+ tt_assert(bitarray_is_set(changed2, 2));
+ tt_assert(!bitarray_is_set(changed2, 3));
+
+ done:
+ bitarray_free(changed1);
+ bitarray_free(changed2);
+ smartlist_free(sl1);
+ smartlist_free(sl2);
+ tor_free(sls1);
+ tor_free(sls2);
+ memarea_drop_all(area);
+}
+
+static void
+test_consdiff_calc_changes(void *arg)
+{
+ smartlist_t *sl1 = smartlist_new();
+ smartlist_t *sl2 = smartlist_new();
+ smartlist_slice_t *sls1, *sls2;
+ bitarray_t *changed1 = bitarray_init_zero(4);
+ bitarray_t *changed2 = bitarray_init_zero(4);
+ memarea_t *area = memarea_new();
+
+ (void)arg;
+ consensus_split_lines(sl1, "a\na\na\na\n", area);
+ consensus_split_lines(sl2, "a\na\na\na\n", area);
+
+ sls1 = smartlist_slice(sl1, 0, -1);
+ sls2 = smartlist_slice(sl2, 0, -1);
+ calc_changes(sls1, sls2, changed1, changed2);
+
+ /* Nothing should be set to changed. */
+ tt_assert(!bitarray_is_set(changed1, 0));
+ tt_assert(!bitarray_is_set(changed1, 1));
+ tt_assert(!bitarray_is_set(changed1, 2));
+ tt_assert(!bitarray_is_set(changed1, 3));
+
+ tt_assert(!bitarray_is_set(changed2, 0));
+ tt_assert(!bitarray_is_set(changed2, 1));
+ tt_assert(!bitarray_is_set(changed2, 2));
+ tt_assert(!bitarray_is_set(changed2, 3));
+
+ smartlist_clear(sl2);
+ consensus_split_lines(sl2, "a\nb\na\nb\n", area);
+ tor_free(sls1);
+ tor_free(sls2);
+ sls1 = smartlist_slice(sl1, 0, -1);
+ sls2 = smartlist_slice(sl2, 0, -1);
+ calc_changes(sls1, sls2, changed1, changed2);
+
+ /* Two elements are changed. */
+ tt_assert(!bitarray_is_set(changed1, 0));
+ tt_assert(bitarray_is_set(changed1, 1));
+ tt_assert(bitarray_is_set(changed1, 2));
+ tt_assert(!bitarray_is_set(changed1, 3));
+ bitarray_clear(changed1, 1);
+ bitarray_clear(changed1, 2);
+
+ tt_assert(!bitarray_is_set(changed2, 0));
+ tt_assert(bitarray_is_set(changed2, 1));
+ tt_assert(!bitarray_is_set(changed2, 2));
+ tt_assert(bitarray_is_set(changed2, 3));
+ bitarray_clear(changed1, 1);
+ bitarray_clear(changed1, 3);
+
+ smartlist_clear(sl2);
+ consensus_split_lines(sl2, "b\nb\nb\nb\n", area);
+ tor_free(sls1);
+ tor_free(sls2);
+ sls1 = smartlist_slice(sl1, 0, -1);
+ sls2 = smartlist_slice(sl2, 0, -1);
+ calc_changes(sls1, sls2, changed1, changed2);
+
+ /* All elements are changed. */
+ tt_assert(bitarray_is_set(changed1, 0));
+ tt_assert(bitarray_is_set(changed1, 1));
+ tt_assert(bitarray_is_set(changed1, 2));
+ tt_assert(bitarray_is_set(changed1, 3));
+
+ tt_assert(bitarray_is_set(changed2, 0));
+ tt_assert(bitarray_is_set(changed2, 1));
+ tt_assert(bitarray_is_set(changed2, 2));
+ tt_assert(bitarray_is_set(changed2, 3));
+
+ done:
+ bitarray_free(changed1);
+ bitarray_free(changed2);
+ smartlist_free(sl1);
+ smartlist_free(sl2);
+ tor_free(sls1);
+ tor_free(sls2);
+ memarea_drop_all(area);
+}
+
+static void
+test_consdiff_get_id_hash(void *arg)
+{
+ (void)arg;
+
+ cdline_t line1 = { "r name", 6 };
+ cdline_t line2 = { "r name _hash_isnt_base64 etc", 28 };
+ cdline_t line3 = { "r name hash+valid+base64 etc", 28 };
+ cdline_t tmp;
+
+ /* No hash. */
+ tt_int_op(-1, OP_EQ, get_id_hash(&line1, &tmp));
+ /* The hash contains characters that are not base64. */
+ tt_int_op(-1, OP_EQ, get_id_hash(&line2, &tmp));
+
+ /* valid hash. */
+ tt_int_op(0, OP_EQ, get_id_hash(&line3, &tmp));
+ tt_ptr_op(tmp.s, OP_EQ, line3.s + 7);
+ tt_uint_op(tmp.len, OP_EQ, line3.len - 11);
+
+ done:
+ ;
+}
+
+static void
+test_consdiff_is_valid_router_entry(void *arg)
+{
+ /* Doesn't start with "r ". */
+ (void)arg;
+ cdline_t line0 = { "foo", 3 };
+ tt_int_op(0, OP_EQ, is_valid_router_entry(&line0));
+
+ /* These are already tested with get_id_hash, but make sure it's run
+ * properly. */
+
+ cdline_t line1 = { "r name", 6 };
+ cdline_t line2 = { "r name _hash_isnt_base64 etc", 28 };
+ cdline_t line3 = { "r name hash+valid+base64 etc", 28 };
+ tt_int_op(0, OP_EQ, is_valid_router_entry(&line1));
+ tt_int_op(0, OP_EQ, is_valid_router_entry(&line2));
+ tt_int_op(1, OP_EQ, is_valid_router_entry(&line3));
+
+ done:
+ ;
+}
+
+static void
+test_consdiff_next_router(void *arg)
+{
+ smartlist_t *sl = smartlist_new();
+ memarea_t *area = memarea_new();
+ (void)arg;
+ smartlist_add_linecpy(sl, area, "foo");
+ smartlist_add_linecpy(sl, area,
+ "r name hash+longer+than+27+chars+and+valid+base64 etc");
+ smartlist_add_linecpy(sl, area, "foo");
+ smartlist_add_linecpy(sl, area, "foo");
+ smartlist_add_linecpy(sl, area,
+ "r name hash+longer+than+27+chars+and+valid+base64 etc");
+ smartlist_add_linecpy(sl, area, "foo");
+
+ /* Not currently on a router entry line, finding the next one. */
+ tt_int_op(1, OP_EQ, next_router(sl, 0));
+ tt_int_op(4, OP_EQ, next_router(sl, 2));
+
+ /* Already at the beginning of a router entry line, ignore it. */
+ tt_int_op(4, OP_EQ, next_router(sl, 1));
+
+ /* There are no more router entries, so return the line after the last. */
+ tt_int_op(6, OP_EQ, next_router(sl, 4));
+ tt_int_op(6, OP_EQ, next_router(sl, 5));
+
+ done:
+ smartlist_free(sl);
+ memarea_drop_all(area);
+}
+
+static int
+base64cmp_wrapper(const char *a, const char *b)
+{
+ cdline_t aa = { a, a ? (uint32_t) strlen(a) : 0 };
+ cdline_t bb = { b, b ? (uint32_t) strlen(b) : 0 };
+ return base64cmp(&aa, &bb);
+}
+
+static void
+test_consdiff_base64cmp(void *arg)
+{
+ /* NULL arguments. */
+ (void)arg;
+ tt_int_op(0, OP_EQ, base64cmp_wrapper(NULL, NULL));
+ tt_int_op(-1, OP_EQ, base64cmp_wrapper(NULL, "foo"));
+ tt_int_op(1, OP_EQ, base64cmp_wrapper("bar", NULL));
+
+ /* Nil base64 values. */
+ tt_int_op(0, OP_EQ, base64cmp_wrapper("", ""));
+ tt_int_op(0, OP_EQ, base64cmp_wrapper("_", "&"));
+
+ /* Exact same valid strings. */
+ tt_int_op(0, OP_EQ, base64cmp_wrapper("abcABC/+", "abcABC/+"));
+ /* Both end with an invalid base64 char other than '\0'. */
+ tt_int_op(0, OP_EQ, base64cmp_wrapper("abcABC/+ ", "abcABC/+ "));
+ /* Only one ends with an invalid base64 char other than '\0'. */
+ tt_int_op(-1, OP_EQ, base64cmp_wrapper("abcABC/+ ", "abcABC/+a"));
+
+ /* Comparisons that would return differently with strcmp(). */
+ tt_int_op(-1, OP_EQ, strcmp("/foo", "Afoo"));
+ tt_int_op(1, OP_EQ, base64cmp_wrapper("/foo", "Afoo"));
+ tt_int_op(1, OP_EQ, strcmp("Afoo", "0foo"));
+ tt_int_op(-1, OP_EQ, base64cmp_wrapper("Afoo", "0foo"));
+
+ /* Comparisons that would return the same as with strcmp(). */
+ tt_int_op(1, OP_EQ, strcmp("afoo", "Afoo"));
+ tt_int_op(1, OP_EQ, base64cmp_wrapper("afoo", "Afoo"));
+
+ /* Different lengths */
+ tt_int_op(-1, OP_EQ, base64cmp_wrapper("afoo", "afooo"));
+ tt_int_op(1, OP_EQ, base64cmp_wrapper("afooo", "afoo"));
+
+ done:
+ ;
+}
+
+static void
+test_consdiff_gen_ed_diff(void *arg)
+{
+ smartlist_t *cons1=NULL, *cons2=NULL, *diff=NULL;
+ int i;
+ memarea_t *area = memarea_new();
+ setup_capture_of_logs(LOG_WARN);
+
+ (void)arg;
+ cons1 = smartlist_new();
+ cons2 = smartlist_new();
+
+ /* Identity hashes are not sorted properly, return NULL. */
+ smartlist_add_linecpy(cons1, area, "r name bbbbbbbbbbbbbbbbbbbbbbbbbbb etc");
+ smartlist_add_linecpy(cons1, area, "foo");
+ smartlist_add_linecpy(cons1, area, "r name aaaaaaaaaaaaaaaaaaaaaaaaaaa etc");
+ smartlist_add_linecpy(cons1, area, "bar");
+
+ smartlist_add_linecpy(cons2, area, "r name aaaaaaaaaaaaaaaaaaaaaaaaaaa etc");
+ smartlist_add_linecpy(cons2, area, "foo");
+ smartlist_add_linecpy(cons2, area, "r name ccccccccccccccccccccccccccc etc");
+ smartlist_add_linecpy(cons2, area, "bar");
+
+ diff = gen_ed_diff(cons1, cons2, area);
+ tt_ptr_op(NULL, OP_EQ, diff);
+ expect_single_log_msg_containing("Refusing to generate consensus diff "
+ "because the base consensus doesn't have its router entries sorted "
+ "properly.");
+
+ /* Same, but now with the second consensus. */
+ mock_clean_saved_logs();
+ diff = gen_ed_diff(cons2, cons1, area);
+ tt_ptr_op(NULL, OP_EQ, diff);
+ expect_single_log_msg_containing("Refusing to generate consensus diff "
+ "because the target consensus doesn't have its router entries sorted "
+ "properly.");
+
+ /* Same as the two above, but with the reversed thing immediately after a
+ match. (The code handles this differently) */
+ smartlist_del(cons1, 0);
+ smartlist_add_linecpy(cons1, area, "r name aaaaaaaaaaaaaaaaaaaaaaaaaaa etc");
+
+ mock_clean_saved_logs();
+ diff = gen_ed_diff(cons1, cons2, area);
+ tt_ptr_op(NULL, OP_EQ, diff);
+ expect_single_log_msg_containing("Refusing to generate consensus diff "
+ "because the base consensus doesn't have its router entries sorted "
+ "properly.");
+
+ mock_clean_saved_logs();
+ diff = gen_ed_diff(cons2, cons1, area);
+ tt_ptr_op(NULL, OP_EQ, diff);
+ expect_single_log_msg_containing("Refusing to generate consensus diff "
+ "because the target consensus doesn't have its router entries sorted "
+ "properly.");
+
+ /* Identity hashes are repeated, return NULL. */
+ smartlist_clear(cons1);
+
+ smartlist_add_linecpy(cons1, area, "r name bbbbbbbbbbbbbbbbbbbbbbbbbbb etc");
+ smartlist_add_linecpy(cons1, area, "foo");
+ smartlist_add_linecpy(cons1, area, "r name bbbbbbbbbbbbbbbbbbbbbbbbbbb etc");
+ smartlist_add_linecpy(cons1, area, "bar");
+
+ mock_clean_saved_logs();
+ diff = gen_ed_diff(cons1, cons2, area);
+ tt_ptr_op(NULL, OP_EQ, diff);
+ expect_single_log_msg_containing("Refusing to generate consensus diff "
+ "because the base consensus doesn't have its router entries sorted "
+ "properly.");
+
+ /* We have to add a line that is just a dot, return NULL. */
+ smartlist_clear(cons1);
+ smartlist_clear(cons2);
+
+ smartlist_add_linecpy(cons1, area, "foo1");
+ smartlist_add_linecpy(cons1, area, "foo2");
+
+ smartlist_add_linecpy(cons2, area, "foo1");
+ smartlist_add_linecpy(cons2, area, ".");
+ smartlist_add_linecpy(cons2, area, "foo2");
+
+ mock_clean_saved_logs();
+ diff = gen_ed_diff(cons1, cons2, area);
+ tt_ptr_op(NULL, OP_EQ, diff);
+ expect_single_log_msg_containing("Cannot generate consensus diff "
+ "because one of the lines to be added is \".\".");
+
+#define MAX_LINE_COUNT (10000)
+ /* Too many lines to be fed to the quadratic-time function. */
+ smartlist_clear(cons1);
+ smartlist_clear(cons2);
+
+ for (i=0; i < MAX_LINE_COUNT; ++i) smartlist_add_linecpy(cons1, area, "a");
+ for (i=0; i < MAX_LINE_COUNT; ++i) smartlist_add_linecpy(cons1, area, "b");
+
+ mock_clean_saved_logs();
+ diff = gen_ed_diff(cons1, cons2, area);
+
+ tt_ptr_op(NULL, OP_EQ, diff);
+ expect_single_log_msg_containing("Refusing to generate consensus diff "
+ "because we found too few common router ids.");
+
+ /* We have dot lines, but they don't interfere with the script format. */
+ smartlist_clear(cons1);
+ smartlist_clear(cons2);
+
+ smartlist_add_linecpy(cons1, area, "foo1");
+ smartlist_add_linecpy(cons1, area, ".");
+ smartlist_add_linecpy(cons1, area, ".");
+ smartlist_add_linecpy(cons1, area, "foo2");
+
+ smartlist_add_linecpy(cons2, area, "foo1");
+ smartlist_add_linecpy(cons2, area, ".");
+ smartlist_add_linecpy(cons2, area, "foo2");
+
+ diff = gen_ed_diff(cons1, cons2, area);
+ tt_ptr_op(NULL, OP_NE, diff);
+ smartlist_free(diff);
+
+ /* Empty diff tests. */
+ smartlist_clear(cons1);
+ smartlist_clear(cons2);
+
+ diff = gen_ed_diff(cons1, cons2, area);
+ tt_ptr_op(NULL, OP_NE, diff);
+ tt_int_op(0, OP_EQ, smartlist_len(diff));
+ smartlist_free(diff);
+
+ smartlist_add_linecpy(cons1, area, "foo");
+ smartlist_add_linecpy(cons1, area, "bar");
+
+ smartlist_add_linecpy(cons2, area, "foo");
+ smartlist_add_linecpy(cons2, area, "bar");
+
+ diff = gen_ed_diff(cons1, cons2, area);
+ tt_ptr_op(NULL, OP_NE, diff);
+ tt_int_op(0, OP_EQ, smartlist_len(diff));
+ smartlist_free(diff);
+
+ /* Everything is deleted. */
+ smartlist_clear(cons2);
+
+ diff = gen_ed_diff(cons1, cons2, area);
+ tt_ptr_op(NULL, OP_NE, diff);
+ tt_int_op(1, OP_EQ, smartlist_len(diff));
+ tt_str_eq_line("1,2d", smartlist_get(diff, 0));
+
+ smartlist_free(diff);
+
+ /* Everything is added. */
+ diff = gen_ed_diff(cons2, cons1, area);
+ tt_ptr_op(NULL, OP_NE, diff);
+ tt_int_op(4, OP_EQ, smartlist_len(diff));
+ tt_str_eq_line("0a", smartlist_get(diff, 0));
+ tt_str_eq_line("foo", smartlist_get(diff, 1));
+ tt_str_eq_line("bar", smartlist_get(diff, 2));
+ tt_str_eq_line(".", smartlist_get(diff, 3));
+
+ smartlist_free(diff);
+
+ /* Everything is changed. */
+ smartlist_add_linecpy(cons2, area, "foo2");
+ smartlist_add_linecpy(cons2, area, "bar2");
+ diff = gen_ed_diff(cons1, cons2, area);
+ tt_ptr_op(NULL, OP_NE, diff);
+ tt_int_op(4, OP_EQ, smartlist_len(diff));
+ tt_str_eq_line("1,2c", smartlist_get(diff, 0));
+ tt_str_eq_line("foo2", smartlist_get(diff, 1));
+ tt_str_eq_line("bar2", smartlist_get(diff, 2));
+ tt_str_eq_line(".", smartlist_get(diff, 3));
+
+ smartlist_free(diff);
+
+ /* Test 'a', 'c' and 'd' together. See that it is done in reverse order. */
+ smartlist_clear(cons1);
+ smartlist_clear(cons2);
+ consensus_split_lines(cons1, "A\nB\nC\nD\nE\n", area);
+ consensus_split_lines(cons2, "A\nC\nO\nE\nU\n", area);
+ diff = gen_ed_diff(cons1, cons2, area);
+ tt_ptr_op(NULL, OP_NE, diff);
+ tt_int_op(7, OP_EQ, smartlist_len(diff));
+ tt_str_eq_line("5a", smartlist_get(diff, 0));
+ tt_str_eq_line("U", smartlist_get(diff, 1));
+ tt_str_eq_line(".", smartlist_get(diff, 2));
+ tt_str_eq_line("4c", smartlist_get(diff, 3));
+ tt_str_eq_line("O", smartlist_get(diff, 4));
+ tt_str_eq_line(".", smartlist_get(diff, 5));
+ tt_str_eq_line("2d", smartlist_get(diff, 6));
+
+ smartlist_free(diff);
+
+ smartlist_clear(cons1);
+ smartlist_clear(cons2);
+ consensus_split_lines(cons1, "B\n", area);
+ consensus_split_lines(cons2, "A\nB\n", area);
+ diff = gen_ed_diff(cons1, cons2, area);
+ tt_ptr_op(NULL, OP_NE, diff);
+ tt_int_op(3, OP_EQ, smartlist_len(diff));
+ tt_str_eq_line("0a", smartlist_get(diff, 0));
+ tt_str_eq_line("A", smartlist_get(diff, 1));
+ tt_str_eq_line(".", smartlist_get(diff, 2));
+
+ /* TODO: small real use-cases, i.e. consensuses. */
+
+ done:
+ teardown_capture_of_logs();
+ smartlist_free(cons1);
+ smartlist_free(cons2);
+ smartlist_free(diff);
+ memarea_drop_all(area);
+}
+
+static void
+test_consdiff_apply_ed_diff(void *arg)
+{
+ smartlist_t *cons1=NULL, *cons2=NULL, *diff=NULL;
+ memarea_t *area = memarea_new();
+ (void)arg;
+ cons1 = smartlist_new();
+ diff = smartlist_new();
+ setup_capture_of_logs(LOG_WARN);
+
+ consensus_split_lines(cons1, "A\nB\nC\nD\nE\n", area);
+
+ /* Command without range. */
+ smartlist_add_linecpy(diff, area, "a");
+ cons2 = apply_ed_diff(cons1, diff, 0);
+ tt_ptr_op(NULL, OP_EQ, cons2);
+ smartlist_clear(diff);
+ expect_single_log_msg_containing("an ed command was missing a line number");
+
+ /* Range without command. */
+ smartlist_add_linecpy(diff, area, "1");
+ mock_clean_saved_logs();
+ cons2 = apply_ed_diff(cons1, diff, 0);
+ tt_ptr_op(NULL, OP_EQ, cons2);
+ expect_single_log_msg_containing("a line with no ed command was found");
+
+ smartlist_clear(diff);
+
+ /* Range without end. */
+ smartlist_add_linecpy(diff, area, "1,");
+ mock_clean_saved_logs();
+ cons2 = apply_ed_diff(cons1, diff, 0);
+ tt_ptr_op(NULL, OP_EQ, cons2);
+ expect_single_log_msg_containing("an ed command was missing a range "
+ "end line number.");
+
+ smartlist_clear(diff);
+
+ /* Incoherent ranges. */
+ smartlist_add_linecpy(diff, area, "1,1");
+ mock_clean_saved_logs();
+ cons2 = apply_ed_diff(cons1, diff, 0);
+ tt_ptr_op(NULL, OP_EQ, cons2);
+ expect_single_log_msg_containing("an invalid range was found");
+
+ smartlist_clear(diff);
+
+ smartlist_add_linecpy(diff, area, "3,2");
+ mock_clean_saved_logs();
+ cons2 = apply_ed_diff(cons1, diff, 0);
+ tt_ptr_op(NULL, OP_EQ, cons2);
+ expect_single_log_msg_containing("an invalid range was found");
+
+ smartlist_clear(diff);
+
+ /* Unexpected range for add command. */
+ smartlist_add_linecpy(diff, area, "1,2a");
+ mock_clean_saved_logs();
+ cons2 = apply_ed_diff(cons1, diff, 0);
+ tt_ptr_op(NULL, OP_EQ, cons2);
+ expect_single_log_msg_containing("add lines after a range");
+
+ smartlist_clear(diff);
+
+ /* Script is not in reverse order. */
+ smartlist_add_linecpy(diff, area, "1d");
+ smartlist_add_linecpy(diff, area, "3d");
+ mock_clean_saved_logs();
+ cons2 = apply_ed_diff(cons1, diff, 0);
+ tt_ptr_op(NULL, OP_EQ, cons2);
+ expect_single_log_msg_containing("its commands are not properly sorted");
+
+ smartlist_clear(diff);
+
+ /* Script contains unrecognised commands longer than one char. */
+ smartlist_add_linecpy(diff, area, "1foo");
+ mock_clean_saved_logs();
+ cons2 = apply_ed_diff(cons1, diff, 0);
+ tt_ptr_op(NULL, OP_EQ, cons2);
+ expect_single_log_msg_containing("an ed command longer than one char was "
+ "found");
+
+ smartlist_clear(diff);
+
+ /* Script contains unrecognised commands. */
+ smartlist_add_linecpy(diff, area, "1e");
+ mock_clean_saved_logs();
+ cons2 = apply_ed_diff(cons1, diff, 0);
+ tt_ptr_op(NULL, OP_EQ, cons2);
+ expect_single_log_msg_containing("an unrecognised ed command was found");
+
+ smartlist_clear(diff);
+
+ /* Command that should be followed by at least one line and a ".", but
+ * isn't. */
+ smartlist_add_linecpy(diff, area, "0a");
+ mock_clean_saved_logs();
+ cons2 = apply_ed_diff(cons1, diff, 0);
+ tt_ptr_op(NULL, OP_EQ, cons2);
+ expect_single_log_msg_containing("it has an ed command that tries to "
+ "insert zero lines.");
+
+ /* Now it is followed by a ".", but it inserts zero lines. */
+ smartlist_add_linecpy(diff, area, ".");
+ mock_clean_saved_logs();
+ cons2 = apply_ed_diff(cons1, diff, 0);
+ tt_ptr_op(NULL, OP_EQ, cons2);
+ expect_single_log_msg_containing("it has an ed command that tries to "
+ "insert zero lines.");
+
+ smartlist_clear(diff);
+
+ /* Now it it inserts something, but has no terminator. */
+ smartlist_add_linecpy(diff, area, "0a");
+ smartlist_add_linecpy(diff, area, "hello");
+ mock_clean_saved_logs();
+ cons2 = apply_ed_diff(cons1, diff, 0);
+ tt_ptr_op(NULL, OP_EQ, cons2);
+ expect_single_log_msg_containing("lines to be inserted that don't end with "
+ "a \".\".");
+
+ smartlist_clear(diff);
+
+ /* Ranges must be numeric only and cannot contain spaces. */
+ smartlist_add_linecpy(diff, area, "0, 4d");
+ mock_clean_saved_logs();
+ cons2 = apply_ed_diff(cons1, diff, 0);
+ tt_ptr_op(NULL, OP_EQ, cons2);
+ expect_single_log_msg_containing("an ed command was missing a range "
+ "end line number.");
+
+ smartlist_clear(diff);
+
+ /* '+' is not a number. */
+ smartlist_add_linecpy(diff, area, "+0,4d");
+ mock_clean_saved_logs();
+ cons2 = apply_ed_diff(cons1, diff, 0);
+ tt_ptr_op(NULL, OP_EQ, cons2);
+ expect_single_log_msg_containing("an ed command was missing a line number");
+
+ smartlist_clear(diff);
+
+ /* range duplication */
+ smartlist_add_linecpy(diff, area, "0,4d,5d");
+ mock_clean_saved_logs();
+ cons2 = apply_ed_diff(cons1, diff, 0);
+ tt_ptr_op(NULL, OP_EQ, cons2);
+ expect_single_log_msg_containing("an ed command longer than one char was "
+ "found");
+
+ smartlist_clear(diff);
+
+ /* space before command */
+ smartlist_add_linecpy(diff, area, "0,4 d");
+ mock_clean_saved_logs();
+ cons2 = apply_ed_diff(cons1, diff, 0);
+ tt_ptr_op(NULL, OP_EQ, cons2);
+ expect_single_log_msg_containing("an ed command longer than one char was "
+ "found");
+
+ smartlist_clear(diff);
+
+ /* space inside number */
+ smartlist_add_linecpy(diff, area, "0,4 5d");
+ mock_clean_saved_logs();
+ cons2 = apply_ed_diff(cons1, diff, 0);
+ tt_ptr_op(NULL, OP_EQ, cons2);
+ expect_single_log_msg_containing("an ed command longer than one char was "
+ "found");
+
+ smartlist_clear(diff);
+
+ /* Test appending text, 'a'. */
+ consensus_split_lines(diff, "3a\nU\nO\n.\n0a\nV\n.\n", area);
+ cons2 = apply_ed_diff(cons1, diff, 0);
+ tt_ptr_op(NULL, OP_NE, cons2);
+ tt_int_op(8, OP_EQ, smartlist_len(cons2));
+ tt_str_eq_line("V", smartlist_get(cons2, 0));
+ tt_str_eq_line("A", smartlist_get(cons2, 1));
+ tt_str_eq_line("B", smartlist_get(cons2, 2));
+ tt_str_eq_line("C", smartlist_get(cons2, 3));
+ tt_str_eq_line("U", smartlist_get(cons2, 4));
+ tt_str_eq_line("O", smartlist_get(cons2, 5));
+ tt_str_eq_line("D", smartlist_get(cons2, 6));
+ tt_str_eq_line("E", smartlist_get(cons2, 7));
+
+ smartlist_clear(diff);
+ smartlist_free(cons2);
+
+ /* Test deleting text, 'd'. */
+ consensus_split_lines(diff, "4d\n1,2d\n", area);
+ cons2 = apply_ed_diff(cons1, diff, 0);
+ tt_ptr_op(NULL, OP_NE, cons2);
+ tt_int_op(2, OP_EQ, smartlist_len(cons2));
+ tt_str_eq_line("C", smartlist_get(cons2, 0));
+ tt_str_eq_line("E", smartlist_get(cons2, 1));
+
+ smartlist_clear(diff);
+ smartlist_free(cons2);
+
+ /* Test changing text, 'c'. */
+ consensus_split_lines(diff, "4c\nT\nX\n.\n1,2c\nM\n.\n", area);
+ cons2 = apply_ed_diff(cons1, diff, 0);
+ tt_ptr_op(NULL, OP_NE, cons2);
+ tt_int_op(5, OP_EQ, smartlist_len(cons2));
+ tt_str_eq_line("M", smartlist_get(cons2, 0));
+ tt_str_eq_line("C", smartlist_get(cons2, 1));
+ tt_str_eq_line("T", smartlist_get(cons2, 2));
+ tt_str_eq_line("X", smartlist_get(cons2, 3));
+ tt_str_eq_line("E", smartlist_get(cons2, 4));
+
+ smartlist_clear(diff);
+ smartlist_free(cons2);
+
+ /* Test 'a', 'd' and 'c' together. */
+ consensus_split_lines(diff, "4c\nT\nX\n.\n2d\n0a\nM\n.\n", area);
+ cons2 = apply_ed_diff(cons1, diff, 0);
+ tt_ptr_op(NULL, OP_NE, cons2);
+ tt_int_op(6, OP_EQ, smartlist_len(cons2));
+ tt_str_eq_line("M", smartlist_get(cons2, 0));
+ tt_str_eq_line("A", smartlist_get(cons2, 1));
+ tt_str_eq_line("C", smartlist_get(cons2, 2));
+ tt_str_eq_line("T", smartlist_get(cons2, 3));
+ tt_str_eq_line("X", smartlist_get(cons2, 4));
+ tt_str_eq_line("E", smartlist_get(cons2, 5));
+
+ done:
+ teardown_capture_of_logs();
+ smartlist_free(cons1);
+ smartlist_free(cons2);
+ smartlist_free(diff);
+ memarea_drop_all(area);
+}
+
+static void
+test_consdiff_gen_diff(void *arg)
+{
+ char *cons1_str=NULL, *cons2_str=NULL;
+ smartlist_t *cons1=NULL, *cons2=NULL, *diff=NULL;
+ consensus_digest_t digests1, digests2;
+ memarea_t *area = memarea_new();
+ (void)arg;
+ cons1 = smartlist_new();
+ cons2 = smartlist_new();
+
+ /* Identity hashes are not sorted properly, return NULL.
+ * Already tested in gen_ed_diff, but see that a NULL ed diff also makes
+ * gen_diff return NULL. */
+ cons1_str = tor_strdup(
+ "network-status-version foo\n"
+ "r name bbbbbbbbbbbbbbbbb etc\nfoo\n"
+ "r name aaaaaaaaaaaaaaaaa etc\nbar\n"
+ "directory-signature foo bar\nbar\n"
+ );
+ cons2_str = tor_strdup(
+ "network-status-version foo\n"
+ "r name aaaaaaaaaaaaaaaaa etc\nfoo\n"
+ "r name ccccccccccccccccc etc\nbar\n"
+ "directory-signature foo bar\nbar\n"
+ );
+
+ tt_int_op(0, OP_EQ,
+ consensus_compute_digest(cons1_str, &digests1));
+ tt_int_op(0, OP_EQ,
+ consensus_compute_digest(cons2_str, &digests2));
+
+ consensus_split_lines(cons1, cons1_str, area);
+ consensus_split_lines(cons2, cons2_str, area);
+
+ diff = consdiff_gen_diff(cons1, cons2, &digests1, &digests2, area);
+ tt_ptr_op(NULL, OP_EQ, diff);
+
+ /* Check that the headers are done properly. */
+ tor_free(cons1_str);
+ cons1_str = tor_strdup(
+ "network-status-version foo\n"
+ "r name ccccccccccccccccc etc\nfoo\n"
+ "r name eeeeeeeeeeeeeeeee etc\nbar\n"
+ "directory-signature foo bar\nbar\n"
+ );
+ tt_int_op(0, OP_EQ,
+ consensus_compute_digest(cons1_str, &digests1));
+ smartlist_clear(cons1);
+ consensus_split_lines(cons1, cons1_str, area);
+ diff = consdiff_gen_diff(cons1, cons2, &digests1, &digests2, area);
+ tt_ptr_op(NULL, OP_NE, diff);
+ tt_int_op(7, OP_EQ, smartlist_len(diff));
+ tt_assert(line_str_eq(smartlist_get(diff, 0),
+ "network-status-diff-version 1"));
+ tt_assert(line_str_eq(smartlist_get(diff, 1), "hash "
+ "06646D6CF563A41869D3B02E73254372AE3140046C5E7D83C9F71E54976AF9B4 "
+ "7AFECEFA4599BA33D603653E3D2368F648DF4AC4723929B0F7CF39281596B0C1"));
+ tt_assert(line_str_eq(smartlist_get(diff, 2), "3,4d"));
+ tt_assert(line_str_eq(smartlist_get(diff, 3), "1a"));
+ tt_assert(line_str_eq(smartlist_get(diff, 4),
+ "r name aaaaaaaaaaaaaaaaa etc"));
+ tt_assert(line_str_eq(smartlist_get(diff, 5), "foo"));
+ tt_assert(line_str_eq(smartlist_get(diff, 6), "."));
+
+ /* TODO: small real use-cases, i.e. consensuses. */
+
+ done:
+ tor_free(cons1_str);
+ tor_free(cons2_str);
+ smartlist_free(cons1);
+ smartlist_free(cons2);
+ smartlist_free(diff);
+ memarea_drop_all(area);
+}
+
+static void
+test_consdiff_apply_diff(void *arg)
+{
+ smartlist_t *cons1=NULL, *diff=NULL;
+ char *cons1_str=NULL, *cons2 = NULL;
+ consensus_digest_t digests1;
+ (void)arg;
+ memarea_t *area = memarea_new();
+ cons1 = smartlist_new();
+ diff = smartlist_new();
+ setup_capture_of_logs(LOG_INFO);
+
+ cons1_str = tor_strdup(
+ "network-status-version foo\n"
+ "r name ccccccccccccccccc etc\nfoo\n"
+ "r name eeeeeeeeeeeeeeeee etc\nbar\n"
+ "directory-signature foo bar\nbar\n"
+ );
+ tt_int_op(0, OP_EQ,
+ consensus_compute_digest(cons1_str, &digests1));
+ consensus_split_lines(cons1, cons1_str, area);
+
+ /* diff doesn't have enough lines. */
+ cons2 = consdiff_apply_diff(cons1, diff, &digests1);
+ tt_ptr_op(NULL, OP_EQ, cons2);
+ expect_single_log_msg_containing("too short")
+
+ /* first line doesn't match format-version string. */
+ smartlist_add_linecpy(diff, area, "foo-bar");
+ smartlist_add_linecpy(diff, area, "header-line");
+ mock_clean_saved_logs();
+ cons2 = consdiff_apply_diff(cons1, diff, &digests1);
+ tt_ptr_op(NULL, OP_EQ, cons2);
+ expect_single_log_msg_containing("format is not known")
+
+ /* The first word of the second header line is not "hash". */
+ smartlist_clear(diff);
+ smartlist_add_linecpy(diff, area, "network-status-diff-version 1");
+ smartlist_add_linecpy(diff, area, "word a b");
+ smartlist_add_linecpy(diff, area, "x");
+ mock_clean_saved_logs();
+ cons2 = consdiff_apply_diff(cons1, diff, &digests1);
+ tt_ptr_op(NULL, OP_EQ, cons2);
+ expect_single_log_msg_containing("does not include the necessary digests")
+
+ /* Wrong number of words after "hash". */
+ smartlist_clear(diff);
+ smartlist_add_linecpy(diff, area, "network-status-diff-version 1");
+ smartlist_add_linecpy(diff, area, "hash a b c");
+ mock_clean_saved_logs();
+ cons2 = consdiff_apply_diff(cons1, diff, &digests1);
+ tt_ptr_op(NULL, OP_EQ, cons2);
+ expect_single_log_msg_containing("does not include the necessary digests")
+
+ /* base16 digests do not have the expected length. */
+ smartlist_clear(diff);
+ smartlist_add_linecpy(diff, area, "network-status-diff-version 1");
+ smartlist_add_linecpy(diff, area, "hash aaa bbb");
+ mock_clean_saved_logs();
+ cons2 = consdiff_apply_diff(cons1, diff, &digests1);
+ tt_ptr_op(NULL, OP_EQ, cons2);
+ expect_single_log_msg_containing("includes base16-encoded digests of "
+ "incorrect size")
+
+ /* base16 digests contain non-base16 characters. */
+ smartlist_clear(diff);
+ smartlist_add_linecpy(diff, area, "network-status-diff-version 1");
+ smartlist_add_linecpy(diff, area, "hash"
+ " ????????????????????????????????????????????????????????????????"
+ " ----------------------------------------------------------------");
+ mock_clean_saved_logs();
+ cons2 = consdiff_apply_diff(cons1, diff, &digests1);
+ tt_ptr_op(NULL, OP_EQ, cons2);
+ expect_single_log_msg_containing("includes malformed digests")
+
+ /* Invalid ed diff.
+ * As tested in apply_ed_diff, but check that apply_diff does return NULL if
+ * the ed diff can't be applied. */
+ smartlist_clear(diff);
+ smartlist_add_linecpy(diff, area, "network-status-diff-version 1");
+ smartlist_add_linecpy(diff, area, "hash"
+ /* sha3 of cons1. */
+ " 06646D6CF563A41869D3B02E73254372AE3140046C5E7D83C9F71E54976AF9B4"
+ /* sha256 of cons2. */
+ " 635D34593020C08E5ECD865F9986E29D50028EFA62843766A8197AD228A7F6AA");
+ smartlist_add_linecpy(diff, area, "foobar");
+ mock_clean_saved_logs();
+ cons2 = consdiff_apply_diff(cons1, diff, &digests1);
+ tt_ptr_op(NULL, OP_EQ, cons2);
+ expect_single_log_msg_containing("because an ed command was missing a line "
+ "number")
+
+ /* Base consensus doesn't match its digest as found in the diff. */
+ smartlist_clear(diff);
+ smartlist_add_linecpy(diff, area, "network-status-diff-version 1");
+ smartlist_add_linecpy(diff, area, "hash"
+ /* bogus sha256. */
+ " 3333333333333333333333333333333333333333333333333333333333333333"
+ /* sha256 of cons2. */
+ " 635D34593020C08E5ECD865F9986E29D50028EFA62843766A8197AD228A7F6AA");
+ mock_clean_saved_logs();
+ cons2 = consdiff_apply_diff(cons1, diff, &digests1);
+ tt_ptr_op(NULL, OP_EQ, cons2);
+ expect_log_msg_containing("base consensus doesn't match the digest "
+ "as found");
+
+ /* Resulting consensus doesn't match its digest as found in the diff. */
+ smartlist_clear(diff);
+ smartlist_add_linecpy(diff, area, "network-status-diff-version 1");
+ smartlist_add_linecpy(diff, area, "hash"
+ /* sha3 of cons1. */
+ " 06646D6CF563A41869D3B02E73254372AE3140046C5E7D83C9F71E54976AF9B4"
+ /* bogus sha3. */
+ " 3333333333333333333333333333333333333333333333333333333333333333");
+ mock_clean_saved_logs();
+ cons2 = consdiff_apply_diff(cons1, diff, &digests1);
+ tt_ptr_op(NULL, OP_EQ, cons2);
+ expect_log_msg_containing("resulting consensus doesn't match the "
+ "digest as found");
+
+#if 0
+ /* XXXX No longer possible, since we aren't using the other algorithm. */
+ /* Resulting consensus digest cannot be computed */
+ smartlist_clear(diff);
+ smartlist_add_linecpy(diff, area, "network-status-diff-version 1");
+ smartlist_add_linecpy(diff, area, "hash"
+ /* sha3 of cons1. */
+ " 06646D6CF563A41869D3B02E73254372AE3140046C5E7D83C9F71E54976AF9B4"
+ /* bogus sha3. */
+ " 3333333333333333333333333333333333333333333333333333333333333333");
+ smartlist_add_linecpy(diff, area, "1,2d"); // remove starting line
+ mock_clean_saved_logs();
+ cons2 = consdiff_apply_diff(cons1, diff, &digests1);
+ tt_ptr_op(NULL, OP_EQ, cons2);
+ expect_log_msg_containing("Could not compute digests of the consensus "
+ "resulting from applying a consensus diff.");
+#endif
+
+ /* Very simple test, only to see that nothing errors. */
+ smartlist_clear(diff);
+ smartlist_add_linecpy(diff, area, "network-status-diff-version 1");
+ smartlist_add_linecpy(diff, area, "hash"
+ /* sha3 of cons1. */
+ " 06646D6CF563A41869D3B02E73254372AE3140046C5E7D83C9F71E54976AF9B4"
+ /* sha3 of cons2. */
+ " 90A418881B2FCAB3D9E60EE02E4D666D56CFA38F8A3B7AA3E0ADBA530DDA9353");
+ smartlist_add_linecpy(diff, area, "3c");
+ smartlist_add_linecpy(diff, area, "sample");
+ smartlist_add_linecpy(diff, area, ".");
+ cons2 = consdiff_apply_diff(cons1, diff, &digests1);
+ tt_ptr_op(NULL, OP_NE, cons2);
+ tt_str_op(
+ "network-status-version foo\n"
+ "r name ccccccccccccccccc etc\nsample\n"
+ "r name eeeeeeeeeeeeeeeee etc\nbar\n"
+ "directory-signature foo bar\nbar\n", OP_EQ,
+ cons2);
+ tor_free(cons2);
+
+ /* Check that lowercase letters in base16-encoded digests work too. */
+ smartlist_clear(diff);
+ smartlist_add_linecpy(diff, area, "network-status-diff-version 1");
+ smartlist_add_linecpy(diff, area, "hash"
+ /* sha3 of cons1. */
+ " 06646d6cf563a41869d3b02e73254372ae3140046c5e7d83c9f71e54976af9b4"
+ /* sha3 of cons2. */
+ " 90a418881b2fcab3d9e60ee02e4d666d56cfa38f8a3b7aa3e0adba530dda9353");
+ smartlist_add_linecpy(diff, area, "3c");
+ smartlist_add_linecpy(diff, area, "sample");
+ smartlist_add_linecpy(diff, area, ".");
+ cons2 = consdiff_apply_diff(cons1, diff, &digests1);
+ tt_ptr_op(NULL, OP_NE, cons2);
+ tt_str_op(
+ "network-status-version foo\n"
+ "r name ccccccccccccccccc etc\nsample\n"
+ "r name eeeeeeeeeeeeeeeee etc\nbar\n"
+ "directory-signature foo bar\nbar\n", OP_EQ,
+ cons2);
+ tor_free(cons2);
+
+ smartlist_clear(diff);
+
+ done:
+ teardown_capture_of_logs();
+ tor_free(cons1_str);
+ smartlist_free(cons1);
+ smartlist_free(diff);
+ memarea_drop_all(area);
+}
+
+#define CONSDIFF_LEGACY(name) \
+ { #name, test_consdiff_ ## name , 0, NULL, NULL }
+
+struct testcase_t consdiff_tests[] = {
+ CONSDIFF_LEGACY(smartlist_slice),
+ CONSDIFF_LEGACY(smartlist_slice_string_pos),
+ CONSDIFF_LEGACY(lcs_lengths),
+ CONSDIFF_LEGACY(trim_slices),
+ CONSDIFF_LEGACY(set_changed),
+ CONSDIFF_LEGACY(calc_changes),
+ CONSDIFF_LEGACY(get_id_hash),
+ CONSDIFF_LEGACY(is_valid_router_entry),
+ CONSDIFF_LEGACY(next_router),
+ CONSDIFF_LEGACY(base64cmp),
+ CONSDIFF_LEGACY(gen_ed_diff),
+ CONSDIFF_LEGACY(apply_ed_diff),
+ CONSDIFF_LEGACY(gen_diff),
+ CONSDIFF_LEGACY(apply_diff),
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_consdiffmgr.c b/src/test/test_consdiffmgr.c
new file mode 100644
index 0000000000..31ce6ce901
--- /dev/null
+++ b/src/test/test_consdiffmgr.c
@@ -0,0 +1,890 @@
+/* Copyright (c) 2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#define CONSDIFFMGR_PRIVATE
+
+#include "or.h"
+#include "config.h"
+#include "conscache.h"
+#include "consdiff.h"
+#include "consdiffmgr.h"
+#include "cpuworker.h"
+#include "networkstatus.h"
+#include "workqueue.h"
+
+#include "test.h"
+#include "log_test_helpers.h"
+
+// ============================== Setup/teardown the consdiffmgr
+// These functions get run before/after each test in this module
+
+static void *
+consdiffmgr_test_setup(const struct testcase_t *arg)
+{
+ (void)arg;
+ char *ddir_fname = tor_strdup(get_fname_rnd("datadir_cdm"));
+ tor_free(get_options_mutable()->DataDirectory);
+ get_options_mutable()->DataDirectory = ddir_fname; // now owns the pointer.
+ check_private_dir(ddir_fname, CPD_CREATE, NULL);
+
+ consdiff_cfg_t consdiff_cfg = { 7200, 300 };
+ consdiffmgr_configure(&consdiff_cfg);
+ return (void *)1; // must return something non-null.
+}
+static int
+consdiffmgr_test_teardown(const struct testcase_t *arg, void *ignore)
+{
+ (void)arg;
+ (void)ignore;
+ consdiffmgr_free_all();
+ return 1;
+}
+static struct testcase_setup_t setup_diffmgr = {
+ consdiffmgr_test_setup,
+ consdiffmgr_test_teardown
+};
+
+// ============================== NS faking functions
+// These functions are for making quick fake consensus objects and
+// strings that are just good enough for consdiff and consdiffmgr.
+
+static networkstatus_t *
+fake_ns_new(consensus_flavor_t flav, time_t valid_after)
+{
+ networkstatus_t *ns = tor_malloc_zero(sizeof(networkstatus_t));
+ ns->type = NS_TYPE_CONSENSUS;
+ ns->flavor = flav;
+ ns->valid_after = valid_after;
+ return ns;
+}
+
+static char *
+fake_ns_body_new(consensus_flavor_t flav, time_t valid_after)
+{
+ const char *flavor_string = flav == FLAV_NS ? "" : " microdesc";
+ char valid_after_string[ISO_TIME_LEN+1];
+
+ format_iso_time(valid_after_string, valid_after);
+ char *random_stuff = crypto_random_hostname(3, 25, "junk ", "");
+
+ char *consensus;
+ tor_asprintf(&consensus,
+ "network-status-version 3%s\n"
+ "vote-status consensus\n"
+ "valid-after %s\n"
+ "r name ccccccccccccccccc etc\nsample\n"
+ "r name eeeeeeeeeeeeeeeee etc\nbar\n"
+ "%s\n",
+ flavor_string,
+ valid_after_string,
+ random_stuff);
+ tor_free(random_stuff);
+ return consensus;
+}
+
+// ============================== Cpuworker mocking code
+// These mocking functions and types capture the cpuworker calls
+// so we can inspect them and run them in the main thread.
+static smartlist_t *fake_cpuworker_queue = NULL;
+typedef struct fake_work_queue_ent_t {
+ enum workqueue_reply_t (*fn)(void *, void *);
+ void (*reply_fn)(void *);
+ void *arg;
+} fake_work_queue_ent_t;
+static struct workqueue_entry_s *
+mock_cpuworker_queue_work(enum workqueue_reply_t (*fn)(void *, void *),
+ void (*reply_fn)(void *),
+ void *arg)
+{
+ if (! fake_cpuworker_queue)
+ fake_cpuworker_queue = smartlist_new();
+
+ fake_work_queue_ent_t *ent = tor_malloc_zero(sizeof(*ent));
+ ent->fn = fn;
+ ent->reply_fn = reply_fn;
+ ent->arg = arg;
+ smartlist_add(fake_cpuworker_queue, ent);
+ return (struct workqueue_entry_s *)ent;
+}
+static int
+mock_cpuworker_run_work(void)
+{
+ if (! fake_cpuworker_queue)
+ return 0;
+ SMARTLIST_FOREACH(fake_cpuworker_queue, fake_work_queue_ent_t *, ent, {
+ enum workqueue_reply_t r = ent->fn(NULL, ent->arg);
+ if (r != WQ_RPL_REPLY)
+ return -1;
+ });
+ return 0;
+}
+static void
+mock_cpuworker_handle_replies(void)
+{
+ if (! fake_cpuworker_queue)
+ return;
+ SMARTLIST_FOREACH(fake_cpuworker_queue, fake_work_queue_ent_t *, ent, {
+ ent->reply_fn(ent->arg);
+ tor_free(ent);
+ });
+ smartlist_free(fake_cpuworker_queue);
+ fake_cpuworker_queue = NULL;
+}
+
+// ============================== Other helpers
+
+static consdiff_status_t
+lookup_diff_from(consensus_cache_entry_t **out,
+ consensus_flavor_t flav,
+ const char *str1)
+{
+ uint8_t digest[DIGEST256_LEN];
+ crypto_digest256((char*)digest, str1, strlen(str1), DIGEST_SHA3_256);
+ return consdiffmgr_find_diff_from(out, flav,
+ DIGEST_SHA3_256, digest, sizeof(digest),
+ NO_METHOD);
+}
+
+static int
+lookup_apply_and_verify_diff(consensus_flavor_t flav,
+ const char *str1,
+ const char *str2)
+{
+ consensus_cache_entry_t *ent = NULL;
+ consdiff_status_t status = lookup_diff_from(&ent, flav, str1);
+ if (ent == NULL || status != CONSDIFF_AVAILABLE)
+ return -1;
+
+ consensus_cache_entry_incref(ent);
+ size_t size;
+ char *diff_string = NULL;
+ int r = uncompress_or_copy(&diff_string, &size, ent);
+ consensus_cache_entry_decref(ent);
+ if (diff_string == NULL || r < 0)
+ return -1;
+
+ char *applied = consensus_diff_apply(str1, diff_string);
+ tor_free(diff_string);
+ if (applied == NULL)
+ return -1;
+
+ int match = !strcmp(applied, str2);
+ tor_free(applied);
+ return match ? 0 : -1;
+}
+
+static void
+cdm_reload(void)
+{
+ consdiffmgr_free_all();
+ cdm_cache_get();
+ consdiffmgr_rescan();
+}
+
+// ============================== Beginning of tests
+
+#if 0
+static int got_failure = 0;
+static void
+got_assertion_failure(void)
+{
+ ++got_failure;
+}
+
+/* XXXX This test won't work, because there is currently no way to actually
+ * XXXX capture a real assertion failure. */
+static void
+test_consdiffmgr_init_failure(void *arg)
+{
+ (void)arg;
+ // Capture assertions and bugs.
+
+ /* As in ...test_setup, but do not create the datadir. The missing directory
+ * will cause a failure. */
+ char *ddir_fname = tor_strdup(get_fname_rnd("datadir_cdm"));
+ tor_free(get_options_mutable()->DataDirectory);
+ get_options_mutable()->DataDirectory = ddir_fname; // now owns the pointer.
+
+ consdiff_cfg_t consdiff_cfg = { 7200, 300 };
+
+ tor_set_failed_assertion_callback(got_assertion_failure);
+ tor_capture_bugs_(1);
+ consdiffmgr_configure(&consdiff_cfg); // This should fail.
+ tt_int_op(got_failure, OP_EQ, 1);
+ const smartlist_t *bugs = tor_get_captured_bug_log_();
+ tt_int_op(smartlist_len(bugs), OP_EQ, 1);
+
+ done:
+ tor_end_capture_bugs_();
+}
+#endif
+
+static void
+test_consdiffmgr_sha3_helper(void *arg)
+{
+ (void) arg;
+ consensus_cache_t *cache = cdm_cache_get(); // violate abstraction barrier
+ config_line_t *lines = NULL;
+ char *mem_op_hex_tmp = NULL;
+ config_line_prepend(&lines, "good-sha",
+ "F00DF00DF00DF00DF00DF00DF00DF00D"
+ "F00DF00DF00DF00DF00DF00DF00DF00D");
+ config_line_prepend(&lines, "short-sha",
+ "F00DF00DF00DF00DF00DF00DF00DF00D"
+ "F00DF00DF00DF00DF00DF00DF00DF0");
+ config_line_prepend(&lines, "long-sha",
+ "F00DF00DF00DF00DF00DF00DF00DF00D"
+ "F00DF00DF00DF00DF00DF00DF00DF00DF00D");
+ config_line_prepend(&lines, "not-sha",
+ "F00DF00DF00DF00DF00DF00DF00DF00D"
+ "F00DF00DF00DF00DF00DF00DF00DXXXX");
+ consensus_cache_entry_t *ent =
+ consensus_cache_add(cache, lines, (const uint8_t *)"Hi there", 8);
+
+ uint8_t buf[DIGEST256_LEN];
+ tt_int_op(-1, OP_EQ, cdm_entry_get_sha3_value(buf, NULL, "good-sha"));
+ tt_int_op(0, OP_EQ, cdm_entry_get_sha3_value(buf, ent, "good-sha"));
+ test_memeq_hex(buf, "F00DF00DF00DF00DF00DF00DF00DF00D"
+ "F00DF00DF00DF00DF00DF00DF00DF00D");
+
+ tt_int_op(-1, OP_EQ, cdm_entry_get_sha3_value(buf, ent, "missing-sha"));
+ tt_int_op(-2, OP_EQ, cdm_entry_get_sha3_value(buf, ent, "short-sha"));
+ tt_int_op(-2, OP_EQ, cdm_entry_get_sha3_value(buf, ent, "long-sha"));
+ tt_int_op(-2, OP_EQ, cdm_entry_get_sha3_value(buf, ent, "not-sha"));
+
+ done:
+ consensus_cache_entry_decref(ent);
+ config_free_lines(lines);
+ tor_free(mem_op_hex_tmp);
+}
+
+static void
+test_consdiffmgr_add(void *arg)
+{
+ (void) arg;
+ time_t now = approx_time();
+
+ char *body = NULL;
+
+ consensus_cache_entry_t *ent = NULL;
+ networkstatus_t *ns_tmp = fake_ns_new(FLAV_NS, now);
+ const char *dummy = "foo";
+ int r = consdiffmgr_add_consensus(dummy, ns_tmp);
+ tt_int_op(r, OP_EQ, 0);
+
+ /* If we add it again, it won't work */
+ setup_capture_of_logs(LOG_INFO);
+ dummy = "bar";
+ r = consdiffmgr_add_consensus(dummy, ns_tmp);
+ tt_int_op(r, OP_EQ, -1);
+ expect_single_log_msg_containing("We already have a copy of that "
+ "consensus");
+ mock_clean_saved_logs();
+
+ /* But it will work fine if the flavor is different */
+ dummy = "baz";
+ ns_tmp->flavor = FLAV_MICRODESC;
+ r = consdiffmgr_add_consensus(dummy, ns_tmp);
+ tt_int_op(r, OP_EQ, 0);
+
+ /* And it will work fine if the time is different */
+ dummy = "quux";
+ ns_tmp->flavor = FLAV_NS;
+ ns_tmp->valid_after = now - 60;
+ r = consdiffmgr_add_consensus(dummy, ns_tmp);
+ tt_int_op(r, OP_EQ, 0);
+
+ /* If we add one a long long time ago, it will fail. */
+ dummy = "xyzzy";
+ ns_tmp->valid_after = 86400 * 100; /* A few months into 1970 */
+ r = consdiffmgr_add_consensus(dummy, ns_tmp);
+ tt_int_op(r, OP_EQ, -1);
+ expect_single_log_msg_containing("it's too old.");
+
+ /* Try looking up a consensuses. */
+ ent = cdm_cache_lookup_consensus(FLAV_NS, now-60);
+ tt_assert(ent);
+ consensus_cache_entry_incref(ent);
+ size_t s;
+ r = uncompress_or_copy(&body, &s, ent);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(s, OP_EQ, 4);
+ tt_mem_op(body, OP_EQ, "quux", 4);
+
+ /* Try looking up another entry, but fail */
+ tt_assert(NULL == cdm_cache_lookup_consensus(FLAV_MICRODESC, now-60));
+ tt_assert(NULL == cdm_cache_lookup_consensus(FLAV_NS, now-61));
+
+ done:
+ networkstatus_vote_free(ns_tmp);
+ teardown_capture_of_logs();
+ consensus_cache_entry_decref(ent);
+ tor_free(body);
+}
+
+static void
+test_consdiffmgr_make_diffs(void *arg)
+{
+ (void)arg;
+ networkstatus_t *ns = NULL;
+ char *ns_body = NULL, *md_ns_body = NULL, *md_ns_body_2 = NULL;
+ char *applied = NULL, *diff_text = NULL;
+ time_t now = approx_time();
+ int r;
+ consensus_cache_entry_t *diff = NULL;
+ uint8_t md_ns_sha3[DIGEST256_LEN];
+ consdiff_status_t diff_status;
+
+ MOCK(cpuworker_queue_work, mock_cpuworker_queue_work);
+
+ // Try rescan with no consensuses: shouldn't crash or queue work.
+ consdiffmgr_rescan();
+ tt_ptr_op(NULL, OP_EQ, fake_cpuworker_queue);
+
+ // Make two consensuses, 1 hour sec ago.
+ ns = fake_ns_new(FLAV_NS, now-3600);
+ ns_body = fake_ns_body_new(FLAV_NS, now-3600);
+ r = consdiffmgr_add_consensus(ns_body, ns);
+ networkstatus_vote_free(ns);
+ tor_free(ns_body);
+ tt_int_op(r, OP_EQ, 0);
+
+ ns = fake_ns_new(FLAV_MICRODESC, now-3600);
+ md_ns_body = fake_ns_body_new(FLAV_MICRODESC, now-3600);
+ r = consdiffmgr_add_consensus(md_ns_body, ns);
+ crypto_digest256((char*)md_ns_sha3, md_ns_body, strlen(md_ns_body),
+ DIGEST_SHA3_256);
+ networkstatus_vote_free(ns);
+ tt_int_op(r, OP_EQ, 0);
+
+ // No diffs will be generated.
+ consdiffmgr_rescan();
+ tt_ptr_op(NULL, OP_EQ, fake_cpuworker_queue);
+
+ // Add a MD consensus from 45 minutes ago. This should cause one diff
+ // worth of work to get queued.
+ ns = fake_ns_new(FLAV_MICRODESC, now-45*60);
+ md_ns_body_2 = fake_ns_body_new(FLAV_MICRODESC, now-45*60);
+ r = consdiffmgr_add_consensus(md_ns_body_2, ns);
+ networkstatus_vote_free(ns);
+ tt_int_op(r, OP_EQ, 0);
+
+ consdiffmgr_rescan();
+ tt_ptr_op(NULL, OP_NE, fake_cpuworker_queue);
+ tt_int_op(1, OP_EQ, smartlist_len(fake_cpuworker_queue));
+ diff_status = consdiffmgr_find_diff_from(&diff, FLAV_MICRODESC,
+ DIGEST_SHA3_256,
+ md_ns_sha3, DIGEST256_LEN,
+ NO_METHOD);
+ tt_int_op(CONSDIFF_IN_PROGRESS, OP_EQ, diff_status);
+
+ // Now run that process and get the diff.
+ r = mock_cpuworker_run_work();
+ tt_int_op(r, OP_EQ, 0);
+ mock_cpuworker_handle_replies();
+
+ // At this point we should be able to get that diff.
+ diff_status = consdiffmgr_find_diff_from(&diff, FLAV_MICRODESC,
+ DIGEST_SHA3_256,
+ md_ns_sha3, DIGEST256_LEN,
+ NO_METHOD);
+ tt_int_op(CONSDIFF_AVAILABLE, OP_EQ, diff_status);
+ tt_assert(diff);
+
+ /* Make sure applying the diff actually works */
+ const uint8_t *diff_body;
+ size_t diff_size;
+ r = consensus_cache_entry_get_body(diff, &diff_body, &diff_size);
+ tt_int_op(r, OP_EQ, 0);
+ diff_text = tor_memdup_nulterm(diff_body, diff_size);
+ applied = consensus_diff_apply(md_ns_body, diff_text);
+ tt_assert(applied);
+ tt_str_op(applied, OP_EQ, md_ns_body_2);
+
+ /* Rescan again: no more work to do. */
+ consdiffmgr_rescan();
+ tt_ptr_op(NULL, OP_EQ, fake_cpuworker_queue);
+
+ done:
+ tor_free(md_ns_body);
+ tor_free(md_ns_body_2);
+ tor_free(diff_text);
+ tor_free(applied);
+}
+
+static void
+test_consdiffmgr_diff_rules(void *arg)
+{
+ (void)arg;
+#define N 6
+ char *md_body[N], *ns_body[N];
+ networkstatus_t *md_ns[N], *ns_ns[N];
+ uint8_t md_ns_sha3[N][DIGEST256_LEN], ns_ns_sha3[N][DIGEST256_LEN];
+ int i;
+
+ MOCK(cpuworker_queue_work, mock_cpuworker_queue_work);
+
+ /* Create a bunch of consensus things at 15-second intervals. */
+ time_t start = approx_time() - 120;
+ for (i = 0; i < N; ++i) {
+ time_t when = start + i * 15;
+ md_body[i] = fake_ns_body_new(FLAV_MICRODESC, when);
+ ns_body[i] = fake_ns_body_new(FLAV_NS, when);
+ md_ns[i] = fake_ns_new(FLAV_MICRODESC, when);
+ ns_ns[i] = fake_ns_new(FLAV_NS, when);
+ crypto_digest256((char *)md_ns_sha3[i], md_body[i], strlen(md_body[i]),
+ DIGEST_SHA3_256);
+ crypto_digest256((char *)ns_ns_sha3[i], ns_body[i], strlen(ns_body[i]),
+ DIGEST_SHA3_256);
+ }
+
+ /* For the MD consensuses: add 4 of them, and make sure that
+ * diffs are created to one consensus (the most recent) only. */
+ tt_int_op(0, OP_EQ, consdiffmgr_add_consensus(md_body[1], md_ns[1]));
+ tt_int_op(0, OP_EQ, consdiffmgr_add_consensus(md_body[2], md_ns[2]));
+ tt_int_op(0, OP_EQ, consdiffmgr_add_consensus(md_body[3], md_ns[3]));
+ tt_int_op(0, OP_EQ, consdiffmgr_add_consensus(md_body[4], md_ns[4]));
+ consdiffmgr_rescan();
+ tt_ptr_op(NULL, OP_NE, fake_cpuworker_queue);
+ tt_int_op(3, OP_EQ, smartlist_len(fake_cpuworker_queue));
+ tt_int_op(0, OP_EQ, mock_cpuworker_run_work());
+ mock_cpuworker_handle_replies();
+ tt_ptr_op(NULL, OP_EQ, fake_cpuworker_queue);
+
+ /* For the NS consensuses: add 3, generate, and add one older one and
+ * make sure that older one is the only one whose diff is generated */
+ tt_int_op(0, OP_EQ, consdiffmgr_add_consensus(ns_body[0], ns_ns[0]));
+ tt_int_op(0, OP_EQ, consdiffmgr_add_consensus(ns_body[1], ns_ns[1]));
+ tt_int_op(0, OP_EQ, consdiffmgr_add_consensus(ns_body[5], ns_ns[5]));
+ consdiffmgr_rescan();
+ tt_ptr_op(NULL, OP_NE, fake_cpuworker_queue);
+ tt_int_op(2, OP_EQ, smartlist_len(fake_cpuworker_queue));
+ tt_int_op(0, OP_EQ, mock_cpuworker_run_work());
+ mock_cpuworker_handle_replies();
+
+ /* At this point, we should actually have working diffs! */
+ tt_int_op(0, OP_EQ,
+ lookup_apply_and_verify_diff(FLAV_NS, ns_body[0], ns_body[5]));
+ tt_int_op(0, OP_EQ,
+ lookup_apply_and_verify_diff(FLAV_NS, ns_body[1], ns_body[5]));
+
+ tt_int_op(0, OP_EQ,
+ lookup_apply_and_verify_diff(FLAV_MICRODESC, md_body[1], md_body[4]));
+ tt_int_op(0, OP_EQ,
+ lookup_apply_and_verify_diff(FLAV_MICRODESC, md_body[2], md_body[4]));
+ tt_int_op(0, OP_EQ,
+ lookup_apply_and_verify_diff(FLAV_MICRODESC, md_body[3], md_body[4]));
+
+ /* Self-to-self diff won't be present */
+ consensus_cache_entry_t *ent;
+ tt_int_op(CONSDIFF_NOT_FOUND, OP_EQ,
+ lookup_diff_from(&ent, FLAV_NS, ns_body[5]));
+ /* No diff from 2 has been added yet */
+ tt_int_op(CONSDIFF_NOT_FOUND, OP_EQ,
+ lookup_diff_from(&ent, FLAV_NS, ns_body[2]));
+ /* No diff arriving at old things. */
+ tt_int_op(-1, OP_EQ,
+ lookup_apply_and_verify_diff(FLAV_MICRODESC, md_body[1], md_body[2]));
+ /* No backwards diff */
+ tt_int_op(-1, OP_EQ,
+ lookup_apply_and_verify_diff(FLAV_MICRODESC, md_body[4], md_body[3]));
+
+ /* Now, an update: add number 2 and make sure it's the only one whose diff
+ * is regenerated. */
+ tt_int_op(0, OP_EQ, consdiffmgr_add_consensus(ns_body[2], ns_ns[2]));
+ consdiffmgr_rescan();
+ tt_ptr_op(NULL, OP_NE, fake_cpuworker_queue);
+ tt_int_op(1, OP_EQ, smartlist_len(fake_cpuworker_queue));
+ tt_int_op(0, OP_EQ, mock_cpuworker_run_work());
+ mock_cpuworker_handle_replies();
+
+ tt_int_op(0, OP_EQ,
+ lookup_apply_and_verify_diff(FLAV_NS, ns_body[2], ns_body[5]));
+
+ /* Finally: reload, and make sure that the information is still indexed */
+ cdm_reload();
+
+ tt_int_op(0, OP_EQ,
+ lookup_apply_and_verify_diff(FLAV_NS, ns_body[0], ns_body[5]));
+ tt_int_op(0, OP_EQ,
+ lookup_apply_and_verify_diff(FLAV_NS, ns_body[2], ns_body[5]));
+ tt_int_op(0, OP_EQ,
+ lookup_apply_and_verify_diff(FLAV_NS, ns_body[1], ns_body[5]));
+
+ tt_int_op(0, OP_EQ,
+ lookup_apply_and_verify_diff(FLAV_MICRODESC, md_body[1], md_body[4]));
+ tt_int_op(0, OP_EQ,
+ lookup_apply_and_verify_diff(FLAV_MICRODESC, md_body[2], md_body[4]));
+ tt_int_op(0, OP_EQ,
+ lookup_apply_and_verify_diff(FLAV_MICRODESC, md_body[3], md_body[4]));
+
+ done:
+ for (i = 0; i < N; ++i) {
+ tor_free(md_body[i]);
+ tor_free(ns_body[i]);
+ networkstatus_vote_free(md_ns[i]);
+ networkstatus_vote_free(ns_ns[i]);
+ }
+ UNMOCK(cpuworker_queue_work);
+#undef N
+}
+
+static void
+test_consdiffmgr_diff_failure(void *arg)
+{
+ (void)arg;
+ MOCK(cpuworker_queue_work, mock_cpuworker_queue_work);
+
+ /* We're going to make sure that if we have a bogus request where
+ * we can't actually compute a diff, the world must not end. */
+ networkstatus_t *ns1 = NULL;
+ networkstatus_t *ns2 = NULL;
+ int r;
+
+ ns1 = fake_ns_new(FLAV_NS, approx_time()-100);
+ ns2 = fake_ns_new(FLAV_NS, approx_time()-50);
+ r = consdiffmgr_add_consensus("foo bar baz\n", ns1);
+ tt_int_op(r, OP_EQ, 0);
+ // We refuse to compute a diff to or from a line holding only a single dot.
+ // We can add it here, though.
+ r = consdiffmgr_add_consensus("foo bar baz\n.\n.\n", ns2);
+ tt_int_op(r, OP_EQ, 0);
+
+ consdiffmgr_rescan();
+ tt_ptr_op(NULL, OP_NE, fake_cpuworker_queue);
+ setup_capture_of_logs(LOG_WARN);
+ tt_int_op(1, OP_EQ, smartlist_len(fake_cpuworker_queue));
+ tt_int_op(0, OP_EQ, mock_cpuworker_run_work());
+ expect_single_log_msg_containing("one of the lines to be added is \".\".");
+ mock_clean_saved_logs();
+ mock_cpuworker_handle_replies();
+ expect_single_log_msg_containing("Worker was unable to compute consensus "
+ "diff from ");
+
+ /* Make sure the diff is not present */
+ consensus_cache_entry_t *ent;
+ tt_int_op(CONSDIFF_NOT_FOUND, OP_EQ,
+ lookup_diff_from(&ent, FLAV_NS, "foo bar baz\n"));
+
+ done:
+ teardown_capture_of_logs();
+ UNMOCK(cpuworker_queue_work);
+ networkstatus_vote_free(ns1);
+ networkstatus_vote_free(ns2);
+}
+
+static void
+test_consdiffmgr_diff_pending(void *arg)
+{
+#define N 3
+ (void)arg;
+ char *md_body[N];
+ networkstatus_t *md_ns[N];
+ time_t start = approx_time() - 120;
+ int i;
+ for (i = 0; i < N; ++i) {
+ time_t when = start + i * 30;
+ md_body[i] = fake_ns_body_new(FLAV_MICRODESC, when);
+ md_ns[i] = fake_ns_new(FLAV_MICRODESC, when);
+ }
+
+ MOCK(cpuworker_queue_work, mock_cpuworker_queue_work);
+
+ tt_int_op(0, OP_EQ, consdiffmgr_add_consensus(md_body[1], md_ns[1]));
+ tt_int_op(0, OP_EQ, consdiffmgr_add_consensus(md_body[2], md_ns[2]));
+ /* Make a diff */
+ consdiffmgr_rescan();
+ tt_int_op(1, OP_EQ, smartlist_len(fake_cpuworker_queue));
+
+ /* Look it up. Is it pending? */
+ consensus_cache_entry_t *ent = NULL;
+ consdiff_status_t diff_status;
+ diff_status = lookup_diff_from(&ent, FLAV_MICRODESC, md_body[1]);
+ tt_int_op(CONSDIFF_IN_PROGRESS, OP_EQ, diff_status);
+ tt_ptr_op(ent, OP_EQ, NULL);
+
+ /* Add another old consensus. only one new diff should launch! */
+ tt_int_op(0, OP_EQ, consdiffmgr_add_consensus(md_body[0], md_ns[0]));
+ consdiffmgr_rescan();
+ tt_int_op(2, OP_EQ, smartlist_len(fake_cpuworker_queue));
+
+ tt_int_op(0, OP_EQ, mock_cpuworker_run_work());
+ mock_cpuworker_handle_replies();
+
+ tt_int_op(0, OP_EQ,
+ lookup_apply_and_verify_diff(FLAV_MICRODESC, md_body[0], md_body[2]));
+ tt_int_op(0, OP_EQ,
+ lookup_apply_and_verify_diff(FLAV_MICRODESC, md_body[1], md_body[2]));
+
+ done:
+ UNMOCK(cpuworker_queue_work);
+ for (i = 0; i < N; ++i) {
+ tor_free(md_body[i]);
+ networkstatus_vote_free(md_ns[i]);
+ }
+#undef N
+}
+
+static void
+test_consdiffmgr_cleanup_old(void *arg)
+{
+ (void)arg;
+ config_line_t *labels = NULL;
+ consensus_cache_entry_t *ent = NULL;
+ consensus_cache_t *cache = cdm_cache_get(); // violate abstraction barrier
+
+ /* This item will be will be cleanable because it has a valid-after
+ * time far in the past. */
+ config_line_prepend(&labels, "document-type", "confribble-blarg");
+ config_line_prepend(&labels, "consensus-valid-after",
+ "1980-10-10T10:10:10");
+ ent = consensus_cache_add(cache, labels, (const uint8_t*)"Foo", 3);
+ tt_assert(ent);
+ consensus_cache_entry_decref(ent);
+
+ setup_capture_of_logs(LOG_DEBUG);
+ tt_int_op(1, OP_EQ, consdiffmgr_cleanup());
+ expect_log_msg_containing("Deleting entry because its consensus-valid-"
+ "after value (1980-10-10T10:10:10) was too old");
+
+ done:
+ teardown_capture_of_logs();
+ config_free_lines(labels);
+}
+
+static void
+test_consdiffmgr_cleanup_bad_valid_after(void *arg)
+{
+ /* This will seem cleanable, but isn't, because its valid-after time is
+ * misformed. */
+
+ (void)arg;
+ config_line_t *labels = NULL;
+ consensus_cache_entry_t *ent = NULL;
+ consensus_cache_t *cache = cdm_cache_get(); // violate abstraction barrier
+
+ config_line_prepend(&labels, "document-type", "consensus");
+ config_line_prepend(&labels, "consensus-valid-after",
+ "whan that aprille with his shoures soote"); // (~1385?)
+ ent = consensus_cache_add(cache, labels, (const uint8_t*)"Foo", 3);
+ tt_assert(ent);
+ consensus_cache_entry_decref(ent);
+
+ setup_capture_of_logs(LOG_DEBUG);
+ tt_int_op(0, OP_EQ, consdiffmgr_cleanup());
+ expect_log_msg_containing("Ignoring entry because its consensus-valid-"
+ "after value (\"whan that aprille with his "
+ "shoures soote\") was unparseable");
+
+ done:
+ teardown_capture_of_logs();
+ config_free_lines(labels);
+}
+
+static void
+test_consdiffmgr_cleanup_no_valid_after(void *arg)
+{
+ (void)arg;
+ config_line_t *labels = NULL;
+ consensus_cache_entry_t *ent = NULL;
+ consensus_cache_t *cache = cdm_cache_get(); // violate abstraction barrier
+
+ /* This item will be will be uncleanable because it has no recognized
+ * valid-after. */
+ config_line_prepend(&labels, "document-type", "consensus");
+ config_line_prepend(&labels, "confrooble-voolid-oofter",
+ "2010-10-10T09:08:07");
+ ent = consensus_cache_add(cache, labels, (const uint8_t*)"Foo", 3);
+ tt_assert(ent);
+ consensus_cache_entry_decref(ent);
+
+ setup_capture_of_logs(LOG_DEBUG);
+ tt_int_op(0, OP_EQ, consdiffmgr_cleanup());
+ expect_log_msg_containing("Ignoring entry because it had no consensus-"
+ "valid-after label");
+
+ done:
+ teardown_capture_of_logs();
+ config_free_lines(labels);
+}
+
+static void
+test_consdiffmgr_cleanup_old_diffs(void *arg)
+{
+ (void)arg;
+#define N 4
+ char *md_body[N];
+ networkstatus_t *md_ns[N];
+ uint8_t md_ns_sha3[N][DIGEST256_LEN];
+ int i;
+ consensus_cache_entry_t *hold_ent = NULL, *ent;
+
+ /* Make sure that the cleanup function removes diffs to the not-most-recent
+ * consensus. */
+
+ MOCK(cpuworker_queue_work, mock_cpuworker_queue_work);
+
+ /* Create a bunch of consensus things at 15-second intervals. */
+ time_t start = approx_time() - 120;
+ for (i = 0; i < N; ++i) {
+ time_t when = start + i * 15;
+ md_body[i] = fake_ns_body_new(FLAV_MICRODESC, when);
+ md_ns[i] = fake_ns_new(FLAV_MICRODESC, when);
+ crypto_digest256((char *)md_ns_sha3[i], md_body[i], strlen(md_body[i]),
+ DIGEST_SHA3_256);
+ }
+
+ /* add the first 3. */
+ tt_int_op(0, OP_EQ, consdiffmgr_add_consensus(md_body[0], md_ns[0]));
+ tt_int_op(0, OP_EQ, consdiffmgr_add_consensus(md_body[1], md_ns[1]));
+ tt_int_op(0, OP_EQ, consdiffmgr_add_consensus(md_body[2], md_ns[2]));
+ /* Make diffs. */
+ consdiffmgr_rescan();
+ tt_ptr_op(NULL, OP_NE, fake_cpuworker_queue);
+ tt_int_op(2, OP_EQ, smartlist_len(fake_cpuworker_queue));
+ tt_int_op(0, OP_EQ, mock_cpuworker_run_work());
+ mock_cpuworker_handle_replies();
+ tt_ptr_op(NULL, OP_EQ, fake_cpuworker_queue);
+
+ /* Nothing is deletable now */
+ tt_int_op(0, OP_EQ, consdiffmgr_cleanup());
+ tt_int_op(0, OP_EQ,
+ lookup_apply_and_verify_diff(FLAV_MICRODESC, md_body[0], md_body[2]));
+ tt_int_op(0, OP_EQ,
+ lookup_apply_and_verify_diff(FLAV_MICRODESC, md_body[1], md_body[2]));
+
+ tt_int_op(CONSDIFF_AVAILABLE, OP_EQ,
+ lookup_diff_from(&hold_ent, FLAV_MICRODESC, md_body[1]));
+ consensus_cache_entry_incref(hold_ent); // incref, so it is preserved.
+
+ /* Now add an even-more-recent consensus; this should make all previous
+ * diffs deletable */
+ tt_int_op(0, OP_EQ, consdiffmgr_add_consensus(md_body[3], md_ns[3]));
+ tt_int_op(2 * n_diff_compression_methods(), OP_EQ, consdiffmgr_cleanup());
+
+ tt_int_op(CONSDIFF_NOT_FOUND, OP_EQ,
+ lookup_diff_from(&ent, FLAV_MICRODESC, md_body[0]));
+ /* This one is marked deletable but still in the hashtable */
+ tt_int_op(CONSDIFF_AVAILABLE, OP_EQ,
+ lookup_diff_from(&ent, FLAV_MICRODESC, md_body[1]));
+ tt_int_op(CONSDIFF_NOT_FOUND, OP_EQ,
+ lookup_diff_from(&ent, FLAV_MICRODESC, md_body[2]));
+
+ /* Everything should be valid at this point */
+ tt_int_op(0, OP_EQ, consdiffmgr_validate());
+
+ /* And if we recan NOW, we'll purge the hashtable of the entries,
+ * and launch attempts to generate new ones */
+ consdiffmgr_rescan();
+ tt_int_op(CONSDIFF_IN_PROGRESS, OP_EQ,
+ lookup_diff_from(&ent, FLAV_MICRODESC, md_body[0]));
+ tt_int_op(CONSDIFF_IN_PROGRESS, OP_EQ,
+ lookup_diff_from(&ent, FLAV_MICRODESC, md_body[1]));
+ tt_int_op(CONSDIFF_IN_PROGRESS, OP_EQ,
+ lookup_diff_from(&ent, FLAV_MICRODESC, md_body[2]));
+
+ /* We're still holding on to this, though, so we can still map it! */
+ const uint8_t *t1 = NULL;
+ size_t s;
+ int r = consensus_cache_entry_get_body(hold_ent, &t1, &s);
+ tt_int_op(r, OP_EQ, 0);
+ tt_assert(t1);
+
+ done:
+ for (i = 0; i < N; ++i) {
+ tor_free(md_body[i]);
+ networkstatus_vote_free(md_ns[i]);
+ }
+ consensus_cache_entry_decref(hold_ent);
+ UNMOCK(cpuworker_queue_work);
+#undef N
+}
+
+static void
+test_consdiffmgr_validate(void *arg)
+{
+ (void)arg;
+ config_line_t *lines = NULL;
+ consensus_cache_entry_t *ent = NULL;
+ consensus_cache_t *cache = cdm_cache_get(); // violate abstraction barrier
+ smartlist_t *vals = smartlist_new();
+
+ /* Put these: objects in the cache: one with a good sha3, one with bad sha3,
+ * one with a wrong sha3, and one with no sha3. */
+ config_line_prepend(&lines, "id", "wrong sha3");
+ config_line_prepend(&lines, "sha3-digest",
+ "F00DF00DF00DF00DF00DF00DF00DF00D"
+ "F00DF00DF00DF00DF00DF00DF00DF00D");
+ ent = consensus_cache_add(cache, lines, (const uint8_t *)"Hi there", 8);
+ consensus_cache_entry_decref(ent);
+ config_free_lines(lines);
+ lines = NULL;
+
+ config_line_prepend(&lines, "id", "bad sha3");
+ config_line_prepend(&lines, "sha3-digest",
+ "now is the winter of our dicotheque");
+ ent = consensus_cache_add(cache, lines, (const uint8_t *)"Hi there", 8);
+ consensus_cache_entry_decref(ent);
+ config_free_lines(lines);
+ lines = NULL;
+
+ config_line_prepend(&lines, "id", "no sha3");
+ ent = consensus_cache_add(cache, lines, (const uint8_t *)"Hi there", 8);
+ consensus_cache_entry_decref(ent);
+ config_free_lines(lines);
+ lines = NULL;
+
+ config_line_prepend(&lines, "id", "good sha3");
+ config_line_prepend(&lines, "sha3-digest",
+ "8d8b1998616cd6b4c4055da8d38728dc"
+ "93c758d4131a53c7d81aa6337dee1c05");
+ ent = consensus_cache_add(cache, lines, (const uint8_t *)"Hi there", 8);
+ consensus_cache_entry_decref(ent);
+ config_free_lines(lines);
+ lines = NULL;
+
+ cdm_reload();
+ cache = cdm_cache_get();
+ tt_int_op(1, OP_EQ, consdiffmgr_validate());
+
+ consensus_cache_find_all(vals, cache, "id", "good sha3");
+ tt_int_op(smartlist_len(vals), OP_EQ, 1);
+ smartlist_clear(vals);
+
+ consensus_cache_find_all(vals, cache, "id", "no sha3");
+ tt_int_op(smartlist_len(vals), OP_EQ, 1);
+ smartlist_clear(vals);
+
+ consensus_cache_find_all(vals, cache, "id", "wrong sha3");
+ tt_int_op(smartlist_len(vals), OP_EQ, 0);
+ consensus_cache_find_all(vals, cache, "id", "bad sha3");
+ tt_int_op(smartlist_len(vals), OP_EQ, 0);
+
+ done:
+ smartlist_free(vals);
+}
+
+#define TEST(name) \
+ { #name, test_consdiffmgr_ ## name , TT_FORK, &setup_diffmgr, NULL }
+
+struct testcase_t consdiffmgr_tests[] = {
+#if 0
+ { "init_failure", test_consdiffmgr_init_failure, TT_FORK, NULL, NULL },
+#endif
+ TEST(sha3_helper),
+ TEST(add),
+ TEST(make_diffs),
+ TEST(diff_rules),
+ TEST(diff_failure),
+ TEST(diff_pending),
+ TEST(cleanup_old),
+ TEST(cleanup_bad_valid_after),
+ TEST(cleanup_no_valid_after),
+ TEST(cleanup_old_diffs),
+ TEST(validate),
+
+ // XXXX Test: non-cacheing cases of replyfn().
+
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_containers.c b/src/test/test_containers.c
index 41f3f873de..54484a2a91 100644
--- a/src/test/test_containers.c
+++ b/src/test/test_containers.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2016, The Tor Project, Inc. */
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_controller.c b/src/test/test_controller.c
index 206315e289..592f91a988 100644
--- a/src/test/test_controller.c
+++ b/src/test/test_controller.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Tor Project, Inc. */
+/* Copyright (c) 2015-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CONTROL_PRIVATE
diff --git a/src/test/test_controller_events.c b/src/test/test_controller_events.c
index 11e1e3dc8f..901ad7ab3d 100644
--- a/src/test/test_controller_events.c
+++ b/src/test/test_controller_events.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2016, The Tor Project, Inc. */
+/* Copyright (c) 2013-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CONNECTION_PRIVATE
diff --git a/src/test/test_crypto.c b/src/test/test_crypto.c
index d66ddccd4f..ec9d4e2709 100644
--- a/src/test/test_crypto.c
+++ b/src/test/test_crypto.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2016, The Tor Project, Inc. */
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -15,9 +15,6 @@
#include "crypto_ed25519.h"
#include "ed25519_vectors.inc"
-#include <openssl/evp.h>
-#include <openssl/rand.h>
-
/** Run unit tests for Diffie-Hellman functionality. */
static void
test_crypto_dh(void *arg)
@@ -331,38 +328,6 @@ test_crypto_rng_strongest(void *arg)
#undef N
}
-/* Test for rectifying openssl RAND engine. */
-static void
-test_crypto_rng_engine(void *arg)
-{
- (void)arg;
- RAND_METHOD dummy_method;
- memset(&dummy_method, 0, sizeof(dummy_method));
-
- /* We should be a no-op if we're already on RAND_OpenSSL */
- tt_int_op(0, ==, crypto_force_rand_ssleay());
- tt_assert(RAND_get_rand_method() == RAND_OpenSSL());
-
- /* We should correct the method if it's a dummy. */
- RAND_set_rand_method(&dummy_method);
-#ifdef LIBRESSL_VERSION_NUMBER
- /* On libressl, you can't override the RNG. */
- tt_assert(RAND_get_rand_method() == RAND_OpenSSL());
- tt_int_op(0, ==, crypto_force_rand_ssleay());
-#else
- tt_assert(RAND_get_rand_method() == &dummy_method);
- tt_int_op(1, ==, crypto_force_rand_ssleay());
-#endif
- tt_assert(RAND_get_rand_method() == RAND_OpenSSL());
-
- /* Make sure we aren't calling dummy_method */
- crypto_rand((void *) &dummy_method, sizeof(dummy_method));
- crypto_rand((void *) &dummy_method, sizeof(dummy_method));
-
- done:
- ;
-}
-
/** Run unit tests for our AES128 functionality */
static void
test_crypto_aes128(void *arg)
@@ -1477,28 +1442,6 @@ test_crypto_digest_names(void *arg)
;
}
-#ifndef OPENSSL_1_1_API
-#define EVP_ENCODE_CTX_new() tor_malloc_zero(sizeof(EVP_ENCODE_CTX))
-#define EVP_ENCODE_CTX_free(ctx) tor_free(ctx)
-#endif
-
-/** Encode src into dest with OpenSSL's EVP Encode interface, returning the
- * length of the encoded data in bytes.
- */
-static int
-base64_encode_evp(char *dest, char *src, size_t srclen)
-{
- const unsigned char *s = (unsigned char*)src;
- EVP_ENCODE_CTX *ctx = EVP_ENCODE_CTX_new();
- int len, ret;
-
- EVP_EncodeInit(ctx);
- EVP_EncodeUpdate(ctx, (unsigned char *)dest, &len, s, (int)srclen);
- EVP_EncodeFinal(ctx, (unsigned char *)(dest + len), &ret);
- EVP_ENCODE_CTX_free(ctx);
- return ret+ len;
-}
-
/** Run unit tests for misc crypto formatting functionality (base64, base32,
* fingerprints, etc) */
static void
@@ -1527,7 +1470,7 @@ test_crypto_formats(void *arg)
tt_int_op(i, OP_GE, 0);
tt_int_op(i, OP_EQ, strlen(data2));
tt_assert(! strchr(data2, '='));
- j = base64_decode_nopad((uint8_t*)data3, 1024, data2, i);
+ j = base64_decode(data3, 1024, data2, i);
tt_int_op(j, OP_EQ, idx);
tt_mem_op(data3,OP_EQ, data1, idx);
}
@@ -1554,20 +1497,6 @@ test_crypto_formats(void *arg)
tt_assert(digest_from_base64(data3, "###") < 0);
- for (i = 0; i < 256; i++) {
- /* Test the multiline format Base64 encoder with 0 .. 256 bytes of
- * output against OpenSSL.
- */
- const size_t enclen = base64_encode_size(i, BASE64_ENCODE_MULTILINE);
- data1[i] = i;
- j = base64_encode(data2, 1024, data1, i, BASE64_ENCODE_MULTILINE);
- tt_int_op(j, OP_EQ, enclen);
- j = base64_encode_evp(data3, data1, i);
- tt_int_op(j, OP_EQ, enclen);
- tt_mem_op(data2, OP_EQ, data3, enclen);
- tt_int_op(j, OP_EQ, strlen(data2));
- }
-
/* Encoding SHA256 */
crypto_rand(data2, DIGEST256_LEN);
memset(data2, 100, 1024);
@@ -2941,7 +2870,6 @@ struct testcase_t crypto_tests[] = {
CRYPTO_LEGACY(formats),
CRYPTO_LEGACY(rng),
{ "rng_range", test_crypto_rng_range, 0, NULL, NULL },
- { "rng_engine", test_crypto_rng_engine, TT_FORK, NULL, NULL },
{ "rng_strongest", test_crypto_rng_strongest, TT_FORK, NULL, NULL },
{ "rng_strongest_nosyscall", test_crypto_rng_strongest, TT_FORK,
&passthrough_setup, (void*)"nosyscall" },
diff --git a/src/test/test_crypto_openssl.c b/src/test/test_crypto_openssl.c
new file mode 100644
index 0000000000..3d7d2b4639
--- /dev/null
+++ b/src/test/test_crypto_openssl.c
@@ -0,0 +1,107 @@
+/* Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+
+#define CRYPTO_PRIVATE
+
+#include "crypto.h"
+#include "util.h"
+#include "util_format.h"
+#include "compat.h"
+#include "test.h"
+
+#include <openssl/evp.h>
+#include <openssl/rand.h>
+#include "compat_openssl.h"
+
+/* Test for rectifying openssl RAND engine. */
+static void
+test_crypto_rng_engine(void *arg)
+{
+ (void)arg;
+ RAND_METHOD dummy_method;
+ memset(&dummy_method, 0, sizeof(dummy_method));
+
+ /* We should be a no-op if we're already on RAND_OpenSSL */
+ tt_int_op(0, ==, crypto_force_rand_ssleay());
+ tt_assert(RAND_get_rand_method() == RAND_OpenSSL());
+
+ /* We should correct the method if it's a dummy. */
+ RAND_set_rand_method(&dummy_method);
+#ifdef LIBRESSL_VERSION_NUMBER
+ /* On libressl, you can't override the RNG. */
+ tt_assert(RAND_get_rand_method() == RAND_OpenSSL());
+ tt_int_op(0, ==, crypto_force_rand_ssleay());
+#else
+ tt_assert(RAND_get_rand_method() == &dummy_method);
+ tt_int_op(1, ==, crypto_force_rand_ssleay());
+#endif
+ tt_assert(RAND_get_rand_method() == RAND_OpenSSL());
+
+ /* Make sure we aren't calling dummy_method */
+ crypto_rand((void *) &dummy_method, sizeof(dummy_method));
+ crypto_rand((void *) &dummy_method, sizeof(dummy_method));
+
+ done:
+ ;
+}
+
+#ifndef OPENSSL_1_1_API
+#define EVP_ENCODE_CTX_new() tor_malloc_zero(sizeof(EVP_ENCODE_CTX))
+#define EVP_ENCODE_CTX_free(ctx) tor_free(ctx)
+#endif
+
+/** Encode src into dest with OpenSSL's EVP Encode interface, returning the
+ * length of the encoded data in bytes.
+ */
+static int
+base64_encode_evp(char *dest, char *src, size_t srclen)
+{
+ const unsigned char *s = (unsigned char*)src;
+ EVP_ENCODE_CTX *ctx = EVP_ENCODE_CTX_new();
+ int len, ret;
+
+ EVP_EncodeInit(ctx);
+ EVP_EncodeUpdate(ctx, (unsigned char *)dest, &len, s, (int)srclen);
+ EVP_EncodeFinal(ctx, (unsigned char *)(dest + len), &ret);
+ EVP_ENCODE_CTX_free(ctx);
+ return ret+ len;
+}
+
+static void
+test_crypto_base64_encode_matches(void *arg)
+{
+ (void)arg;
+ int i, j;
+ char data1[1024];
+ char data2[1024];
+ char data3[1024];
+
+ for (i = 0; i < 256; i++) {
+ /* Test the multiline format Base64 encoder with 0 .. 256 bytes of
+ * output against OpenSSL.
+ */
+ const size_t enclen = base64_encode_size(i, BASE64_ENCODE_MULTILINE);
+ data1[i] = i;
+ j = base64_encode(data2, 1024, data1, i, BASE64_ENCODE_MULTILINE);
+ tt_int_op(j, OP_EQ, enclen);
+ j = base64_encode_evp(data3, data1, i);
+ tt_int_op(j, OP_EQ, enclen);
+ tt_mem_op(data2, OP_EQ, data3, enclen);
+ tt_int_op(j, OP_EQ, strlen(data2));
+ }
+
+ done:
+ ;
+}
+
+struct testcase_t crypto_openssl_tests[] = {
+ { "rng_engine", test_crypto_rng_engine, TT_FORK, NULL, NULL },
+ { "base64_encode_match", test_crypto_base64_encode_matches,
+ TT_FORK, NULL, NULL },
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_crypto_slow.c b/src/test/test_crypto_slow.c
index 0d7d65ac73..d6b0a43dd5 100644
--- a/src/test/test_crypto_slow.c
+++ b/src/test/test_crypto_slow.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2016, The Tor Project, Inc. */
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -12,11 +12,8 @@
#if defined(HAVE_LIBSCRYPT_H) && defined(HAVE_LIBSCRYPT_SCRYPT)
#define HAVE_LIBSCRYPT
-#include <libscrypt.h>
#endif
-#include <openssl/evp.h>
-
/** Run unit tests for our secret-to-key passphrase hashing functionality. */
static void
test_crypto_s2k_rfc2440(void *arg)
diff --git a/src/test/test_data.c b/src/test/test_data.c
index 788489a097..ce6c3394f6 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-2016, The Tor Project, Inc. */
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "test.h"
diff --git a/src/test/test_dir.c b/src/test/test_dir.c
index 4e5876fa3c..a9d9cba7df 100644
--- a/src/test/test_dir.c
+++ b/src/test/test_dir.c
@@ -1,12 +1,13 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2016, The Tor Project, Inc. */
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
#include <math.h>
#define CONFIG_PRIVATE
+#define CONTROL_PRIVATE
#define DIRSERV_PRIVATE
#define DIRVOTE_PRIVATE
#define ROUTER_PRIVATE
@@ -19,6 +20,7 @@
#include "or.h"
#include "confparse.h"
#include "config.h"
+#include "control.h"
#include "crypto_ed25519.h"
#include "directory.h"
#include "dirserv.h"
@@ -329,7 +331,7 @@ test_dir_formats(void *arg)
ntor_cc = make_ntor_onion_key_crosscert(&r2_onion_keypair,
&kp1.pubkey,
r2->cache_info.published_on,
- MIN_ONION_KEY_LIFETIME,
+ get_onion_key_lifetime(),
&ntor_cc_sign);
tt_assert(ntor_cc);
base64_encode(cert_buf, sizeof(cert_buf),
@@ -910,6 +912,23 @@ mock_get_by_ei_desc_digest(const char *d)
}
}
+static signed_descriptor_t *
+mock_ei_get_by_ei_digest(const char *d)
+{
+ char hex[HEX_DIGEST_LEN+1];
+ base16_encode(hex, sizeof(hex), d, DIGEST_LEN);
+ signed_descriptor_t *sd = &sd_ei_minimal;
+
+ if (!strcmp(hex, "11E0EDF526950739F7769810FCACAB8C882FAEEE")) {
+ sd->signed_descriptor_body = (char *)EX_EI_MINIMAL;
+ sd->signed_descriptor_len = sizeof(EX_EI_MINIMAL);
+ sd->annotations_len = 0;
+ sd->saved_location = SAVED_NOWHERE;
+ return sd;
+ }
+ return NULL;
+}
+
static smartlist_t *mock_ei_insert_list = NULL;
static was_router_added_t
mock_ei_insert(routerlist_t *rl, extrainfo_t *ei, int warn_if_incompatible)
@@ -999,6 +1018,37 @@ test_dir_load_extrainfo(void *arg)
}
static void
+test_dir_getinfo_extra(void *arg)
+{
+ int r;
+ char *answer = NULL;
+ const char *errmsg = NULL;
+
+ (void)arg;
+ MOCK(extrainfo_get_by_descriptor_digest, mock_ei_get_by_ei_digest);
+ r = getinfo_helper_dir(NULL, "extra-info/digest/"
+ "11E0EDF526950739F7769810FCACAB8C882FAEEE", &answer,
+ &errmsg);
+ tt_int_op(0, OP_EQ, r);
+ tt_ptr_op(NULL, OP_EQ, errmsg);
+ tt_str_op(answer, OP_EQ, EX_EI_MINIMAL);
+ tor_free(answer);
+
+ answer = NULL;
+ r = getinfo_helper_dir(NULL, "extra-info/digest/"
+ "NOTAVALIDHEXSTRINGNOTAVALIDHEXSTRINGNOTA", &answer,
+ &errmsg);
+ tt_int_op(0, OP_EQ, r);
+ /* getinfo_helper_dir() should maybe return an error here but doesn't */
+ tt_ptr_op(NULL, OP_EQ, errmsg);
+ /* In any case, there should be no answer for an invalid hex string. */
+ tt_ptr_op(NULL, OP_EQ, answer);
+
+ done:
+ UNMOCK(extrainfo_get_by_descriptor_digest);
+}
+
+static void
test_dir_versions(void *arg)
{
tor_version_t ver1;
@@ -1065,6 +1115,7 @@ test_dir_versions(void *arg)
tt_int_op(0, OP_EQ, ver1.patchlevel);
tt_int_op(VER_RELEASE, OP_EQ, ver1.status);
tt_str_op("alpha", OP_EQ, ver1.status_tag);
+ /* Go through the full set of status tags */
tt_int_op(0, OP_EQ, tor_version_parse("2.1.700-alpha", &ver1));
tt_int_op(2, OP_EQ, ver1.major);
tt_int_op(1, OP_EQ, ver1.minor);
@@ -1079,6 +1130,60 @@ test_dir_versions(void *arg)
tt_int_op(0, OP_EQ, ver1.patchlevel);
tt_int_op(VER_RELEASE, OP_EQ, ver1.status);
tt_str_op("alpha-dev", OP_EQ, ver1.status_tag);
+ tt_int_op(0, OP_EQ, tor_version_parse("0.2.9.5-rc", &ver1));
+ tt_int_op(0, OP_EQ, ver1.major);
+ tt_int_op(2, OP_EQ, ver1.minor);
+ tt_int_op(9, OP_EQ, ver1.micro);
+ tt_int_op(5, OP_EQ, ver1.patchlevel);
+ tt_int_op(VER_RELEASE, OP_EQ, ver1.status);
+ tt_str_op("rc", OP_EQ, ver1.status_tag);
+ tt_int_op(0, OP_EQ, tor_version_parse("0.2.9.6-rc-dev", &ver1));
+ tt_int_op(0, OP_EQ, ver1.major);
+ tt_int_op(2, OP_EQ, ver1.minor);
+ tt_int_op(9, OP_EQ, ver1.micro);
+ tt_int_op(6, OP_EQ, ver1.patchlevel);
+ tt_int_op(VER_RELEASE, OP_EQ, ver1.status);
+ tt_str_op("rc-dev", OP_EQ, ver1.status_tag);
+ tt_int_op(0, OP_EQ, tor_version_parse("0.2.9.8", &ver1));
+ tt_int_op(0, OP_EQ, ver1.major);
+ tt_int_op(2, OP_EQ, ver1.minor);
+ tt_int_op(9, OP_EQ, ver1.micro);
+ tt_int_op(8, OP_EQ, ver1.patchlevel);
+ tt_int_op(VER_RELEASE, OP_EQ, ver1.status);
+ tt_str_op("", OP_EQ, ver1.status_tag);
+ tt_int_op(0, OP_EQ, tor_version_parse("0.2.9.9-dev", &ver1));
+ tt_int_op(0, OP_EQ, ver1.major);
+ tt_int_op(2, OP_EQ, ver1.minor);
+ tt_int_op(9, OP_EQ, ver1.micro);
+ tt_int_op(9, OP_EQ, ver1.patchlevel);
+ tt_int_op(VER_RELEASE, OP_EQ, ver1.status);
+ tt_str_op("dev", OP_EQ, ver1.status_tag);
+ /* In #21450, we fixed an inconsistency in parsing versions > INT32_MAX
+ * between i386 and x86_64, as we used tor_parse_long, and then cast to int
+ */
+ tt_int_op(0, OP_EQ, tor_version_parse("0.2147483647.0", &ver1));
+ tt_int_op(0, OP_EQ, ver1.major);
+ tt_int_op(2147483647, OP_EQ, ver1.minor);
+ tt_int_op(0, OP_EQ, ver1.micro);
+ tt_int_op(0, OP_EQ, ver1.patchlevel);
+ tt_int_op(VER_RELEASE, OP_EQ, ver1.status);
+ tt_str_op("", OP_EQ, ver1.status_tag);
+ tt_int_op(-1, OP_EQ, tor_version_parse("0.2147483648.0", &ver1));
+ tt_int_op(-1, OP_EQ, tor_version_parse("0.4294967295.0", &ver1));
+ /* In #21278, we reject negative version components */
+ tt_int_op(-1, OP_EQ, tor_version_parse("0.-1.0", &ver1));
+ tt_int_op(-1, OP_EQ, tor_version_parse("0.-2147483648.0", &ver1));
+ tt_int_op(-1, OP_EQ, tor_version_parse("0.-4294967295.0", &ver1));
+ /* In #21507, we reject version components with non-numeric prefixes */
+ tt_int_op(-1, OP_EQ, tor_version_parse("0.-0.0", &ver1));
+ tt_int_op(-1, OP_EQ, tor_version_parse("+1.0.0", &ver1));
+ /* use the list in isspace() */
+ tt_int_op(-1, OP_EQ, tor_version_parse("0.\t0.0", &ver1));
+ tt_int_op(-1, OP_EQ, tor_version_parse("0.\n0.0", &ver1));
+ tt_int_op(-1, OP_EQ, tor_version_parse("0.\v0.0", &ver1));
+ tt_int_op(-1, OP_EQ, tor_version_parse("0.\f0.0", &ver1));
+ tt_int_op(-1, OP_EQ, tor_version_parse("0.\r0.0", &ver1));
+ tt_int_op(-1, OP_EQ, tor_version_parse("0. 0.0", &ver1));
#define tt_versionstatus_op(vs1, op, vs2) \
tt_assert_test_type(vs1,vs2,#vs1" "#op" "#vs2,version_status_t, \
@@ -1098,6 +1203,7 @@ test_dir_versions(void *arg)
test_v_i_o(VS_RECOMMENDED, "0.0.7rc2", "0.0.7,Tor 0.0.7rc2,Tor 0.0.8");
test_v_i_o(VS_OLD, "0.0.5.0", "0.0.5.1-cvs");
test_v_i_o(VS_NEW_IN_SERIES, "0.0.5.1-cvs", "0.0.5, 0.0.6");
+ test_v_i_o(VS_NEW, "0.2.9.9-dev", "0.2.9.9");
/* Not on list, but newer than any in same series. */
test_v_i_o(VS_NEW_IN_SERIES, "0.1.0.3",
"Tor 0.1.0.2,Tor 0.0.9.5,Tor 0.1.1.0");
@@ -1136,6 +1242,70 @@ test_dir_versions(void *arg)
"Tor 0.2.1.0-dev (r99)"));
tt_int_op(1,OP_EQ, tor_version_as_new_as("Tor 0.2.1.1",
"Tor 0.2.1.0-dev (r99)"));
+ /* And git revisions */
+ tt_int_op(1,OP_EQ, tor_version_as_new_as(
+ "Tor 0.2.9.9 (git-56788a2489127072)",
+ "Tor 0.2.9.9 (git-56788a2489127072)"));
+ /* a git revision is newer than no git revision */
+ tt_int_op(1,OP_EQ, tor_version_as_new_as(
+ "Tor 0.2.9.9 (git-56788a2489127072)",
+ "Tor 0.2.9.9"));
+ /* a longer git revision is newer than a shorter git revision
+ * this should be true if they prefix-match, but if they don't, they are
+ * incomparable, because hashes aren't ordered (but we compare their bytes
+ * anyway) */
+ tt_int_op(1,OP_EQ, tor_version_as_new_as(
+ "Tor 0.2.9.9 (git-56788a2489127072d513cf4baf35a8ff475f3c7b)",
+ "Tor 0.2.9.9 (git-56788a2489127072)"));
+ tt_int_op(1,OP_EQ, tor_version_as_new_as(
+ "Tor 0.2.9.9 (git-0102)",
+ "Tor 0.2.9.9 (git-03)"));
+ tt_int_op(1,OP_EQ, tor_version_as_new_as(
+ "Tor 0.2.9.9 (git-0102)",
+ "Tor 0.2.9.9 (git-00)"));
+ tt_int_op(1,OP_EQ, tor_version_as_new_as(
+ "Tor 0.2.9.9 (git-01)",
+ "Tor 0.2.9.9 (git-00)"));
+ tt_int_op(0,OP_EQ, tor_version_as_new_as(
+ "Tor 0.2.9.9 (git-00)",
+ "Tor 0.2.9.9 (git-01)"));
+ /* In #21278, we comapre without integer overflows.
+ * But since #21450 limits version components to [0, INT32_MAX], it is no
+ * longer possible to cause an integer overflow in tor_version_compare() */
+ tt_int_op(0,OP_EQ, tor_version_as_new_as(
+ "Tor 0.0.0.0",
+ "Tor 2147483647.0.0.0"));
+ tt_int_op(1,OP_EQ, tor_version_as_new_as(
+ "Tor 2147483647.0.0.0",
+ "Tor 0.0.0.0"));
+ /* These versions used to cause an overflow, now they don't parse
+ * (and authorities reject their descriptors), and log a BUG message */
+ setup_full_capture_of_logs(LOG_WARN);
+ tt_int_op(0,OP_EQ, tor_version_as_new_as(
+ "Tor 0.0.0.0",
+ "Tor 0.-2147483648.0.0"));
+ expect_single_log_msg_containing("unparseable");
+ mock_clean_saved_logs();
+ tt_int_op(0,OP_EQ, tor_version_as_new_as(
+ "Tor 0.2147483647.0.0",
+ "Tor 0.-1.0.0"));
+ expect_single_log_msg_containing("unparseable");
+ mock_clean_saved_logs();
+ tt_int_op(0,OP_EQ, tor_version_as_new_as(
+ "Tor 0.2147483647.0.0",
+ "Tor 0.-2147483648.0.0"));
+ expect_single_log_msg_containing("unparseable");
+ mock_clean_saved_logs();
+ tt_int_op(1,OP_EQ, tor_version_as_new_as(
+ "Tor 4294967295.0.0.0",
+ "Tor 0.0.0.0"));
+ expect_no_log_entry();
+ tt_int_op(0,OP_EQ, tor_version_as_new_as(
+ "Tor 0.4294967295.0.0",
+ "Tor 0.-4294967295.0.0"));
+ expect_single_log_msg_containing("unparseable");
+ mock_clean_saved_logs();
+ teardown_capture_of_logs();
/* Now try git revisions */
tt_int_op(0,OP_EQ, tor_version_parse("0.5.6.7 (git-ff00ff)", &ver1));
@@ -1145,11 +1315,24 @@ test_dir_versions(void *arg)
tt_int_op(7,OP_EQ, ver1.patchlevel);
tt_int_op(3,OP_EQ, ver1.git_tag_len);
tt_mem_op(ver1.git_tag,OP_EQ, "\xff\x00\xff", 3);
+ /* reject bad hex digits */
tt_int_op(-1,OP_EQ, tor_version_parse("0.5.6.7 (git-ff00xx)", &ver1));
+ /* reject odd hex digit count */
tt_int_op(-1,OP_EQ, tor_version_parse("0.5.6.7 (git-ff00fff)", &ver1));
+ /* ignore "git " */
tt_int_op(0,OP_EQ, tor_version_parse("0.5.6.7 (git ff00fff)", &ver1));
+ /* standard length is 16 hex digits */
+ tt_int_op(0,OP_EQ, tor_version_parse("0.5.6.7 (git-0010203040506070)",
+ &ver1));
+ /* length limit is 40 hex digits */
+ tt_int_op(0,OP_EQ, tor_version_parse(
+ "0.5.6.7 (git-000102030405060708090a0b0c0d0e0f10111213)",
+ &ver1));
+ tt_int_op(-1,OP_EQ, tor_version_parse(
+ "0.5.6.7 (git-000102030405060708090a0b0c0d0e0f1011121314)",
+ &ver1));
done:
- ;
+ teardown_capture_of_logs();
}
/** Run unit tests for directory fp_pair functions. */
@@ -4399,15 +4582,7 @@ test_dir_should_use_directory_guards(void *data)
}
NS_DECL(void,
-directory_initiate_command_routerstatus, (const routerstatus_t *status,
- uint8_t dir_purpose,
- uint8_t router_purpose,
- dir_indirection_t indirection,
- const char *resource,
- const char *payload,
- size_t payload_len,
- time_t if_modified_since,
- circuit_guard_state_t *guardstate));
+directory_initiate_request, (directory_request_t *req));
static void
test_dir_should_not_init_request_to_ourselves(void *data)
@@ -4417,7 +4592,7 @@ test_dir_should_not_init_request_to_ourselves(void *data)
crypto_pk_t *key = pk_generate(2);
(void) data;
- NS_MOCK(directory_initiate_command_routerstatus);
+ NS_MOCK(directory_initiate_request);
clear_dir_servers();
routerlist_free_all();
@@ -4432,15 +4607,15 @@ test_dir_should_not_init_request_to_ourselves(void *data)
dir_server_add(ourself);
directory_get_from_all_authorities(DIR_PURPOSE_FETCH_STATUS_VOTE, 0, NULL);
- tt_int_op(CALLED(directory_initiate_command_routerstatus), OP_EQ, 0);
+ tt_int_op(CALLED(directory_initiate_request), OP_EQ, 0);
directory_get_from_all_authorities(DIR_PURPOSE_FETCH_DETACHED_SIGNATURES, 0,
NULL);
- tt_int_op(CALLED(directory_initiate_command_routerstatus), OP_EQ, 0);
+ tt_int_op(CALLED(directory_initiate_request), OP_EQ, 0);
done:
- NS_UNMOCK(directory_initiate_command_routerstatus);
+ NS_UNMOCK(directory_initiate_request);
clear_dir_servers();
routerlist_free_all();
crypto_pk_free(key);
@@ -4454,7 +4629,7 @@ test_dir_should_not_init_request_to_dir_auths_without_v3_info(void *data)
| MICRODESC_DIRINFO;
(void) data;
- NS_MOCK(directory_initiate_command_routerstatus);
+ NS_MOCK(directory_initiate_request);
clear_dir_servers();
routerlist_free_all();
@@ -4465,14 +4640,14 @@ test_dir_should_not_init_request_to_dir_auths_without_v3_info(void *data)
dir_server_add(ds);
directory_get_from_all_authorities(DIR_PURPOSE_FETCH_STATUS_VOTE, 0, NULL);
- tt_int_op(CALLED(directory_initiate_command_routerstatus), OP_EQ, 0);
+ tt_int_op(CALLED(directory_initiate_request), OP_EQ, 0);
directory_get_from_all_authorities(DIR_PURPOSE_FETCH_DETACHED_SIGNATURES, 0,
NULL);
- tt_int_op(CALLED(directory_initiate_command_routerstatus), OP_EQ, 0);
+ tt_int_op(CALLED(directory_initiate_request), OP_EQ, 0);
done:
- NS_UNMOCK(directory_initiate_command_routerstatus);
+ NS_UNMOCK(directory_initiate_request);
clear_dir_servers();
routerlist_free_all();
}
@@ -4483,7 +4658,7 @@ test_dir_should_init_request_to_dir_auths(void *data)
dir_server_t *ds = NULL;
(void) data;
- NS_MOCK(directory_initiate_command_routerstatus);
+ NS_MOCK(directory_initiate_request);
clear_dir_servers();
routerlist_free_all();
@@ -4494,39 +4669,23 @@ test_dir_should_init_request_to_dir_auths(void *data)
dir_server_add(ds);
directory_get_from_all_authorities(DIR_PURPOSE_FETCH_STATUS_VOTE, 0, NULL);
- tt_int_op(CALLED(directory_initiate_command_routerstatus), OP_EQ, 1);
+ tt_int_op(CALLED(directory_initiate_request), OP_EQ, 1);
directory_get_from_all_authorities(DIR_PURPOSE_FETCH_DETACHED_SIGNATURES, 0,
NULL);
- tt_int_op(CALLED(directory_initiate_command_routerstatus), OP_EQ, 2);
+ tt_int_op(CALLED(directory_initiate_request), OP_EQ, 2);
done:
- NS_UNMOCK(directory_initiate_command_routerstatus);
+ NS_UNMOCK(directory_initiate_request);
clear_dir_servers();
routerlist_free_all();
}
void
-NS(directory_initiate_command_routerstatus)(const routerstatus_t *status,
- uint8_t dir_purpose,
- uint8_t router_purpose,
- dir_indirection_t indirection,
- const char *resource,
- const char *payload,
- size_t payload_len,
- time_t if_modified_since,
- circuit_guard_state_t *guardstate)
+NS(directory_initiate_request)(directory_request_t *req)
{
- (void)status;
- (void)dir_purpose;
- (void)router_purpose;
- (void)indirection;
- (void)resource;
- (void)payload;
- (void)payload_len;
- (void)if_modified_since;
- (void)guardstate;
- CALLED(directory_initiate_command_routerstatus)++;
+ (void)req;
+ CALLED(directory_initiate_request)++;
}
static void
@@ -5837,6 +5996,7 @@ struct testcase_t dir_tests[] = {
DIR(parse_router_list, TT_FORK),
DIR(load_routers, TT_FORK),
DIR(load_extrainfo, TT_FORK),
+ DIR(getinfo_extra, 0),
DIR_LEGACY(versions),
DIR_LEGACY(fp_pairs),
DIR(split_fps, 0),
diff --git a/src/test/test_dir_common.c b/src/test/test_dir_common.c
index ca43dd4c04..fca70249bd 100644
--- a/src/test/test_dir_common.c
+++ b/src/test/test_dir_common.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2016, The Tor Project, Inc. */
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_dir_common.h b/src/test/test_dir_common.h
index 9682b0db49..65b9cf6436 100644
--- a/src/test/test_dir_common.h
+++ b/src/test/test_dir_common.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2016, The Tor Project, Inc. */
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "or.h"
diff --git a/src/test/test_dir_handle_get.c b/src/test/test_dir_handle_get.c
index a0868f9253..6e963913d1 100644
--- a/src/test/test_dir_handle_get.c
+++ b/src/test/test_dir_handle_get.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2016, The Tor Project, Inc. */
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define RENDCOMMON_PRIVATE
@@ -14,6 +14,7 @@
#include "connection.h"
#include "directory.h"
#include "test.h"
+#include "compress.h"
#include "connection.h"
#include "rendcommon.h"
#include "rendcache.h"
@@ -28,7 +29,6 @@
#include "networkstatus.h"
#include "geoip.h"
#include "dirserv.h"
-#include "torgzip.h"
#include "dirvote.h"
#include "log_test_helpers.h"
@@ -743,7 +743,7 @@ test_dir_handle_get_server_descriptors_not_found(void* data)
NULL, NULL, 1, 0);
tt_str_op(NOT_FOUND, OP_EQ, header);
- tt_int_op(conn->dir_spool_src, OP_EQ, DIR_SPOOL_SERVER_BY_FP);
+ tt_ptr_op(conn->spool, OP_EQ, NULL);
done:
UNMOCK(connection_write_to_buf_impl_);
@@ -773,6 +773,7 @@ test_dir_handle_get_server_descriptors_all(void* data)
tt_int_op(smartlist_len(our_routerlist->routers), OP_GE, 1);
mock_routerinfo = smartlist_get(our_routerlist->routers, 0);
set_server_identity_key(mock_routerinfo->identity_pkey);
+ mock_routerinfo->cache_info.published_on = time(NULL);
/* Treat "all" requests as if they were unencrypted */
mock_routerinfo->cache_info.send_unencrypted = 1;
@@ -787,7 +788,7 @@ test_dir_handle_get_server_descriptors_all(void* data)
//which is smaller than that by annotation_len bytes
fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE,
&body, &body_used,
- mock_routerinfo->cache_info.signed_descriptor_len+1, 0);
+ 1024*1024, 0);
tt_assert(header);
tt_assert(body);
@@ -803,7 +804,7 @@ test_dir_handle_get_server_descriptors_all(void* data)
tt_str_op(body, OP_EQ, mock_routerinfo->cache_info.signed_descriptor_body +
mock_routerinfo->cache_info.annotations_len);
- tt_int_op(conn->dir_spool_src, OP_EQ, DIR_SPOOL_NONE);
+ tt_ptr_op(conn->spool, OP_EQ, NULL);
done:
NS_UNMOCK(router_get_my_routerinfo);
@@ -882,6 +883,7 @@ test_dir_handle_get_server_descriptors_authority(void* data)
mock_routerinfo->cache_info.signed_descriptor_len =
strlen(TEST_DESCRIPTOR) - annotation_len;;
mock_routerinfo->cache_info.annotations_len = annotation_len;
+ mock_routerinfo->cache_info.published_on = time(NULL);
conn = new_dir_conn();
@@ -904,7 +906,7 @@ test_dir_handle_get_server_descriptors_authority(void* data)
tt_int_op(body_used, OP_EQ, strlen(body));
tt_str_op(body, OP_EQ, TEST_DESCRIPTOR + annotation_len);
- tt_int_op(conn->dir_spool_src, OP_EQ, DIR_SPOOL_NONE);
+ tt_ptr_op(conn->spool, OP_EQ, NULL);
done:
NS_UNMOCK(router_get_my_routerinfo);
@@ -946,6 +948,7 @@ test_dir_handle_get_server_descriptors_fp(void* data)
mock_routerinfo->cache_info.signed_descriptor_len =
strlen(TEST_DESCRIPTOR) - annotation_len;
mock_routerinfo->cache_info.annotations_len = annotation_len;
+ mock_routerinfo->cache_info.published_on = time(NULL);
conn = new_dir_conn();
@@ -975,7 +978,7 @@ test_dir_handle_get_server_descriptors_fp(void* data)
tt_int_op(body_used, OP_EQ, strlen(body));
tt_str_op(body, OP_EQ, TEST_DESCRIPTOR + annotation_len);
- tt_int_op(conn->dir_spool_src, OP_EQ, DIR_SPOOL_NONE);
+ tt_ptr_op(conn->spool, OP_EQ, NULL);
done:
NS_UNMOCK(router_get_my_routerinfo);
@@ -1041,7 +1044,7 @@ test_dir_handle_get_server_descriptors_d(void* data)
tt_str_op(body, OP_EQ, router->cache_info.signed_descriptor_body +
router->cache_info.annotations_len);
- tt_int_op(conn->dir_spool_src, OP_EQ, DIR_SPOOL_NONE);
+ tt_ptr_op(conn->spool, OP_EQ, NULL);
done:
UNMOCK(connection_write_to_buf_impl_);
@@ -1096,7 +1099,7 @@ test_dir_handle_get_server_descriptors_busy(void* data)
tt_assert(header);
tt_str_op(SERVER_BUSY, OP_EQ, header);
- tt_int_op(conn->dir_spool_src, OP_EQ, DIR_SPOOL_NONE);
+ tt_ptr_op(conn->spool, OP_EQ, NULL);
done:
UNMOCK(get_options);
@@ -1829,8 +1832,8 @@ test_dir_handle_get_status_vote_current_consensus_ns(void* data)
comp_body_used);
tt_int_op(ZLIB_METHOD, OP_EQ, compression);
- tor_gzip_uncompress(&body, &body_used, comp_body, comp_body_used,
- compression, 0, LOG_PROTOCOL_WARN);
+ tor_uncompress(&body, &body_used, comp_body, comp_body_used,
+ compression, 0, LOG_PROTOCOL_WARN);
tt_str_op(NETWORK_STATUS, OP_EQ, body);
tt_int_op(strlen(NETWORK_STATUS), OP_EQ, body_used);
@@ -2494,6 +2497,53 @@ test_dir_handle_get_status_vote_current_authority(void* data)
dirvote_free_all();
}
+static void
+test_dir_handle_get_parse_accept_encoding(void *arg)
+{
+ (void)arg;
+ const unsigned B_NONE = 1u << NO_METHOD;
+ const unsigned B_ZLIB = 1u << ZLIB_METHOD;
+ const unsigned B_GZIP = 1u << GZIP_METHOD;
+ const unsigned B_LZMA = 1u << LZMA_METHOD;
+ const unsigned B_ZSTD = 1u << ZSTD_METHOD;
+
+ unsigned encodings;
+
+ encodings = parse_accept_encoding_header("");
+ tt_uint_op(B_NONE, OP_EQ, encodings);
+
+ encodings = parse_accept_encoding_header(" ");
+ tt_uint_op(B_NONE, OP_EQ, encodings);
+
+ encodings = parse_accept_encoding_header("dewey, cheatham, and howe ");
+ tt_uint_op(B_NONE, OP_EQ, encodings);
+
+ encodings = parse_accept_encoding_header("dewey, cheatham, and gzip");
+ tt_uint_op(B_NONE, OP_EQ, encodings);
+
+ encodings = parse_accept_encoding_header("dewey, cheatham, and, gzip");
+ tt_uint_op(B_NONE|B_GZIP, OP_EQ, encodings);
+
+ encodings = parse_accept_encoding_header(" gzip");
+ tt_uint_op(B_NONE|B_GZIP, OP_EQ, encodings);
+
+ encodings = parse_accept_encoding_header("gzip");
+ tt_uint_op(B_NONE|B_GZIP, OP_EQ, encodings);
+
+ encodings = parse_accept_encoding_header("x-zstd, deflate, x-tor-lzma");
+ tt_uint_op(B_NONE|B_ZLIB|B_ZSTD|B_LZMA, OP_EQ, encodings);
+
+ encodings = parse_accept_encoding_header(
+ "x-zstd, deflate, x-tor-lzma, gzip");
+ tt_uint_op(B_NONE|B_ZLIB|B_ZSTD|B_LZMA|B_GZIP, OP_EQ, encodings);
+
+ encodings = parse_accept_encoding_header("x-zstd,deflate,x-tor-lzma,gzip");
+ tt_uint_op(B_NONE|B_ZLIB|B_ZSTD|B_LZMA|B_GZIP, OP_EQ, encodings);
+
+ done:
+ ;
+}
+
#define DIR_HANDLE_CMD(name,flags) \
{ #name, test_dir_handle_get_##name, (flags), NULL, NULL }
@@ -2552,6 +2602,7 @@ struct testcase_t dir_handle_get_tests[] = {
DIR_HANDLE_CMD(status_vote_next_consensus_signatures_not_found, 0),
DIR_HANDLE_CMD(status_vote_next_consensus_signatures_busy, 0),
DIR_HANDLE_CMD(status_vote_next_consensus_signatures, 0),
+ DIR_HANDLE_CMD(parse_accept_encoding, 0),
END_OF_TESTCASES
};
diff --git a/src/test/test_entryconn.c b/src/test/test_entryconn.c
index 50848cfec2..12a631630b 100644
--- a/src/test/test_entryconn.c
+++ b/src/test/test_entryconn.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Tor Project, Inc. */
+/* Copyright (c) 2014-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_entrynodes.c b/src/test/test_entrynodes.c
index 249fd1f973..3db7e63ee3 100644
--- a/src/test/test_entrynodes.c
+++ b/src/test/test_entrynodes.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Tor Project, Inc. */
+/* Copyright (c) 2014-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -584,6 +584,9 @@ test_entry_guard_parse_from_state_full(void *arg)
smartlist_t *text = smartlist_new();
char *joined = NULL;
+ // So nodes aren't expired. This is Tue, 13 Dec 2016 09:37:14 GMT
+ update_approx_time(1481621834);
+
MOCK(entry_guard_is_listed, mock_entry_guard_is_listed);
dummy_state = state;
diff --git a/src/test/test_extorport.c b/src/test/test_extorport.c
index 1f92780177..fc9f27a5ac 100644
--- a/src/test/test_extorport.c
+++ b/src/test/test_extorport.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2016, The Tor Project, Inc. */
+/* Copyright (c) 2013-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CONNECTION_PRIVATE
@@ -72,9 +72,9 @@ test_ext_or_id_map(void *arg)
* writes to outbuf. */
static void
connection_write_to_buf_impl_replacement(const char *string, size_t len,
- connection_t *conn, int zlib)
+ connection_t *conn, int compressed)
{
- (void) zlib;
+ (void) compressed;
tor_assert(string);
tor_assert(conn);
diff --git a/src/test/test_guardfraction.c b/src/test/test_guardfraction.c
index 8173e44d47..56006f3cc3 100644
--- a/src/test/test_guardfraction.c
+++ b/src/test/test_guardfraction.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Tor Project, Inc. */
+/* Copyright (c) 2014-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define DIRSERV_PRIVATE
diff --git a/src/test/test_handles.c b/src/test/test_handles.c
index 536a478689..7ddee6e376 100644
--- a/src/test/test_handles.c
+++ b/src/test/test_handles.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Tor Project, Inc. */
+/* Copyright (c) 2016-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_helpers.c b/src/test/test_helpers.c
index 5b84366e6d..9fada5a675 100644
--- a/src/test/test_helpers.c
+++ b/src/test/test_helpers.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Tor Project, Inc. */
+/* Copyright (c) 2014-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -98,9 +98,9 @@ helper_setup_fake_routerlist(void)
void
connection_write_to_buf_mock(const char *string, size_t len,
- connection_t *conn, int zlib)
+ connection_t *conn, int compressed)
{
- (void) zlib;
+ (void) compressed;
tor_assert(string);
tor_assert(conn);
diff --git a/src/test/test_helpers.h b/src/test/test_helpers.h
index c6d4d9c41f..4621631cc1 100644
--- a/src/test/test_helpers.h
+++ b/src/test/test_helpers.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Tor Project, Inc. */
+/* Copyright (c) 2014-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_TEST_HELPERS_H
@@ -15,7 +15,7 @@ void helper_setup_fake_routerlist(void);
#define GET(path) "GET " path " HTTP/1.0\r\n\r\n"
void connection_write_to_buf_mock(const char *string, size_t len,
- connection_t *conn, int zlib);
+ connection_t *conn, int compressed);
int mock_tor_addr_lookup__fail_on_bad_addrs(const char *name,
uint16_t family, tor_addr_t *out);
diff --git a/src/test/test_hs.c b/src/test/test_hs.c
index fbaabe91d8..c3457c43da 100644
--- a/src/test/test_hs.c
+++ b/src/test/test_hs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2016, The Tor Project, Inc. */
+/* Copyright (c) 2007-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -821,7 +821,9 @@ test_prune_services_on_reload(void *arg)
smartlist_add(old, e1);
/* Only put the non ephemeral in the new list. */
smartlist_add(new, s1);
- prune_services_on_reload(old, new);
+ set_rend_service_list(old);
+ set_rend_rend_service_staging_list(new);
+ rend_service_prune_list_impl_();
/* We expect that the ephemeral one is in the new list but removed from
* the old one. */
tt_int_op(smartlist_len(old), OP_EQ, 1);
@@ -840,7 +842,9 @@ test_prune_services_on_reload(void *arg)
* one. */
smartlist_add(old, s1);
smartlist_add(old, e1);
- prune_services_on_reload(old, new);
+ set_rend_service_list(old);
+ set_rend_rend_service_staging_list(new);
+ rend_service_prune_list_impl_();
tt_int_op(smartlist_len(old), OP_EQ, 1);
tt_assert(smartlist_get(old, 0) == s1);
tt_int_op(smartlist_len(new), OP_EQ, 1);
@@ -855,7 +859,9 @@ test_prune_services_on_reload(void *arg)
* list being completely different. */
smartlist_add(new, s1);
smartlist_add(new, e1);
- prune_services_on_reload(old, new);
+ set_rend_service_list(old);
+ set_rend_rend_service_staging_list(new);
+ rend_service_prune_list_impl_();
tt_int_op(smartlist_len(old), OP_EQ, 0);
tt_int_op(smartlist_len(new), OP_EQ, 2);
tt_assert(smartlist_get(new, 0) == s1);
@@ -871,7 +877,9 @@ test_prune_services_on_reload(void *arg)
/* Setup our list. */
smartlist_add(old, s1);
smartlist_add(new, s2);
- prune_services_on_reload(old, new);
+ set_rend_service_list(old);
+ set_rend_rend_service_staging_list(new);
+ rend_service_prune_list_impl_();
tt_int_op(smartlist_len(old), OP_EQ, 1);
/* Intro nodes have been moved to the s2 in theory so it must be empty. */
tt_int_op(smartlist_len(s1->intro_nodes), OP_EQ, 0);
@@ -892,7 +900,9 @@ test_prune_services_on_reload(void *arg)
/* Test two ephemeral services. */
smartlist_add(old, e1);
smartlist_add(old, e2);
- prune_services_on_reload(old, new);
+ set_rend_service_list(old);
+ set_rend_rend_service_staging_list(new);
+ rend_service_prune_list_impl_();
/* Check if they've all been transfered. */
tt_int_op(smartlist_len(old), OP_EQ, 0);
tt_int_op(smartlist_len(new), OP_EQ, 2);
diff --git a/src/test/test_hs_cache.c b/src/test/test_hs_cache.c
index 1943d0ffac..bc4bfabde9 100644
--- a/src/test/test_hs_cache.c
+++ b/src/test/test_hs_cache.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Tor Project, Inc. */
+/* Copyright (c) 2016-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -93,8 +93,8 @@ helper_build_hs_desc(uint64_t revision_counter, uint32_t lifetime,
/* Setup encrypted data section. */
desc->encrypted_data.create2_ntor = 1;
- desc->encrypted_data.auth_types = smartlist_new();
- smartlist_add(desc->encrypted_data.auth_types, tor_strdup("ed25519"));
+ desc->encrypted_data.intro_auth_types = smartlist_new();
+ smartlist_add(desc->encrypted_data.intro_auth_types, tor_strdup("ed25519"));
desc->encrypted_data.intro_points = smartlist_new();
/* Add an intro point. */
smartlist_add(desc->encrypted_data.intro_points,
@@ -333,7 +333,7 @@ helper_fetch_desc_from_hsdir(const ed25519_public_key_t *blinded_key)
size_t body_used = 0;
fetch_from_buf_http(TO_CONN(conn)->outbuf, &headers, MAX_HEADERS_SIZE,
- &received_desc, &body_used, 10000, 0);
+ &received_desc, &body_used, HS_DESC_MAX_LEN, 0);
tor_free(headers);
}
diff --git a/src/test/test_hs_descriptor.c b/src/test/test_hs_descriptor.c
index 02a71aa473..a1a1f14fb8 100644
--- a/src/test/test_hs_descriptor.c
+++ b/src/test/test_hs_descriptor.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Tor Project, Inc. */
+/* Copyright (c) 2016-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -15,6 +15,9 @@
#include "test.h"
#include "torcert.h"
+#include "test_helpers.h"
+#include "log_test_helpers.h"
+
static hs_desc_intro_point_t *
helper_build_intro_point(const ed25519_keypair_t *blinded_kp, time_t now,
const char *addr, int legacy)
@@ -105,9 +108,9 @@ helper_build_hs_desc(unsigned int no_ip, ed25519_public_key_t *signing_pubkey)
/* Setup encrypted data section. */
desc->encrypted_data.create2_ntor = 1;
- desc->encrypted_data.auth_types = smartlist_new();
+ desc->encrypted_data.intro_auth_types = smartlist_new();
desc->encrypted_data.single_onion_service = 1;
- smartlist_add(desc->encrypted_data.auth_types, tor_strdup("ed25519"));
+ smartlist_add(desc->encrypted_data.intro_auth_types, tor_strdup("ed25519"));
desc->encrypted_data.intro_points = smartlist_new();
if (!no_ip) {
/* Add four intro points. */
@@ -157,14 +160,17 @@ helper_compare_hs_desc(const hs_descriptor_t *desc1,
desc2->encrypted_data.create2_ntor);
/* Authentication type. */
- tt_int_op(!!desc1->encrypted_data.auth_types, ==,
- !!desc2->encrypted_data.auth_types);
- if (desc1->encrypted_data.auth_types && desc2->encrypted_data.auth_types) {
- tt_int_op(smartlist_len(desc1->encrypted_data.auth_types), ==,
- smartlist_len(desc2->encrypted_data.auth_types));
- for (int i = 0; i < smartlist_len(desc1->encrypted_data.auth_types); i++) {
- tt_str_op(smartlist_get(desc1->encrypted_data.auth_types, i), OP_EQ,
- smartlist_get(desc2->encrypted_data.auth_types, i));
+ tt_int_op(!!desc1->encrypted_data.intro_auth_types, ==,
+ !!desc2->encrypted_data.intro_auth_types);
+ if (desc1->encrypted_data.intro_auth_types &&
+ desc2->encrypted_data.intro_auth_types) {
+ tt_int_op(smartlist_len(desc1->encrypted_data.intro_auth_types), ==,
+ smartlist_len(desc2->encrypted_data.intro_auth_types));
+ for (int i = 0;
+ i < smartlist_len(desc1->encrypted_data.intro_auth_types);
+ i++) {
+ tt_str_op(smartlist_get(desc1->encrypted_data.intro_auth_types, i),OP_EQ,
+ smartlist_get(desc2->encrypted_data.intro_auth_types, i));
}
}
@@ -311,13 +317,13 @@ test_descriptor_padding(void *arg)
/* Example: if l = 129, the ceiled division gives 2 and then multiplied by 128
* to give 256. With l = 127, ceiled division gives 1 then times 128. */
#define PADDING_EXPECTED_LEN(l) \
- CEIL_DIV(l, HS_DESC_PLAINTEXT_PADDING_MULTIPLE) * \
- HS_DESC_PLAINTEXT_PADDING_MULTIPLE
+ CEIL_DIV(l, HS_DESC_SUPERENC_PLAINTEXT_PAD_MULTIPLE) * \
+ HS_DESC_SUPERENC_PLAINTEXT_PAD_MULTIPLE
(void) arg;
{ /* test #1: no padding */
- plaintext_len = HS_DESC_PLAINTEXT_PADDING_MULTIPLE;
+ plaintext_len = HS_DESC_SUPERENC_PLAINTEXT_PAD_MULTIPLE;
plaintext = tor_malloc(plaintext_len);
padded_len = build_plaintext_padding(plaintext, plaintext_len,
&padded_plaintext);
@@ -333,7 +339,7 @@ test_descriptor_padding(void *arg)
}
{ /* test #2: one byte padding? */
- plaintext_len = HS_DESC_PLAINTEXT_PADDING_MULTIPLE - 1;
+ plaintext_len = HS_DESC_SUPERENC_PLAINTEXT_PAD_MULTIPLE - 1;
plaintext = tor_malloc(plaintext_len);
padded_plaintext = NULL;
padded_len = build_plaintext_padding(plaintext, plaintext_len,
@@ -350,7 +356,7 @@ test_descriptor_padding(void *arg)
}
{ /* test #3: Lots more bytes of padding? */
- plaintext_len = HS_DESC_PLAINTEXT_PADDING_MULTIPLE + 1;
+ plaintext_len = HS_DESC_SUPERENC_PLAINTEXT_PAD_MULTIPLE + 1;
plaintext = tor_malloc(plaintext_len);
padded_plaintext = NULL;
padded_len = build_plaintext_padding(plaintext, plaintext_len,
@@ -587,19 +593,11 @@ test_encrypted_data_len(void *arg)
/* No length, error. */
ret = encrypted_data_length_is_valid(0);
tt_int_op(ret, OP_EQ, 0);
- /* Not a multiple of our encryption algorithm (thus no padding). It's
- * suppose to be aligned on HS_DESC_PLAINTEXT_PADDING_MULTIPLE. */
- value = HS_DESC_PLAINTEXT_PADDING_MULTIPLE * 10 - 1;
- ret = encrypted_data_length_is_valid(value);
- tt_int_op(ret, OP_EQ, 0);
/* Valid value. */
- value = HS_DESC_PADDED_PLAINTEXT_MAX_LEN + HS_DESC_ENCRYPTED_SALT_LEN +
- DIGEST256_LEN;
+ value = HS_DESC_ENCRYPTED_SALT_LEN + DIGEST256_LEN + 1;
ret = encrypted_data_length_is_valid(value);
tt_int_op(ret, OP_EQ, 1);
- /* XXX: Test maximum possible size. */
-
done:
;
}
@@ -1006,6 +1004,103 @@ test_desc_signature(void *arg)
tor_free(data);
}
+/* bad desc auth type */
+static const char bad_superencrypted_text1[] = "desc-auth-type scoobysnack\n"
+ "desc-auth-ephemeral-key A/O8DVtnUheb3r1JqoB8uJB7wxXL1XJX3eny4yB+eFA=\n"
+ "auth-client oiNrQB8WwKo S5D02W7vKgiWIMygrBl8RQ FB//SfOBmLEx1kViEWWL1g\n"
+ "encrypted\n"
+ "-----BEGIN MESSAGE-----\n"
+ "YmVpbmcgb24gbW91bnRhaW5zLCB0aGlua2luZyBhYm91dCBjb21wdXRlcnMsIGlzIG5vdC"
+ "BiYWQgYXQgYWxs\n"
+ "-----END MESSAGE-----\n";
+
+/* bad ephemeral key */
+static const char bad_superencrypted_text2[] = "desc-auth-type x25519\n"
+ "desc-auth-ephemeral-key differentalphabet\n"
+ "auth-client oiNrQB8WwKo S5D02W7vKgiWIMygrBl8RQ FB//SfOBmLEx1kViEWWL1g\n"
+ "encrypted\n"
+ "-----BEGIN MESSAGE-----\n"
+ "YmVpbmcgb24gbW91bnRhaW5zLCB0aGlua2luZyBhYm91dCBjb21wdXRlcnMsIGlzIG5vdC"
+ "BiYWQgYXQgYWxs\n"
+ "-----END MESSAGE-----\n";
+
+/* bad encrypted msg */
+static const char bad_superencrypted_text3[] = "desc-auth-type x25519\n"
+ "desc-auth-ephemeral-key A/O8DVtnUheb3r1JqoB8uJB7wxXL1XJX3eny4yB+eFA=\n"
+ "auth-client oiNrQB8WwKo S5D02W7vKgiWIMygrBl8RQ FB//SfOBmLEx1kViEWWL1g\n"
+ "encrypted\n"
+ "-----BEGIN MESSAGE-----\n"
+ "SO SMALL NOT GOOD\n"
+ "-----END MESSAGE-----\n";
+
+static const char correct_superencrypted_text[] = "desc-auth-type x25519\n"
+ "desc-auth-ephemeral-key A/O8DVtnUheb3r1JqoB8uJB7wxXL1XJX3eny4yB+eFA=\n"
+ "auth-client oiNrQB8WwKo S5D02W7vKgiWIMygrBl8RQ FB//SfOBmLEx1kViEWWL1g\n"
+ "auth-client Od09Qu636Qo /PKLzqewAdS/+0+vZC+MvQ dpw4NFo13zDnuPz45rxrOg\n"
+ "auth-client JRr840iGYN0 8s8cxYqF7Lx23+NducC4Qg zAafl4wPLURkuEjJreZq1g\n"
+ "encrypted\n"
+ "-----BEGIN MESSAGE-----\n"
+ "YmVpbmcgb24gbW91bnRhaW5zLCB0aGlua2luZyBhYm91dCBjb21wdXRlcnMsIGlzIG5vdC"
+ "BiYWQgYXQgYWxs\n"
+ "-----END MESSAGE-----\n";
+
+static const char correct_encrypted_plaintext[] = "being on mountains, "
+ "thinking about computers, is not bad at all";
+
+static void
+test_parse_hs_desc_superencrypted(void *arg)
+{
+ (void) arg;
+ size_t retval;
+ uint8_t *encrypted_out = NULL;
+
+ {
+ setup_full_capture_of_logs(LOG_WARN);
+ retval = decode_superencrypted(bad_superencrypted_text1,
+ strlen(bad_superencrypted_text1),
+ &encrypted_out);
+ tt_u64_op(retval, ==, 0);
+ tt_assert(!encrypted_out);
+ expect_log_msg_containing("Unrecognized desc auth type");
+ teardown_capture_of_logs();
+ }
+
+ {
+ setup_full_capture_of_logs(LOG_WARN);
+ retval = decode_superencrypted(bad_superencrypted_text2,
+ strlen(bad_superencrypted_text2),
+ &encrypted_out);
+ tt_u64_op(retval, ==, 0);
+ tt_assert(!encrypted_out);
+ expect_log_msg_containing("Bogus desc auth key in HS desc");
+ teardown_capture_of_logs();
+ }
+
+ {
+ setup_full_capture_of_logs(LOG_WARN);
+ retval = decode_superencrypted(bad_superencrypted_text3,
+ strlen(bad_superencrypted_text3),
+ &encrypted_out);
+ tt_u64_op(retval, ==, 0);
+ tt_assert(!encrypted_out);
+ expect_log_msg_containing("Length of descriptor\'s encrypted data "
+ "is too small.");
+ teardown_capture_of_logs();
+ }
+
+ /* Now finally the good one */
+ retval = decode_superencrypted(correct_superencrypted_text,
+ strlen(correct_superencrypted_text),
+ &encrypted_out);
+
+ tt_u64_op(retval, ==, strlen(correct_encrypted_plaintext));
+ tt_mem_op(encrypted_out, OP_EQ, correct_encrypted_plaintext,
+ strlen(correct_encrypted_plaintext));
+
+ done:
+ tor_free(encrypted_out);
+}
+
struct testcase_t hs_descriptor[] = {
/* Encoding tests. */
{ "cert_encoding", test_cert_encoding, TT_FORK,
@@ -1035,6 +1130,9 @@ struct testcase_t hs_descriptor[] = {
{ "desc_signature", test_desc_signature, TT_FORK,
NULL, NULL },
+ { "parse_hs_desc_superencrypted", test_parse_hs_desc_superencrypted,
+ TT_FORK, NULL, NULL },
+
END_OF_TESTCASES
};
diff --git a/src/test/test_hs_intropoint.c b/src/test/test_hs_intropoint.c
index ea12aeb2da..ef5cb46567 100644
--- a/src/test/test_hs_intropoint.c
+++ b/src/test/test_hs_intropoint.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Tor Project, Inc. */
+/* Copyright (c) 2016-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -69,10 +69,10 @@ helper_create_intro_circuit(void)
return circ;
}
-static hs_cell_introduce1_t *
+static trn_cell_introduce1_t *
helper_create_introduce1_cell(void)
{
- hs_cell_introduce1_t *cell = NULL;
+ trn_cell_introduce1_t *cell = NULL;
ed25519_keypair_t auth_key_kp;
/* Generate the auth_key of the cell. */
@@ -80,39 +80,39 @@ helper_create_introduce1_cell(void)
goto err;
}
- cell = hs_cell_introduce1_new();
+ cell = trn_cell_introduce1_new();
tt_assert(cell);
/* Set the auth key. */
{
size_t auth_key_len = sizeof(auth_key_kp.pubkey);
- hs_cell_introduce1_set_auth_key_type(cell,
+ trn_cell_introduce1_set_auth_key_type(cell,
HS_INTRO_AUTH_KEY_TYPE_ED25519);
- hs_cell_introduce1_set_auth_key_len(cell, auth_key_len);
- hs_cell_introduce1_setlen_auth_key(cell, auth_key_len);
- uint8_t *auth_key_ptr = hs_cell_introduce1_getarray_auth_key(cell);
+ trn_cell_introduce1_set_auth_key_len(cell, auth_key_len);
+ trn_cell_introduce1_setlen_auth_key(cell, auth_key_len);
+ uint8_t *auth_key_ptr = trn_cell_introduce1_getarray_auth_key(cell);
memcpy(auth_key_ptr, auth_key_kp.pubkey.pubkey, auth_key_len);
}
/* Set the cell extentions to none. */
{
- cell_extension_t *ext = cell_extension_new();
- cell_extension_set_num(ext, 0);
- hs_cell_introduce1_set_extensions(cell, ext);
+ trn_cell_extension_t *ext = trn_cell_extension_new();
+ trn_cell_extension_set_num(ext, 0);
+ trn_cell_introduce1_set_extensions(cell, ext);
}
/* Set the encrypted section to some data. */
{
size_t enc_len = 128;
- hs_cell_introduce1_setlen_encrypted(cell, enc_len);
- uint8_t *enc_ptr = hs_cell_introduce1_getarray_encrypted(cell);
+ trn_cell_introduce1_setlen_encrypted(cell, enc_len);
+ uint8_t *enc_ptr = trn_cell_introduce1_getarray_encrypted(cell);
memset(enc_ptr, 'a', enc_len);
}
return cell;
err:
done:
- hs_cell_introduce1_free(cell);
+ trn_cell_introduce1_free(cell);
return NULL;
}
@@ -122,7 +122,7 @@ static void
test_establish_intro_wrong_purpose(void *arg)
{
int retval;
- hs_cell_establish_intro_t *establish_intro_cell = NULL;
+ trn_cell_establish_intro_t *establish_intro_cell = NULL;
or_circuit_t *intro_circ = or_circuit_new(0,NULL);;
uint8_t cell_body[RELAY_PAYLOAD_SIZE];
ssize_t cell_len = 0;
@@ -154,7 +154,7 @@ test_establish_intro_wrong_purpose(void *arg)
tt_int_op(retval, ==, -1);
done:
- hs_cell_establish_intro_free(establish_intro_cell);
+ trn_cell_establish_intro_free(establish_intro_cell);
circuit_free(TO_CIRCUIT(intro_circ));
}
@@ -198,7 +198,7 @@ static void
test_establish_intro_wrong_keytype2(void *arg)
{
int retval;
- hs_cell_establish_intro_t *establish_intro_cell = NULL;
+ trn_cell_establish_intro_t *establish_intro_cell = NULL;
or_circuit_t *intro_circ = or_circuit_new(0,NULL);;
uint8_t cell_body[RELAY_PAYLOAD_SIZE];
ssize_t cell_len = 0;
@@ -230,7 +230,7 @@ test_establish_intro_wrong_keytype2(void *arg)
tt_int_op(retval, ==, -1);
done:
- hs_cell_establish_intro_free(establish_intro_cell);
+ trn_cell_establish_intro_free(establish_intro_cell);
circuit_free(TO_CIRCUIT(intro_circ));
}
@@ -239,7 +239,7 @@ static void
test_establish_intro_wrong_mac(void *arg)
{
int retval;
- hs_cell_establish_intro_t *establish_intro_cell = NULL;
+ trn_cell_establish_intro_t *establish_intro_cell = NULL;
or_circuit_t *intro_circ = or_circuit_new(0,NULL);;
uint8_t cell_body[RELAY_PAYLOAD_SIZE];
ssize_t cell_len = 0;
@@ -258,7 +258,7 @@ test_establish_intro_wrong_mac(void *arg)
tt_assert(establish_intro_cell);
/* Mangle one byte of the MAC. */
uint8_t *handshake_ptr =
- hs_cell_establish_intro_getarray_handshake_mac(establish_intro_cell);
+ trn_cell_establish_intro_getarray_handshake_mac(establish_intro_cell);
handshake_ptr[TRUNNEL_SHA3_256_LEN - 1]++;
/* We need to resign the payload with that change. */
{
@@ -269,7 +269,7 @@ test_establish_intro_wrong_mac(void *arg)
retval = ed25519_keypair_generate(&key_struct, 0);
tt_int_op(retval, OP_EQ, 0);
uint8_t *auth_key_ptr =
- hs_cell_establish_intro_getarray_auth_key(establish_intro_cell);
+ trn_cell_establish_intro_getarray_auth_key(establish_intro_cell);
memcpy(auth_key_ptr, key_struct.pubkey.pubkey, ED25519_PUBKEY_LEN);
/* Encode payload so we can sign it. */
cell_len = get_establish_intro_payload(cell_body, sizeof(cell_body),
@@ -284,7 +284,7 @@ test_establish_intro_wrong_mac(void *arg)
tt_int_op(retval, OP_EQ, 0);
/* And write the signature to the cell */
uint8_t *sig_ptr =
- hs_cell_establish_intro_getarray_sig(establish_intro_cell);
+ trn_cell_establish_intro_getarray_sig(establish_intro_cell);
memcpy(sig_ptr, sig.sig, establish_intro_cell->sig_len);
/* Re-encode with the new signature. */
cell_len = get_establish_intro_payload(cell_body, sizeof(cell_body),
@@ -299,7 +299,7 @@ test_establish_intro_wrong_mac(void *arg)
tt_int_op(retval, ==, -1);
done:
- hs_cell_establish_intro_free(establish_intro_cell);
+ trn_cell_establish_intro_free(establish_intro_cell);
circuit_free(TO_CIRCUIT(intro_circ));
}
@@ -309,7 +309,7 @@ static void
test_establish_intro_wrong_auth_key_len(void *arg)
{
int retval;
- hs_cell_establish_intro_t *establish_intro_cell = NULL;
+ trn_cell_establish_intro_t *establish_intro_cell = NULL;
or_circuit_t *intro_circ = or_circuit_new(0,NULL);;
uint8_t cell_body[RELAY_PAYLOAD_SIZE];
ssize_t cell_len = 0;
@@ -328,9 +328,9 @@ test_establish_intro_wrong_auth_key_len(void *arg)
sizeof(circuit_key_material));
tt_assert(establish_intro_cell);
/* Mangle the auth key length. */
- hs_cell_establish_intro_set_auth_key_len(establish_intro_cell,
+ trn_cell_establish_intro_set_auth_key_len(establish_intro_cell,
bad_auth_key_len);
- hs_cell_establish_intro_setlen_auth_key(establish_intro_cell,
+ trn_cell_establish_intro_setlen_auth_key(establish_intro_cell,
bad_auth_key_len);
cell_len = get_establish_intro_payload(cell_body, sizeof(cell_body),
establish_intro_cell);
@@ -344,7 +344,7 @@ test_establish_intro_wrong_auth_key_len(void *arg)
tt_int_op(retval, ==, -1);
done:
- hs_cell_establish_intro_free(establish_intro_cell);
+ trn_cell_establish_intro_free(establish_intro_cell);
circuit_free(TO_CIRCUIT(intro_circ));
}
@@ -354,7 +354,7 @@ static void
test_establish_intro_wrong_sig_len(void *arg)
{
int retval;
- hs_cell_establish_intro_t *establish_intro_cell = NULL;
+ trn_cell_establish_intro_t *establish_intro_cell = NULL;
or_circuit_t *intro_circ = or_circuit_new(0,NULL);;
uint8_t cell_body[RELAY_PAYLOAD_SIZE];
ssize_t cell_len = 0;
@@ -373,8 +373,8 @@ test_establish_intro_wrong_sig_len(void *arg)
sizeof(circuit_key_material));
tt_assert(establish_intro_cell);
/* Mangle the signature length. */
- hs_cell_establish_intro_set_sig_len(establish_intro_cell, bad_sig_len);
- hs_cell_establish_intro_setlen_sig(establish_intro_cell, bad_sig_len);
+ trn_cell_establish_intro_set_sig_len(establish_intro_cell, bad_sig_len);
+ trn_cell_establish_intro_setlen_sig(establish_intro_cell, bad_sig_len);
cell_len = get_establish_intro_payload(cell_body, sizeof(cell_body),
establish_intro_cell);
tt_int_op(cell_len, >, 0);
@@ -387,7 +387,7 @@ test_establish_intro_wrong_sig_len(void *arg)
tt_int_op(retval, ==, -1);
done:
- hs_cell_establish_intro_free(establish_intro_cell);
+ trn_cell_establish_intro_free(establish_intro_cell);
circuit_free(TO_CIRCUIT(intro_circ));
}
@@ -397,7 +397,7 @@ static void
test_establish_intro_wrong_sig(void *arg)
{
int retval;
- hs_cell_establish_intro_t *establish_intro_cell = NULL;
+ trn_cell_establish_intro_t *establish_intro_cell = NULL;
or_circuit_t *intro_circ = or_circuit_new(0,NULL);;
uint8_t cell_body[RELAY_PAYLOAD_SIZE];
ssize_t cell_len = 0;
@@ -429,17 +429,17 @@ test_establish_intro_wrong_sig(void *arg)
tt_int_op(retval, ==, -1);
done:
- hs_cell_establish_intro_free(establish_intro_cell);
+ trn_cell_establish_intro_free(establish_intro_cell);
circuit_free(TO_CIRCUIT(intro_circ));
}
/* Helper function: Send a well-formed v3 ESTABLISH_INTRO cell to
* <b>intro_circ</b>. Return the cell. */
-static hs_cell_establish_intro_t *
+static trn_cell_establish_intro_t *
helper_establish_intro_v3(or_circuit_t *intro_circ)
{
int retval;
- hs_cell_establish_intro_t *establish_intro_cell = NULL;
+ trn_cell_establish_intro_t *establish_intro_cell = NULL;
uint8_t cell_body[RELAY_PAYLOAD_SIZE];
ssize_t cell_len = 0;
uint8_t circuit_key_material[DIGEST_LEN] = {0};
@@ -489,6 +489,7 @@ helper_establish_intro_v2(or_circuit_t *intro_circ)
/* Use old circuit_key_material why not */
cell_len = encode_establish_intro_cell_legacy((char*)cell_body,
+ sizeof(cell_body),
key1,
(char *) circuit_key_material);
tt_int_op(cell_len, >, 0);
@@ -511,7 +512,7 @@ test_intro_point_registration(void *arg)
hs_circuitmap_ht *the_hs_circuitmap = NULL;
or_circuit_t *intro_circ = NULL;
- hs_cell_establish_intro_t *establish_intro_cell = NULL;
+ trn_cell_establish_intro_t *establish_intro_cell = NULL;
ed25519_public_key_t auth_key;
crypto_pk_t *legacy_auth_key = NULL;
@@ -531,7 +532,7 @@ test_intro_point_registration(void *arg)
tt_assert(the_hs_circuitmap);
tt_int_op(0, ==, HT_SIZE(the_hs_circuitmap));
/* Do a circuitmap query in any case */
- returned_intro_circ = hs_circuitmap_get_intro_circ_v3(&auth_key);
+ returned_intro_circ =hs_circuitmap_get_intro_circ_v3_relay_side(&auth_key);
tt_ptr_op(returned_intro_circ, ==, NULL);
}
@@ -547,7 +548,8 @@ test_intro_point_registration(void *arg)
tt_int_op(1, ==, HT_SIZE(the_hs_circuitmap));
get_auth_key_from_cell(&auth_key, RELAY_COMMAND_ESTABLISH_INTRO,
establish_intro_cell);
- returned_intro_circ = hs_circuitmap_get_intro_circ_v3(&auth_key);
+ returned_intro_circ =
+ hs_circuitmap_get_intro_circ_v3_relay_side(&auth_key);
tt_ptr_op(intro_circ, ==, returned_intro_circ);
}
@@ -568,7 +570,8 @@ test_intro_point_registration(void *arg)
/* Check that the new element is our legacy intro circuit. */
retval = crypto_pk_get_digest(legacy_auth_key, key_digest);
tt_int_op(retval, ==, 0);
- returned_intro_circ= hs_circuitmap_get_intro_circ_v2((uint8_t*)key_digest);
+ returned_intro_circ =
+ hs_circuitmap_get_intro_circ_v2_relay_side((uint8_t*)key_digest);
tt_ptr_op(legacy_intro_circ, ==, returned_intro_circ);
}
@@ -579,7 +582,7 @@ test_intro_point_registration(void *arg)
crypto_pk_free(legacy_auth_key);
circuit_free(TO_CIRCUIT(intro_circ));
circuit_free(TO_CIRCUIT(legacy_intro_circ));
- hs_cell_establish_intro_free(establish_intro_cell);
+ trn_cell_establish_intro_free(establish_intro_cell);
{ /* Test circuitmap free_all function. */
the_hs_circuitmap = get_hs_circuitmap();
@@ -673,7 +676,7 @@ static void
test_introduce1_validation(void *arg)
{
int ret;
- hs_cell_introduce1_t *cell = NULL;
+ trn_cell_introduce1_t *cell = NULL;
(void) arg;
@@ -713,25 +716,25 @@ test_introduce1_validation(void *arg)
ret = validate_introduce1_parsed_cell(cell);
tt_int_op(ret, OP_EQ, 0);
/* Set an invalid size of the auth key buffer. */
- hs_cell_introduce1_setlen_auth_key(cell, 3);
+ trn_cell_introduce1_setlen_auth_key(cell, 3);
ret = validate_introduce1_parsed_cell(cell);
tt_int_op(ret, OP_EQ, -1);
/* Reset auth key buffer and make sure it works. */
- hs_cell_introduce1_setlen_auth_key(cell, sizeof(ed25519_public_key_t));
+ trn_cell_introduce1_setlen_auth_key(cell, sizeof(ed25519_public_key_t));
ret = validate_introduce1_parsed_cell(cell);
tt_int_op(ret, OP_EQ, 0);
/* Empty encrypted section. */
- hs_cell_introduce1_setlen_encrypted(cell, 0);
+ trn_cell_introduce1_setlen_encrypted(cell, 0);
ret = validate_introduce1_parsed_cell(cell);
tt_int_op(ret, OP_EQ, -1);
/* Reset it to some non zero bytes and validate. */
- hs_cell_introduce1_setlen_encrypted(cell, 1);
+ trn_cell_introduce1_setlen_encrypted(cell, 1);
ret = validate_introduce1_parsed_cell(cell);
tt_int_op(ret, OP_EQ, 0);
done:
- hs_cell_introduce1_free(cell);
+ trn_cell_introduce1_free(cell);
}
static void
@@ -739,7 +742,7 @@ test_received_introduce1_handling(void *arg)
{
int ret;
uint8_t *request = NULL, buf[128];
- hs_cell_introduce1_t *cell = NULL;
+ trn_cell_introduce1_t *cell = NULL;
or_circuit_t *circ = NULL;
(void) arg;
@@ -773,12 +776,12 @@ test_received_introduce1_handling(void *arg)
/* Valid case. */
{
cell = helper_create_introduce1_cell();
- ssize_t request_len = hs_cell_introduce1_encoded_len(cell);
- tt_size_op(request_len, OP_GT, 0);
+ ssize_t request_len = trn_cell_introduce1_encoded_len(cell);
+ tt_int_op((int)request_len, OP_GT, 0);
request = tor_malloc_zero(request_len);
ssize_t encoded_len =
- hs_cell_introduce1_encode(request, request_len, cell);
- tt_size_op(encoded_len, OP_GT, 0);
+ trn_cell_introduce1_encode(request, request_len, cell);
+ tt_int_op((int)encoded_len, OP_GT, 0);
circ = helper_create_intro_circuit();
or_circuit_t *service_circ = helper_create_intro_circuit();
@@ -787,9 +790,9 @@ test_received_introduce1_handling(void *arg)
/* Register the circuit in the map for the auth key of the cell. */
ed25519_public_key_t auth_key;
const uint8_t *cell_auth_key =
- hs_cell_introduce1_getconstarray_auth_key(cell);
+ trn_cell_introduce1_getconstarray_auth_key(cell);
memcpy(auth_key.pubkey, cell_auth_key, ED25519_PUBKEY_LEN);
- hs_circuitmap_register_intro_circ_v3(service_circ, &auth_key);
+ hs_circuitmap_register_intro_circ_v3_relay_side(service_circ, &auth_key);
ret = hs_intro_received_introduce1(circ, request, request_len);
circuit_free(TO_CIRCUIT(circ));
circuit_free(TO_CIRCUIT(service_circ));
@@ -799,17 +802,17 @@ test_received_introduce1_handling(void *arg)
/* Valid legacy cell. */
{
tor_free(request);
- hs_cell_introduce1_free(cell);
+ trn_cell_introduce1_free(cell);
cell = helper_create_introduce1_cell();
- uint8_t *legacy_key_id = hs_cell_introduce1_getarray_legacy_key_id(cell);
+ uint8_t *legacy_key_id = trn_cell_introduce1_getarray_legacy_key_id(cell);
memset(legacy_key_id, 'a', DIGEST_LEN);
/* Add an arbitrary amount of data for the payload of a v2 cell. */
- size_t request_len = hs_cell_introduce1_encoded_len(cell) + 256;
+ size_t request_len = trn_cell_introduce1_encoded_len(cell) + 256;
tt_size_op(request_len, OP_GT, 0);
request = tor_malloc_zero(request_len + 256);
ssize_t encoded_len =
- hs_cell_introduce1_encode(request, request_len, cell);
- tt_size_op(encoded_len, OP_GT, 0);
+ trn_cell_introduce1_encode(request, request_len, cell);
+ tt_int_op((int)encoded_len, OP_GT, 0);
circ = helper_create_intro_circuit();
or_circuit_t *service_circ = helper_create_intro_circuit();
@@ -818,7 +821,7 @@ test_received_introduce1_handling(void *arg)
/* Register the circuit in the map for the auth key of the cell. */
uint8_t token[REND_TOKEN_LEN];
memcpy(token, legacy_key_id, sizeof(token));
- hs_circuitmap_register_intro_circ_v2(service_circ, token);
+ hs_circuitmap_register_intro_circ_v2_relay_side(service_circ, token);
ret = hs_intro_received_introduce1(circ, request, request_len);
circuit_free(TO_CIRCUIT(circ));
circuit_free(TO_CIRCUIT(service_circ));
@@ -826,7 +829,7 @@ test_received_introduce1_handling(void *arg)
}
done:
- hs_cell_introduce1_free(cell);
+ trn_cell_introduce1_free(cell);
tor_free(request);
hs_circuitmap_free_all();
UNMOCK(relay_send_command_from_edge_);
diff --git a/src/test/test_hs_ntor.sh b/src/test/test_hs_ntor.sh
new file mode 100755
index 0000000000..8a0003d44a
--- /dev/null
+++ b/src/test/test_hs_ntor.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+# Validate Tor's ntor implementation.
+
+exitcode=0
+
+# Run the python integration test sand return the exitcode of the python
+# script. The python script might ask the testsuite to skip it if not all
+# python dependencies are covered.
+"${PYTHON:-python}" "${abs_top_srcdir:-.}/src/test/hs_ntor_ref.py" || exitcode=$?
+
+exit ${exitcode}
diff --git a/src/test/test_hs_ntor_cl.c b/src/test/test_hs_ntor_cl.c
new file mode 100644
index 0000000000..ed1eda58ea
--- /dev/null
+++ b/src/test/test_hs_ntor_cl.c
@@ -0,0 +1,255 @@
+/* Copyright (c) 2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/** This is a wrapper over the little-t-tor HS ntor functions. The wrapper is
+ * used by src/test/hs_ntor_ref.py to conduct the HS ntor integration
+ * tests.
+ *
+ * The logic of this wrapper is basically copied from src/test/test_ntor_cl.c
+ */
+
+#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 "hs_ntor.h"
+#include "onion_ntor.h"
+
+#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)) < (int)n ) { \
+ 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
+
+/** The first part of the HS ntor protocol. The client-side computes all
+ necessary key material and sends the appropriate message to the service. */
+static int
+client1(int argc, char **argv)
+{
+ int retval;
+
+ /* Inputs */
+ curve25519_public_key_t intro_enc_pubkey;
+ ed25519_public_key_t intro_auth_pubkey;
+ curve25519_keypair_t client_ephemeral_enc_keypair;
+ uint8_t subcredential[DIGEST256_LEN];
+
+ /* Output */
+ hs_ntor_intro_cell_keys_t hs_ntor_intro_cell_keys;
+
+ char buf[256];
+
+ N_ARGS(6);
+ BASE16(2, intro_auth_pubkey.pubkey, ED25519_PUBKEY_LEN);
+ BASE16(3, intro_enc_pubkey.public_key, CURVE25519_PUBKEY_LEN);
+ BASE16(4, client_ephemeral_enc_keypair.seckey.secret_key,
+ CURVE25519_SECKEY_LEN);
+ BASE16(5, subcredential, DIGEST256_LEN);
+
+ /* Generate keypair */
+ curve25519_public_key_generate(&client_ephemeral_enc_keypair.pubkey,
+ &client_ephemeral_enc_keypair.seckey);
+
+ retval = hs_ntor_client_get_introduce1_keys(&intro_auth_pubkey,
+ &intro_enc_pubkey,
+ &client_ephemeral_enc_keypair,
+ subcredential,
+ &hs_ntor_intro_cell_keys);
+ if (retval < 0) {
+ goto done;
+ }
+
+ /* Send ENC_KEY */
+ base16_encode(buf, sizeof(buf),
+ (const char*)hs_ntor_intro_cell_keys.enc_key,
+ sizeof(hs_ntor_intro_cell_keys.enc_key));
+ printf("%s\n", buf);
+ /* Send MAC_KEY */
+ base16_encode(buf, sizeof(buf),
+ (const char*)hs_ntor_intro_cell_keys.mac_key,
+ sizeof(hs_ntor_intro_cell_keys.mac_key));
+ printf("%s\n", buf);
+
+ done:
+ return retval;
+}
+
+/** The second part of the HS ntor protocol. The service-side computes all
+ necessary key material and sends the appropriate message to the client */
+static int
+server1(int argc, char **argv)
+{
+ int retval;
+
+ /* Inputs */
+ curve25519_keypair_t intro_enc_keypair;
+ ed25519_public_key_t intro_auth_pubkey;
+ curve25519_public_key_t client_ephemeral_enc_pubkey;
+ uint8_t subcredential[DIGEST256_LEN];
+
+ /* Output */
+ hs_ntor_intro_cell_keys_t hs_ntor_intro_cell_keys;
+ hs_ntor_rend_cell_keys_t hs_ntor_rend_cell_keys;
+ curve25519_keypair_t service_ephemeral_rend_keypair;
+
+ char buf[256];
+
+ N_ARGS(6);
+ BASE16(2, intro_auth_pubkey.pubkey, ED25519_PUBKEY_LEN);
+ BASE16(3, intro_enc_keypair.seckey.secret_key, CURVE25519_SECKEY_LEN);
+ BASE16(4, client_ephemeral_enc_pubkey.public_key, CURVE25519_PUBKEY_LEN);
+ BASE16(5, subcredential, DIGEST256_LEN);
+
+ /* Generate keypair */
+ curve25519_public_key_generate(&intro_enc_keypair.pubkey,
+ &intro_enc_keypair.seckey);
+ curve25519_keypair_generate(&service_ephemeral_rend_keypair, 0);
+
+ /* Get INTRODUCE1 keys */
+ retval = hs_ntor_service_get_introduce1_keys(&intro_auth_pubkey,
+ &intro_enc_keypair,
+ &client_ephemeral_enc_pubkey,
+ subcredential,
+ &hs_ntor_intro_cell_keys);
+ if (retval < 0) {
+ goto done;
+ }
+
+ /* Get RENDEZVOUS1 keys */
+ retval = hs_ntor_service_get_rendezvous1_keys(&intro_auth_pubkey,
+ &intro_enc_keypair,
+ &service_ephemeral_rend_keypair,
+ &client_ephemeral_enc_pubkey,
+ &hs_ntor_rend_cell_keys);
+ if (retval < 0) {
+ goto done;
+ }
+
+ /* Send ENC_KEY */
+ base16_encode(buf, sizeof(buf),
+ (const char*)hs_ntor_intro_cell_keys.enc_key,
+ sizeof(hs_ntor_intro_cell_keys.enc_key));
+ printf("%s\n", buf);
+ /* Send MAC_KEY */
+ base16_encode(buf, sizeof(buf),
+ (const char*)hs_ntor_intro_cell_keys.mac_key,
+ sizeof(hs_ntor_intro_cell_keys.mac_key));
+ printf("%s\n", buf);
+ /* Send AUTH_MAC */
+ base16_encode(buf, sizeof(buf),
+ (const char*)hs_ntor_rend_cell_keys.rend_cell_auth_mac,
+ sizeof(hs_ntor_rend_cell_keys.rend_cell_auth_mac));
+ printf("%s\n", buf);
+ /* Send NTOR_KEY_SEED */
+ base16_encode(buf, sizeof(buf),
+ (const char*)hs_ntor_rend_cell_keys.ntor_key_seed,
+ sizeof(hs_ntor_rend_cell_keys.ntor_key_seed));
+ printf("%s\n", buf);
+ /* Send service ephemeral pubkey (Y) */
+ base16_encode(buf, sizeof(buf),
+ (const char*)service_ephemeral_rend_keypair.pubkey.public_key,
+ sizeof(service_ephemeral_rend_keypair.pubkey.public_key));
+ printf("%s\n", buf);
+
+ done:
+ return retval;
+}
+
+/** The final step of the ntor protocol, the client computes and returns the
+ * rendezvous key material. */
+static int
+client2(int argc, char **argv)
+{
+ int retval;
+
+ /* Inputs */
+ curve25519_public_key_t intro_enc_pubkey;
+ ed25519_public_key_t intro_auth_pubkey;
+ curve25519_keypair_t client_ephemeral_enc_keypair;
+ curve25519_public_key_t service_ephemeral_rend_pubkey;
+ uint8_t subcredential[DIGEST256_LEN];
+
+ /* Output */
+ hs_ntor_rend_cell_keys_t hs_ntor_rend_cell_keys;
+
+ char buf[256];
+
+ N_ARGS(7);
+ BASE16(2, intro_auth_pubkey.pubkey, ED25519_PUBKEY_LEN);
+ BASE16(3, client_ephemeral_enc_keypair.seckey.secret_key,
+ CURVE25519_SECKEY_LEN);
+ BASE16(4, intro_enc_pubkey.public_key, CURVE25519_PUBKEY_LEN);
+ BASE16(5, service_ephemeral_rend_pubkey.public_key, CURVE25519_PUBKEY_LEN);
+ BASE16(6, subcredential, DIGEST256_LEN);
+
+ /* Generate keypair */
+ curve25519_public_key_generate(&client_ephemeral_enc_keypair.pubkey,
+ &client_ephemeral_enc_keypair.seckey);
+
+ /* Get RENDEZVOUS1 keys */
+ retval = hs_ntor_client_get_rendezvous1_keys(&intro_auth_pubkey,
+ &client_ephemeral_enc_keypair,
+ &intro_enc_pubkey,
+ &service_ephemeral_rend_pubkey,
+ &hs_ntor_rend_cell_keys);
+ if (retval < 0) {
+ goto done;
+ }
+
+ /* Send AUTH_MAC */
+ base16_encode(buf, sizeof(buf),
+ (const char*)hs_ntor_rend_cell_keys.rend_cell_auth_mac,
+ sizeof(hs_ntor_rend_cell_keys.rend_cell_auth_mac));
+ printf("%s\n", buf);
+ /* Send NTOR_KEY_SEED */
+ base16_encode(buf, sizeof(buf),
+ (const char*)hs_ntor_rend_cell_keys.ntor_key_seed,
+ sizeof(hs_ntor_rend_cell_keys.ntor_key_seed));
+ printf("%s\n", buf);
+
+ done:
+ return 1;
+}
+
+/** Perform a different part of the protocol depdning on the argv used. */
+int
+main(int argc, char **argv)
+{
+ if (argc < 2) {
+ fprintf(stderr, "I need arguments. Read source for more info.\n");
+ return 1;
+ }
+
+ curve25519_init();
+ 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_hs_service.c b/src/test/test_hs_service.c
index 039d727cea..fcfb3b992d 100644
--- a/src/test/test_hs_service.c
+++ b/src/test/test_hs_service.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Tor Project, Inc. */
+/* Copyright (c) 2016-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -6,6 +6,7 @@
* \brief Test hidden service functionality.
*/
+#define HS_COMMON_PRIVATE
#define HS_SERVICE_PRIVATE
#define HS_INTROPOINT_PRIVATE
@@ -14,9 +15,12 @@
#include "crypto.h"
#include "hs/cell_establish_intro.h"
+#include "hs_common.h"
#include "hs_service.h"
#include "hs_intropoint.h"
+#include "hs_ntor.h"
+
/** We simulate the creation of an outgoing ESTABLISH_INTRO cell, and then we
* parse it from the receiver side. */
static void
@@ -26,8 +30,8 @@ test_gen_establish_intro_cell(void *arg)
ssize_t retval;
uint8_t circuit_key_material[DIGEST_LEN] = {0};
uint8_t buf[RELAY_PAYLOAD_SIZE];
- hs_cell_establish_intro_t *cell_out = NULL;
- hs_cell_establish_intro_t *cell_in = NULL;
+ trn_cell_establish_intro_t *cell_out = NULL;
+ trn_cell_establish_intro_t *cell_in = NULL;
crypto_rand((char *) circuit_key_material, sizeof(circuit_key_material));
@@ -44,7 +48,7 @@ test_gen_establish_intro_cell(void *arg)
/* Parse it as the receiver */
{
- ssize_t parse_result = hs_cell_establish_intro_parse(&cell_in,
+ ssize_t parse_result = trn_cell_establish_intro_parse(&cell_in,
buf, sizeof(buf));
tt_int_op(parse_result, >=, 0);
@@ -55,8 +59,8 @@ test_gen_establish_intro_cell(void *arg)
}
done:
- hs_cell_establish_intro_free(cell_out);
- hs_cell_establish_intro_free(cell_in);
+ trn_cell_establish_intro_free(cell_out);
+ trn_cell_establish_intro_free(cell_in);
}
/* Mocked ed25519_sign_prefixed() function that always fails :) */
@@ -78,7 +82,7 @@ static void
test_gen_establish_intro_cell_bad(void *arg)
{
(void) arg;
- hs_cell_establish_intro_t *cell = NULL;
+ trn_cell_establish_intro_t *cell = NULL;
uint8_t circuit_key_material[DIGEST_LEN] = {0};
MOCK(ed25519_sign_prefixed, mock_ed25519_sign_prefixed);
@@ -96,15 +100,150 @@ test_gen_establish_intro_cell_bad(void *arg)
tt_assert(!cell);
done:
- hs_cell_establish_intro_free(cell);
+ trn_cell_establish_intro_free(cell);
UNMOCK(ed25519_sign_prefixed);
}
+/** Test the HS ntor handshake. Simulate the sending of an encrypted INTRODUCE1
+ * cell, and verify the proper derivation of decryption keys on the other end.
+ * Then simulate the sending of an authenticated RENDEZVOUS1 cell and verify
+ * the proper verification on the other end. */
+static void
+test_hs_ntor(void *arg)
+{
+ int retval;
+
+ uint8_t subcredential[DIGEST256_LEN];
+
+ ed25519_keypair_t service_intro_auth_keypair;
+ curve25519_keypair_t service_intro_enc_keypair;
+ curve25519_keypair_t service_ephemeral_rend_keypair;
+
+ curve25519_keypair_t client_ephemeral_enc_keypair;
+
+ hs_ntor_intro_cell_keys_t client_hs_ntor_intro_cell_keys;
+ hs_ntor_intro_cell_keys_t service_hs_ntor_intro_cell_keys;
+
+ hs_ntor_rend_cell_keys_t service_hs_ntor_rend_cell_keys;
+ hs_ntor_rend_cell_keys_t client_hs_ntor_rend_cell_keys;
+
+ (void) arg;
+
+ /* Generate fake data for this unittest */
+ {
+ /* Generate fake subcredential */
+ memset(subcredential, 'Z', DIGEST256_LEN);
+
+ /* service */
+ curve25519_keypair_generate(&service_intro_enc_keypair, 0);
+ ed25519_keypair_generate(&service_intro_auth_keypair, 0);
+ curve25519_keypair_generate(&service_ephemeral_rend_keypair, 0);
+ /* client */
+ curve25519_keypair_generate(&client_ephemeral_enc_keypair, 0);
+ }
+
+ /* Client: Simulate the sending of an encrypted INTRODUCE1 cell */
+ retval =
+ hs_ntor_client_get_introduce1_keys(&service_intro_auth_keypair.pubkey,
+ &service_intro_enc_keypair.pubkey,
+ &client_ephemeral_enc_keypair,
+ subcredential,
+ &client_hs_ntor_intro_cell_keys);
+ tt_int_op(retval, ==, 0);
+
+ /* Service: Simulate the decryption of the received INTRODUCE1 */
+ retval =
+ hs_ntor_service_get_introduce1_keys(&service_intro_auth_keypair.pubkey,
+ &service_intro_enc_keypair,
+ &client_ephemeral_enc_keypair.pubkey,
+ subcredential,
+ &service_hs_ntor_intro_cell_keys);
+ tt_int_op(retval, ==, 0);
+
+ /* Test that the INTRODUCE1 encryption/mac keys match! */
+ tt_mem_op(client_hs_ntor_intro_cell_keys.enc_key, OP_EQ,
+ service_hs_ntor_intro_cell_keys.enc_key,
+ CIPHER256_KEY_LEN);
+ tt_mem_op(client_hs_ntor_intro_cell_keys.mac_key, OP_EQ,
+ service_hs_ntor_intro_cell_keys.mac_key,
+ DIGEST256_LEN);
+
+ /* Service: Simulate creation of RENDEZVOUS1 key material. */
+ retval =
+ hs_ntor_service_get_rendezvous1_keys(&service_intro_auth_keypair.pubkey,
+ &service_intro_enc_keypair,
+ &service_ephemeral_rend_keypair,
+ &client_ephemeral_enc_keypair.pubkey,
+ &service_hs_ntor_rend_cell_keys);
+ tt_int_op(retval, ==, 0);
+
+ /* Client: Simulate the verification of a received RENDEZVOUS1 cell */
+ retval =
+ hs_ntor_client_get_rendezvous1_keys(&service_intro_auth_keypair.pubkey,
+ &client_ephemeral_enc_keypair,
+ &service_intro_enc_keypair.pubkey,
+ &service_ephemeral_rend_keypair.pubkey,
+ &client_hs_ntor_rend_cell_keys);
+ tt_int_op(retval, ==, 0);
+
+ /* Test that the RENDEZVOUS1 key material match! */
+ tt_mem_op(client_hs_ntor_rend_cell_keys.rend_cell_auth_mac, OP_EQ,
+ service_hs_ntor_rend_cell_keys.rend_cell_auth_mac,
+ DIGEST256_LEN);
+ tt_mem_op(client_hs_ntor_rend_cell_keys.ntor_key_seed, OP_EQ,
+ service_hs_ntor_rend_cell_keys.ntor_key_seed,
+ DIGEST256_LEN);
+
+ done:
+ ;
+}
+
+/** Test that our HS time period calculation functions work properly */
+static void
+test_time_period(void *arg)
+{
+ (void) arg;
+ uint64_t tn;
+ int retval;
+ time_t fake_time;
+
+ /* Let's do the example in prop224 section [TIME-PERIODS] */
+ retval = parse_rfc1123_time("Wed, 13 Apr 2016 11:00:00 UTC",
+ &fake_time);
+ tt_int_op(retval, ==, 0);
+
+ /* Check that the time period number is right */
+ tn = get_time_period_num(fake_time);
+ tt_u64_op(tn, ==, 16903);
+
+ /* Increase current time to 11:59:59 UTC and check that the time period
+ number is still the same */
+ fake_time += 3599;
+ tn = get_time_period_num(fake_time);
+ tt_u64_op(tn, ==, 16903);
+
+ /* Now take time to 12:00:00 UTC and check that the time period rotated */
+ fake_time += 1;
+ tn = get_time_period_num(fake_time);
+ tt_u64_op(tn, ==, 16904);
+
+ /* Now also check our hs_get_next_time_period_num() function */
+ tn = hs_get_next_time_period_num(fake_time);
+ tt_u64_op(tn, ==, 16905);
+
+ done:
+ ;
+}
+
struct testcase_t hs_service_tests[] = {
{ "gen_establish_intro_cell", test_gen_establish_intro_cell, TT_FORK,
NULL, NULL },
{ "gen_establish_intro_cell_bad", test_gen_establish_intro_cell_bad, TT_FORK,
NULL, NULL },
+ { "hs_ntor", test_hs_ntor, TT_FORK,
+ NULL, NULL },
+ { "time_period", test_time_period, TT_FORK,
+ NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_introduce.c b/src/test/test_introduce.c
index 810b03c93d..cfb8d83b1d 100644
--- a/src/test/test_introduce.c
+++ b/src/test/test_introduce.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Tor Project, Inc. */
+/* Copyright (c) 2012-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_keypin.c b/src/test/test_keypin.c
index 95657349c6..d2ec8e9ca7 100644
--- a/src/test/test_keypin.c
+++ b/src/test/test_keypin.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Tor Project, Inc. */
+/* Copyright (c) 2014-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_link_handshake.c b/src/test/test_link_handshake.c
index 421f3aaedf..217088ee37 100644
--- a/src/test/test_link_handshake.c
+++ b/src/test/test_link_handshake.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Tor Project, Inc. */
+/* Copyright (c) 2014-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -10,13 +10,6 @@
#include "compat.h"
-/* Some versions of OpenSSL declare SSL_get_selected_srtp_profile twice in
- * srtp.h. Suppress the GCC warning so we can build with -Wredundant-decl. */
-DISABLE_GCC_WARNING(redundant-decls)
-#include <openssl/x509.h>
-#include <openssl/ssl.h>
-ENABLE_GCC_WARNING(redundant-decls)
-
#include "or.h"
#include "config.h"
#include "connection.h"
@@ -785,19 +778,14 @@ CERTS_FAIL(expired_rsa_id, /* both */
certs_cell_cert_t *cert = certs_cell_get_certs(d->ccell, 1);
const tor_x509_cert_t *idc;
tor_tls_get_my_certs(1, NULL, &idc);
- X509 *newc = X509_dup(idc->cert);
+ tor_x509_cert_t *newc;
time_t new_end = time(NULL) - 86400 * 10;
- X509_time_adj(X509_get_notAfter(newc), 0, &new_end);
- EVP_PKEY *pk = crypto_pk_get_evp_pkey_(d->key2, 1);
- tt_assert(X509_sign(newc, pk, EVP_sha1()));
- int len = i2d_X509(newc, NULL);
- certs_cell_cert_setlen_body(cert, len);
- uint8_t *body = certs_cell_cert_getarray_body(cert);
- int len2 = i2d_X509(newc, &body);
- tt_int_op(len, ==, len2);
+ newc = tor_x509_cert_replace_expiration(idc, new_end, d->key2);
+ certs_cell_cert_setlen_body(cert, newc->encoded_len);
+ memcpy(certs_cell_cert_getarray_body(cert),
+ newc->encoded, newc->encoded_len);
REENCODE();
- X509_free(newc);
- EVP_PKEY_free(pk);
+ tor_x509_cert_free(newc);
})
CERTS_FAIL(expired_ed_id, /* ed25519 */
{
diff --git a/src/test/test_logging.c b/src/test/test_logging.c
index 15471e46d0..94b3e4ea68 100644
--- a/src/test/test_logging.c
+++ b/src/test/test_logging.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2016, The Tor Project, Inc. */
+/* Copyright (c) 2013-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_microdesc.c b/src/test/test_microdesc.c
index 2ae605b8db..c78fda3b69 100644
--- a/src/test/test_microdesc.c
+++ b/src/test/test_microdesc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2016, The Tor Project, Inc. */
+/* Copyright (c) 2010-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -14,12 +14,6 @@
#include "test.h"
-DISABLE_GCC_WARNING(redundant-decls)
-#include <openssl/rsa.h>
-#include <openssl/bn.h>
-#include <openssl/pem.h>
-ENABLE_GCC_WARNING(redundant-decls)
-
#ifdef _WIN32
/* For mkdir() */
#include <direct.h>
diff --git a/src/test/test_nodelist.c b/src/test/test_nodelist.c
index d58f8a7fca..256354415c 100644
--- a/src/test/test_nodelist.c
+++ b/src/test/test_nodelist.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2016, The Tor Project, Inc. */
+/* Copyright (c) 2007-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/test/test_ntor_cl.c b/src/test/test_ntor_cl.c
index a560e5fc5e..d0eea85d6f 100644
--- a/src/test/test_ntor_cl.c
+++ b/src/test/test_ntor_cl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Tor Project, Inc. */
+/* Copyright (c) 2012-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_oom.c b/src/test/test_oom.c
index 0f97972032..f03a504d1d 100644
--- a/src/test/test_oom.c
+++ b/src/test/test_oom.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Tor Project, Inc. */
+/* Copyright (c) 2014-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/* Unit tests for OOM handling logic */
diff --git a/src/test/test_oos.c b/src/test/test_oos.c
index db06625116..9fd6bce5ae 100644
--- a/src/test/test_oos.c
+++ b/src/test/test_oos.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Tor Project, Inc. */
+/* Copyright (c) 2016-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/* Unit tests for OOS handler */
diff --git a/src/test/test_options.c b/src/test/test_options.c
index d5782e9ec0..29f6665f23 100644
--- a/src/test/test_options.c
+++ b/src/test/test_options.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2016, The Tor Project, Inc. */
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CONFIG_PRIVATE
@@ -105,27 +105,13 @@ clear_log_messages(void)
"EDE6D711294FADF8E7951F4DE6CA56B58 194.109.206.212:80 7EA6 EAD6 FD83" \
" 083C 538F 4403 8BBF A077 587D D755\n"
-static void
-test_options_validate_impl(const char *configuration,
- const char *expect_errmsg,
- int expect_log_severity,
- const char *expect_log)
+static int
+test_options_checkmsgs(const char *configuration,
+ const char *expect_errmsg,
+ int expect_log_severity,
+ const char *expect_log,
+ char *msg)
{
- or_options_t *opt=NULL;
- or_options_t *dflt;
- config_line_t *cl=NULL;
- char *msg=NULL;
- int r;
-
- setup_options(opt, dflt);
-
- r = config_get_lines(configuration, &cl, 1);
- tt_int_op(r, OP_EQ, 0);
-
- r = config_assign(&options_format, opt, cl, 0, &msg);
- tt_int_op(r, OP_EQ, 0);
-
- r = options_validate(NULL, opt, dflt, 0, &msg);
if (expect_errmsg && !msg) {
TT_DIE(("Expected error message <%s> from <%s>, but got none.",
expect_errmsg, configuration));
@@ -136,8 +122,6 @@ test_options_validate_impl(const char *configuration,
TT_DIE(("Expected no error message from <%s> but got <%s>.",
configuration, msg));
}
- tt_int_op((r == 0), OP_EQ, (msg == NULL));
-
if (expect_log) {
int found = 0;
if (messages) {
@@ -157,6 +141,56 @@ test_options_validate_impl(const char *configuration,
configuration, msg));
}
}
+ return 0;
+
+ done:
+ return -1;
+}
+
+/* Which phases of config parsing/validation to check for messages/logs */
+enum { PH_GETLINES, PH_ASSIGN, PH_VALIDATE };
+
+static void
+test_options_validate_impl(const char *configuration,
+ const char *expect_errmsg,
+ int expect_log_severity,
+ const char *expect_log,
+ int phase)
+{
+ or_options_t *opt=NULL;
+ or_options_t *dflt;
+ config_line_t *cl=NULL;
+ char *msg=NULL;
+ int r;
+
+ setup_options(opt, dflt);
+
+ r = config_get_lines(configuration, &cl, 1);
+ if (phase == PH_GETLINES) {
+ if (test_options_checkmsgs(configuration, expect_errmsg,
+ expect_log_severity,
+ expect_log, msg))
+ goto done;
+ }
+ tt_int_op((r == 0), OP_EQ, (msg == NULL));
+
+ r = config_assign(&options_format, opt, cl, 0, &msg);
+ if (phase == PH_ASSIGN) {
+ if (test_options_checkmsgs(configuration, expect_errmsg,
+ expect_log_severity,
+ expect_log, msg))
+ goto done;
+ }
+ tt_int_op((r == 0), OP_EQ, (msg == NULL));
+
+ r = options_validate(NULL, opt, dflt, 0, &msg);
+ if (phase == PH_VALIDATE) {
+ if (test_options_checkmsgs(configuration, expect_errmsg,
+ expect_log_severity,
+ expect_log, msg))
+ goto done;
+ }
+ tt_int_op((r == 0), OP_EQ, (msg == NULL));
done:
escaped(NULL);
@@ -168,14 +202,14 @@ test_options_validate_impl(const char *configuration,
clear_log_messages();
}
-#define WANT_ERR(config, msg) \
- test_options_validate_impl((config), (msg), 0, NULL)
-#define WANT_LOG(config, severity, msg) \
- test_options_validate_impl((config), NULL, (severity), (msg))
-#define WANT_ERR_LOG(config, msg, severity, logmsg) \
- test_options_validate_impl((config), (msg), (severity), (logmsg))
-#define OK(config) \
- test_options_validate_impl((config), NULL, 0, NULL)
+#define WANT_ERR(config, msg, ph) \
+ test_options_validate_impl((config), (msg), 0, NULL, (ph))
+#define WANT_LOG(config, severity, msg, ph) \
+ test_options_validate_impl((config), NULL, (severity), (msg), (ph))
+#define WANT_ERR_LOG(config, msg, severity, logmsg, ph) \
+ test_options_validate_impl((config), (msg), (severity), (logmsg), (ph))
+#define OK(config, ph) \
+ test_options_validate_impl((config), NULL, 0, NULL, (ph))
static void
test_options_validate(void *arg)
@@ -184,21 +218,32 @@ test_options_validate(void *arg)
setup_log_callback();
sandbox_disable_getaddrinfo_cache();
- WANT_ERR("ExtORPort 500000", "Invalid ExtORPort");
+ WANT_ERR("ExtORPort 500000", "Invalid ExtORPort", PH_VALIDATE);
WANT_ERR_LOG("ServerTransportOptions trebuchet",
"ServerTransportOptions did not parse",
- LOG_WARN, "Too few arguments");
- OK("ServerTransportOptions trebuchet sling=snappy");
- OK("ServerTransportOptions trebuchet sling=");
+ LOG_WARN, "Too few arguments", PH_VALIDATE);
+ OK("ServerTransportOptions trebuchet sling=snappy", PH_VALIDATE);
+ OK("ServerTransportOptions trebuchet sling=", PH_VALIDATE);
WANT_ERR_LOG("ServerTransportOptions trebuchet slingsnappy",
"ServerTransportOptions did not parse",
- LOG_WARN, "\"slingsnappy\" is not a k=v");
+ LOG_WARN, "\"slingsnappy\" is not a k=v", PH_VALIDATE);
WANT_ERR("DirPort 8080\nDirCache 0",
- "DirPort configured but DirCache disabled.");
+ "DirPort configured but DirCache disabled.", PH_VALIDATE);
WANT_ERR("BridgeRelay 1\nDirCache 0",
- "We're a bridge but DirCache is disabled.");
+ "We're a bridge but DirCache is disabled.", PH_VALIDATE);
+
+ WANT_ERR_LOG("HeartbeatPeriod 21 snarks",
+ "Interval 'HeartbeatPeriod 21 snarks' is malformed or"
+ " out of bounds.", LOG_WARN, "Unknown unit 'snarks'.",
+ PH_ASSIGN);
+ WANT_ERR_LOG("LogTimeGranularity 21 snarks",
+ "Msec interval 'LogTimeGranularity 21 snarks' is malformed or"
+ " out of bounds.", LOG_WARN, "Unknown unit 'snarks'.",
+ PH_ASSIGN);
+ OK("HeartbeatPeriod 1 hour", PH_VALIDATE);
+ OK("LogTimeGranularity 100 milliseconds", PH_VALIDATE);
close_temp_logs();
clear_log_messages();
diff --git a/src/test/test_policy.c b/src/test/test_policy.c
index e86d0f0274..1b2fac4325 100644
--- a/src/test/test_policy.c
+++ b/src/test/test_policy.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2016, The Tor Project, Inc. */
+/* Copyright (c) 2013-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "or.h"
diff --git a/src/test/test_procmon.c b/src/test/test_procmon.c
index 9e63fc006d..5c52af8693 100644
--- a/src/test/test_procmon.c
+++ b/src/test/test_procmon.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2016, The Tor Project, Inc. */
+/* Copyright (c) 2010-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define PROCMON_PRIVATE
diff --git a/src/test/test_protover.c b/src/test/test_protover.c
index f00955d1b4..5626816024 100644
--- a/src/test/test_protover.c
+++ b/src/test/test_protover.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Tor Project, Inc. */
+/* Copyright (c) 2016-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define PROTOVER_PRIVATE
diff --git a/src/test/test_pt.c b/src/test/test_pt.c
index f93019f1c4..79b03171bc 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-2016, The Tor Project, Inc. */
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -284,13 +284,13 @@ test_pt_get_extrainfo_string(void *arg)
}
#ifdef _WIN32
-#define STDIN_HANDLE HANDLE
+#define STDIN_HANDLE HANDLE*
#else
-#define STDIN_HANDLE FILE
+#define STDIN_HANDLE int
#endif
static smartlist_t *
-tor_get_lines_from_handle_replacement(STDIN_HANDLE *handle,
+tor_get_lines_from_handle_replacement(STDIN_HANDLE handle,
enum stream_status *stream_status_out)
{
static int times_called = 0;
diff --git a/src/test/test_pubsub.c b/src/test/test_pubsub.c
index 547d6c6b32..2f047d9f2c 100644
--- a/src/test/test_pubsub.c
+++ b/src/test/test_pubsub.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Tor Project, Inc. */
+/* Copyright (c) 2016-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/test/test_relay.c b/src/test/test_relay.c
index 4713c79ea5..238d4c5baf 100644
--- a/src/test/test_relay.c
+++ b/src/test/test_relay.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Tor Project, Inc. */
+/* Copyright (c) 2014-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "or.h"
diff --git a/src/test/test_relaycell.c b/src/test/test_relaycell.c
index fb6748965a..eea1f5dc80 100644
--- a/src/test/test_relaycell.c
+++ b/src/test/test_relaycell.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Tor Project, Inc. */
+/* Copyright (c) 2014-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/* Unit tests for handling different kinds of relay cell */
diff --git a/src/test/test_rendcache.c b/src/test/test_rendcache.c
index 0d53c78817..feba8f664e 100644
--- a/src/test/test_rendcache.c
+++ b/src/test/test_rendcache.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2016, The Tor Project, Inc. */
+/* Copyright (c) 2010-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -11,7 +11,6 @@
#include "routerlist.h"
#include "config.h"
#include "hs_common.h"
-#include <openssl/rsa.h>
#include "rend_test_helpers.h"
#include "log_test_helpers.h"
diff --git a/src/test/test_replay.c b/src/test/test_replay.c
index e882bc6164..80e7203716 100644
--- a/src/test/test_replay.c
+++ b/src/test/test_replay.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Tor Project, Inc. */
+/* Copyright (c) 2012-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define REPLAYCACHE_PRIVATE
diff --git a/src/test/test_routerkeys.c b/src/test/test_routerkeys.c
index 64692d28a0..263923f50f 100644
--- a/src/test/test_routerkeys.c
+++ b/src/test/test_routerkeys.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2016, The Tor Project, Inc. */
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_routerlist.c b/src/test/test_routerlist.c
index 78f1cf16b7..0b4b6c5c44 100644
--- a/src/test/test_routerlist.c
+++ b/src/test/test_routerlist.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Tor Project, Inc. */
+/* Copyright (c) 2014-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_scheduler.c b/src/test/test_scheduler.c
index 05ea8e86e8..4c536b0905 100644
--- a/src/test/test_scheduler.c
+++ b/src/test/test_scheduler.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Tor Project, Inc. */
+/* Copyright (c) 2014-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_slow.c b/src/test/test_slow.c
index 7c9f0b1cc2..e640702499 100644
--- a/src/test/test_slow.c
+++ b/src/test/test_slow.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2016, The Tor Project, Inc. */
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/test/test_socks.c b/src/test/test_socks.c
index 62ff12fe15..bb1be11f2b 100644
--- a/src/test/test_socks.c
+++ b/src/test/test_socks.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2016, The Tor Project, Inc. */
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "or.h"
diff --git a/src/test/test_storagedir.c b/src/test/test_storagedir.c
new file mode 100644
index 0000000000..19e5de4ea3
--- /dev/null
+++ b/src/test/test_storagedir.c
@@ -0,0 +1,375 @@
+/* Copyright (c) 2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "or.h"
+#include "storagedir.h"
+#include "test.h"
+
+#ifdef HAVE_UTIME_H
+#include <utime.h>
+#endif
+
+static void
+test_storagedir_empty(void *arg)
+{
+ char *dirname = tor_strdup(get_fname_rnd("store_dir"));
+ storage_dir_t *d = NULL;
+ (void)arg;
+
+ tt_int_op(FN_NOENT, OP_EQ, file_status(dirname));
+
+ d = storage_dir_new(dirname, 10);
+ tt_assert(d);
+
+ tt_int_op(FN_DIR, OP_EQ, file_status(dirname));
+
+ tt_int_op(0, OP_EQ, smartlist_len(storage_dir_list(d)));
+ tt_u64_op(0, OP_EQ, storage_dir_get_usage(d));
+
+ storage_dir_free(d);
+ d = storage_dir_new(dirname, 10);
+ tt_assert(d);
+
+ tt_int_op(FN_DIR, OP_EQ, file_status(dirname));
+
+ tt_int_op(0, OP_EQ, smartlist_len(storage_dir_list(d)));
+ tt_u64_op(0, OP_EQ, storage_dir_get_usage(d));
+
+ done:
+ storage_dir_free(d);
+ tor_free(dirname);
+}
+
+static void
+test_storagedir_basic(void *arg)
+{
+ char *dirname = tor_strdup(get_fname_rnd("store_dir"));
+ storage_dir_t *d = NULL;
+ uint8_t *junk = NULL, *bytes = NULL;
+ const size_t junklen = 1024;
+ char *fname1 = NULL, *fname2 = NULL;
+ const char hello_str[] = "then what are we but cold, alone ... ?";
+ tor_mmap_t *mapping = NULL;
+ (void)arg;
+
+ junk = tor_malloc(junklen);
+ crypto_rand((void*)junk, junklen);
+
+ d = storage_dir_new(dirname, 10);
+ tt_assert(d);
+ tt_u64_op(0, OP_EQ, storage_dir_get_usage(d));
+
+ int r;
+ r = storage_dir_save_string_to_file(d, hello_str, 1, &fname1);
+ tt_int_op(r, OP_EQ, 0);
+ tt_ptr_op(fname1, OP_NE, NULL);
+ tt_u64_op(strlen(hello_str), OP_EQ, storage_dir_get_usage(d));
+
+ r = storage_dir_save_bytes_to_file(d, junk, junklen, 1, &fname2);
+ tt_int_op(r, OP_EQ, 0);
+ tt_ptr_op(fname2, OP_NE, NULL);
+
+ tt_str_op(fname1, OP_NE, fname2);
+
+ tt_int_op(2, OP_EQ, smartlist_len(storage_dir_list(d)));
+ tt_u64_op(junklen + strlen(hello_str), OP_EQ, storage_dir_get_usage(d));
+ tt_assert(smartlist_contains_string(storage_dir_list(d), fname1));
+ tt_assert(smartlist_contains_string(storage_dir_list(d), fname2));
+
+ storage_dir_free(d);
+ d = storage_dir_new(dirname, 10);
+ tt_assert(d);
+ tt_int_op(2, OP_EQ, smartlist_len(storage_dir_list(d)));
+ tt_u64_op(junklen + strlen(hello_str), OP_EQ, storage_dir_get_usage(d));
+ tt_assert(smartlist_contains_string(storage_dir_list(d), fname1));
+ tt_assert(smartlist_contains_string(storage_dir_list(d), fname2));
+
+ size_t n;
+ bytes = storage_dir_read(d, fname2, 1, &n);
+ tt_assert(bytes);
+ tt_u64_op(n, OP_EQ, junklen);
+ tt_mem_op(bytes, OP_EQ, junk, junklen);
+
+ mapping = storage_dir_map(d, fname1);
+ tt_assert(mapping);
+ tt_u64_op(mapping->size, OP_EQ, strlen(hello_str));
+ tt_mem_op(mapping->data, OP_EQ, hello_str, strlen(hello_str));
+
+ done:
+ tor_free(dirname);
+ tor_free(junk);
+ tor_free(bytes);
+ tor_munmap_file(mapping);
+ storage_dir_free(d);
+ tor_free(fname1);
+ tor_free(fname2);
+}
+
+static void
+test_storagedir_deletion(void *arg)
+{
+ (void)arg;
+ char *dirname = tor_strdup(get_fname_rnd("store_dir"));
+ storage_dir_t *d = NULL;
+ char *fn1 = NULL, *fn2 = NULL;
+ char *bytes = NULL;
+ int r;
+ const char str1[] = "There are nine and sixty ways to disguise communiques";
+ const char str2[] = "And rather more than one of them is right";
+
+ // Make sure the directory is there. */
+ d = storage_dir_new(dirname, 10);
+ storage_dir_free(d);
+ d = NULL;
+
+ tor_asprintf(&fn1, "%s/1007", dirname);
+ r = write_str_to_file(fn1, str1, 0);
+ tt_int_op(r, OP_EQ, 0);
+
+ tor_asprintf(&fn2, "%s/1003.tmp", dirname);
+ r = write_str_to_file(fn2, str2, 0);
+ tt_int_op(r, OP_EQ, 0);
+
+ // The tempfile should be deleted the next time we list the directory.
+ d = storage_dir_new(dirname, 10);
+ tt_int_op(1, OP_EQ, smartlist_len(storage_dir_list(d)));
+ tt_u64_op(strlen(str1), OP_EQ, storage_dir_get_usage(d));
+ tt_int_op(FN_FILE, OP_EQ, file_status(fn1));
+ tt_int_op(FN_NOENT, OP_EQ, file_status(fn2));
+
+ bytes = (char*) storage_dir_read(d, "1007", 1, NULL);
+ tt_str_op(bytes, OP_EQ, str1);
+
+ // Should have no effect; file already gone.
+ storage_dir_remove_file(d, "1003.tmp");
+ tt_int_op(1, OP_EQ, smartlist_len(storage_dir_list(d)));
+ tt_u64_op(strlen(str1), OP_EQ, storage_dir_get_usage(d));
+
+ // Actually remove a file.
+ storage_dir_remove_file(d, "1007");
+ tt_int_op(FN_NOENT, OP_EQ, file_status(fn1));
+ tt_int_op(0, OP_EQ, smartlist_len(storage_dir_list(d)));
+ tt_u64_op(0, OP_EQ, storage_dir_get_usage(d));
+
+ done:
+ tor_free(dirname);
+ tor_free(fn1);
+ tor_free(fn2);
+ storage_dir_free(d);
+ tor_free(bytes);
+}
+
+static void
+test_storagedir_full(void *arg)
+{
+ (void)arg;
+
+ char *dirname = tor_strdup(get_fname_rnd("store_dir"));
+ storage_dir_t *d = NULL;
+ const char str[] = "enemies of the peephole";
+ int r;
+
+ d = storage_dir_new(dirname, 3);
+ tt_assert(d);
+
+ r = storage_dir_save_string_to_file(d, str, 1, NULL);
+ tt_int_op(r, OP_EQ, 0);
+ r = storage_dir_save_string_to_file(d, str, 1, NULL);
+ tt_int_op(r, OP_EQ, 0);
+ r = storage_dir_save_string_to_file(d, str, 1, NULL);
+ tt_int_op(r, OP_EQ, 0);
+
+ // These should fail!
+ r = storage_dir_save_string_to_file(d, str, 1, NULL);
+ tt_int_op(r, OP_EQ, -1);
+ r = storage_dir_save_string_to_file(d, str, 1, NULL);
+ tt_int_op(r, OP_EQ, -1);
+
+ tt_u64_op(strlen(str) * 3, OP_EQ, storage_dir_get_usage(d));
+
+ done:
+ tor_free(dirname);
+ storage_dir_free(d);
+}
+
+static void
+test_storagedir_cleaning(void *arg)
+{
+ (void)arg;
+
+ char *dirname = tor_strdup(get_fname_rnd("store_dir"));
+ storage_dir_t *d = NULL;
+ const char str[] =
+ "On a mountain halfway between Reno and Rome / "
+ "We have a machine in a plexiglass dome / "
+ "Which listens and looks into everyone's home."
+ " -- Dr. Seuss";
+ char *fns[8];
+ int r, i;
+
+ memset(fns, 0, sizeof(fns));
+ d = storage_dir_new(dirname, 10);
+ tt_assert(d);
+
+ for (i = 0; i < 8; ++i) {
+ r = storage_dir_save_string_to_file(d, str+i*2, 1, &fns[i]);
+ tt_int_op(r, OP_EQ, 0);
+ }
+
+ /* Now we're going to make sure all the files have distinct mtimes. */
+ time_t now = time(NULL);
+ struct utimbuf ub;
+ ub.actime = now;
+ ub.modtime = now - 1000;
+ for (i = 0; i < 8; ++i) {
+ char *f = NULL;
+ tor_asprintf(&f, "%s/%s", dirname, fns[i]);
+ r = utime(f, &ub);
+ tor_free(f);
+ tt_int_op(r, OP_EQ, 0);
+ ub.modtime += 5;
+ }
+
+ const uint64_t usage_orig = storage_dir_get_usage(d);
+ /* No changes needed if we are already under target. */
+ storage_dir_shrink(d, 1024*1024, 0);
+ tt_u64_op(usage_orig, OP_EQ, storage_dir_get_usage(d));
+
+ /* Get rid of at least one byte. This will delete fns[0]. */
+ storage_dir_shrink(d, usage_orig - 1, 0);
+ tt_u64_op(usage_orig, OP_GT, storage_dir_get_usage(d));
+ tt_u64_op(usage_orig - strlen(str), OP_EQ, storage_dir_get_usage(d));
+
+ /* Get rid of at least two files. This will delete fns[1] and fns[2]. */
+ storage_dir_shrink(d, 1024*1024, 2);
+ tt_u64_op(usage_orig - strlen(str)*3 + 6, OP_EQ, storage_dir_get_usage(d));
+
+ /* Get rid of everything. */
+ storage_dir_remove_all(d);
+ tt_u64_op(0, OP_EQ, storage_dir_get_usage(d));
+
+ done:
+ tor_free(dirname);
+ storage_dir_free(d);
+ for (i = 0; i < 8; ++i) {
+ tor_free(fns[i]);
+ }
+}
+
+static void
+test_storagedir_save_labeled(void *arg)
+{
+ (void)arg;
+ char *dirname = tor_strdup(get_fname_rnd("store_dir"));
+ storage_dir_t *d = NULL;
+ uint8_t *inp = tor_malloc_zero(8192);
+ config_line_t *labels = NULL;
+ char *fname = NULL;
+ uint8_t *saved = NULL;
+
+ d = storage_dir_new(dirname, 10);
+ tt_assert(d);
+
+ crypto_rand((char *)inp, 8192);
+
+ config_line_append(&labels, "Foo", "bar baz");
+ config_line_append(&labels, "quux", "quuzXxz");
+ const char expected[] =
+ "Foo bar baz\n"
+ "quux quuzXxz\n";
+
+ int r = storage_dir_save_labeled_to_file(d, labels, inp, 8192, &fname);
+ tt_int_op(r, OP_EQ, 0);
+
+ size_t n;
+ saved = storage_dir_read(d, fname, 1, &n);
+ tt_assert(memchr(saved, '\0', n));
+ tt_str_op((char*)saved, OP_EQ, expected); /* NUL guarantees strcmp works */
+ tt_mem_op(saved+strlen(expected)+1, OP_EQ, inp, 8192);
+
+ done:
+ storage_dir_free(d);
+ tor_free(dirname);
+ tor_free(inp);
+ tor_free(fname);
+ config_free_lines(labels);
+ tor_free(saved);
+}
+
+static void
+test_storagedir_read_labeled(void *arg)
+{
+ (void)arg;
+ char *dirname = tor_strdup(get_fname_rnd("store_dir"));
+ storage_dir_t *d = NULL;
+ uint8_t *inp = tor_malloc_zero(8192);
+ config_line_t *labels = NULL, *labels2 = NULL;
+ char *fname = NULL;
+ tor_mmap_t *map = NULL;
+ uint8_t *as_read = NULL;
+
+ d = storage_dir_new(dirname, 10);
+ tt_assert(d);
+
+ tor_snprintf((char*)inp, 8192,
+ "Hello world\n"
+ "This is a test\n"
+ "Yadda yadda.\n");
+ size_t bodylen = 8192 - strlen((char*)inp) - 1;
+ crypto_rand((char *)inp+strlen((char*)inp)+1, bodylen);
+
+ int r = storage_dir_save_bytes_to_file(d, inp, 8192, 1, &fname);
+ tt_int_op(r, OP_EQ, 0);
+
+ /* Try mapping */
+ const uint8_t *datap = NULL;
+ size_t sz = 0;
+ map = storage_dir_map_labeled(d, fname, &labels, &datap, &sz);
+ tt_assert(map);
+ tt_assert(datap);
+ tt_u64_op(sz, OP_EQ, bodylen);
+ tt_mem_op(datap, OP_EQ, inp+strlen((char*)inp)+1, bodylen);
+ tt_assert(labels);
+ tt_str_op(labels->key, OP_EQ, "Hello");
+ tt_str_op(labels->value, OP_EQ, "world");
+ tt_assert(labels->next);
+ tt_str_op(labels->next->key, OP_EQ, "This");
+ tt_str_op(labels->next->value, OP_EQ, "is a test");
+ tt_assert(labels->next->next);
+ tt_str_op(labels->next->next->key, OP_EQ, "Yadda");
+ tt_str_op(labels->next->next->value, OP_EQ, "yadda.");
+ tt_assert(labels->next->next->next == NULL);
+
+ /* Try reading this time. */
+ sz = 0;
+ as_read = storage_dir_read_labeled(d, fname, &labels2, &sz);
+ tt_assert(as_read);
+ tt_u64_op(sz, OP_EQ, bodylen);
+ tt_mem_op(as_read, OP_EQ, inp+strlen((char*)inp)+1, bodylen);
+ tt_assert(config_lines_eq(labels, labels2));
+
+ done:
+ storage_dir_free(d);
+ tor_free(dirname);
+ tor_free(inp);
+ tor_free(fname);
+ config_free_lines(labels);
+ config_free_lines(labels2);
+ tor_munmap_file(map);
+ tor_free(as_read);
+}
+
+#define ENT(name) \
+ { #name, test_storagedir_ ## name, TT_FORK, NULL, NULL }
+
+struct testcase_t storagedir_tests[] = {
+ ENT(empty),
+ ENT(basic),
+ ENT(deletion),
+ ENT(full),
+ ENT(cleaning),
+ ENT(save_labeled),
+ ENT(read_labeled),
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_switch_id.c b/src/test/test_switch_id.c
index 322f5bdc7a..44e02e87b3 100644
--- a/src/test/test_switch_id.c
+++ b/src/test/test_switch_id.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Tor Project, Inc. */
+/* Copyright (c) 2015-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "or.h"
diff --git a/src/test/test_threads.c b/src/test/test_threads.c
index ebbc95c7ca..18a9407ff7 100644
--- a/src/test/test_threads.c
+++ b/src/test/test_threads.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2016, The Tor Project, Inc. */
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
diff --git a/src/test/test_tortls.c b/src/test/test_tortls.c
index 4bfcea211d..7aa3051464 100644
--- a/src/test/test_tortls.c
+++ b/src/test/test_tortls.c
@@ -1,7 +1,8 @@
-/* Copyright (c) 2010-2016, The Tor Project, Inc. */
+/* Copyright (c) 2010-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define TORTLS_PRIVATE
+#define TORTLS_OPENSSL_PRIVATE
#define LOG_PRIVATE
#include "orconfig.h"
diff --git a/src/test/test_util.c b/src/test/test_util.c
index e80201737a..b3f8ecdf51 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-2016, The Tor Project, Inc. */
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -2242,114 +2242,160 @@ test_util_pow2(void *arg)
;
}
-/** Run unit tests for compression functions */
static void
-test_util_gzip(void *arg)
+test_util_compress_impl(compress_method_t method)
{
- char *buf1=NULL, *buf2=NULL, *buf3=NULL, *cp1, *cp2;
- const char *ccp2;
+ char *buf1=NULL, *buf2=NULL, *buf3=NULL;
size_t len1, len2;
- tor_zlib_state_t *state = NULL;
- (void)arg;
+ tt_assert(tor_compress_supports_method(method));
+
buf1 = tor_strdup("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZAAAAAAAAAAAAAAAAAAAZ");
tt_assert(detect_compression_method(buf1, strlen(buf1)) == UNKNOWN_METHOD);
- tt_assert(!tor_gzip_compress(&buf2, &len1, buf1, strlen(buf1)+1,
- GZIP_METHOD));
- tt_assert(buf2);
- tt_assert(len1 < strlen(buf1));
- tt_assert(detect_compression_method(buf2, len1) == GZIP_METHOD);
-
- tt_assert(!tor_gzip_uncompress(&buf3, &len2, buf2, len1,
- GZIP_METHOD, 1, LOG_INFO));
- tt_assert(buf3);
- tt_int_op(strlen(buf1) + 1,OP_EQ, len2);
- tt_str_op(buf1,OP_EQ, buf3);
-
- tor_free(buf2);
- tor_free(buf3);
-
- tt_assert(!tor_gzip_compress(&buf2, &len1, buf1, strlen(buf1)+1,
- ZLIB_METHOD));
- tt_assert(buf2);
- tt_assert(detect_compression_method(buf2, len1) == ZLIB_METHOD);
+ tt_assert(!tor_compress(&buf2, &len1, buf1, strlen(buf1)+1, method));
+ tt_assert(buf2 != NULL);
+ if (method == NO_METHOD) {
+ // The identity transform doesn't actually compress, and it isn't
+ // detectable as "the identity transform."
+ tt_int_op(len1, OP_EQ, strlen(buf1)+1);
+ tt_int_op(detect_compression_method(buf2, len1), OP_EQ, UNKNOWN_METHOD);
+ } else {
+ tt_int_op(len1, OP_LT, strlen(buf1));
+ tt_int_op(detect_compression_method(buf2, len1), OP_EQ, method);
+ }
- tt_assert(!tor_gzip_uncompress(&buf3, &len2, buf2, len1,
- ZLIB_METHOD, 1, LOG_INFO));
- tt_assert(buf3);
- tt_int_op(strlen(buf1) + 1,OP_EQ, len2);
- tt_str_op(buf1,OP_EQ, buf3);
+ tt_assert(!tor_uncompress(&buf3, &len2, buf2, len1, method, 1, LOG_INFO));
+ tt_assert(buf3 != NULL);
+ tt_int_op(strlen(buf1) + 1, OP_EQ, len2);
+ tt_str_op(buf1, OP_EQ, buf3);
+ tt_int_op(buf3[len2], OP_EQ, 0);
/* Check whether we can uncompress concatenated, compressed strings. */
tor_free(buf3);
buf2 = tor_reallocarray(buf2, len1, 2);
memcpy(buf2+len1, buf2, len1);
- tt_assert(!tor_gzip_uncompress(&buf3, &len2, buf2, len1*2,
- ZLIB_METHOD, 1, LOG_INFO));
- tt_int_op((strlen(buf1)+1)*2,OP_EQ, len2);
- tt_mem_op(buf3,OP_EQ,
+ tt_assert(!tor_uncompress(&buf3, &len2, buf2, len1*2, method, 1, LOG_INFO));
+ tt_int_op((strlen(buf1)+1)*2, OP_EQ, len2);
+ tt_mem_op(buf3, OP_EQ,
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZAAAAAAAAAAAAAAAAAAAZ\0"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZAAAAAAAAAAAAAAAAAAAZ\0",
(strlen(buf1)+1)*2);
+ tt_int_op(buf3[len2], OP_EQ, 0);
+
+ /* Check whether we can uncompress partial strings */
tor_free(buf1);
tor_free(buf2);
tor_free(buf3);
- /* Check whether we can uncompress partial strings. */
- buf1 =
- tor_strdup("String with low redundancy that won't be compressed much.");
- tt_assert(!tor_gzip_compress(&buf2, &len1, buf1, strlen(buf1)+1,
- ZLIB_METHOD));
- tt_assert(len1>16);
- /* when we allow an incomplete string, we should succeed.*/
- tt_assert(!tor_gzip_uncompress(&buf3, &len2, buf2, len1-16,
- ZLIB_METHOD, 0, LOG_INFO));
- tt_assert(len2 > 5);
- buf3[len2]='\0';
- tt_assert(!strcmpstart(buf1, buf3));
-
- /* when we demand a complete string, this must fail. */
+ size_t b1len = 1<<10;
+ if (method == ZSTD_METHOD) {
+ // zstd needs a big input before it starts generating output that it
+ // can partially decompress.
+ b1len = 1<<18;
+ }
+ buf1 = tor_malloc(b1len);
+ crypto_rand(buf1, b1len);
+ tt_assert(!tor_compress(&buf2, &len1, buf1, b1len, method));
+ tt_int_op(len1, OP_GT, 16);
+ /* when we allow an incomplete output we should succeed.*/
+ tt_assert(!tor_uncompress(&buf3, &len2, buf2, len1-16,
+ method, 0, LOG_INFO));
+ tt_int_op(len2, OP_GT, 5);
+ tt_int_op(len2, OP_LE, len1);
+ tt_assert(fast_memeq(buf1, buf3, len2));
+ tt_int_op(buf3[len2], OP_EQ, 0);
+
+ /* when we demand a complete output from a real compression method, this
+ * must fail. */
tor_free(buf3);
- tt_assert(tor_gzip_uncompress(&buf3, &len2, buf2, len1-16,
- ZLIB_METHOD, 1, LOG_INFO));
- tt_assert(!buf3);
+ if (method != NO_METHOD) {
+ tt_assert(tor_uncompress(&buf3, &len2, buf2, len1-16,
+ method, 1, LOG_INFO));
+ tt_assert(buf3 == NULL);
+ }
- /* Now, try streaming compression. */
+ done:
tor_free(buf1);
tor_free(buf2);
tor_free(buf3);
- state = tor_zlib_new(1, ZLIB_METHOD, HIGH_COMPRESSION);
+}
+
+static void
+test_util_compress_stream_impl(compress_method_t method,
+ compression_level_t level)
+{
+ char *buf1=NULL, *buf2=NULL, *buf3=NULL, *cp1, *cp2;
+ const char *ccp2;
+ size_t len1, len2;
+
+ tor_compress_state_t *state = NULL;
+ state = tor_compress_new(1, method, level);
tt_assert(state);
cp1 = buf1 = tor_malloc(1024);
len1 = 1024;
ccp2 = "ABCDEFGHIJABCDEFGHIJ";
len2 = 21;
- tt_assert(tor_zlib_process(state, &cp1, &len1, &ccp2, &len2, 0)
- == TOR_ZLIB_OK);
- tt_int_op(0,OP_EQ, len2); /* Make sure we compressed it all. */
+ tt_int_op(tor_compress_process(state, &cp1, &len1, &ccp2, &len2, 0),
+ OP_EQ, TOR_COMPRESS_OK);
+ tt_int_op(0, OP_EQ, len2); /* Make sure we compressed it all. */
tt_assert(cp1 > buf1);
len2 = 0;
cp2 = cp1;
- tt_assert(tor_zlib_process(state, &cp1, &len1, &ccp2, &len2, 1)
- == TOR_ZLIB_DONE);
- tt_int_op(0,OP_EQ, len2);
- tt_assert(cp1 > cp2); /* Make sure we really added something. */
+ tt_int_op(tor_compress_process(state, &cp1, &len1, &ccp2, &len2, 1),
+ OP_EQ, TOR_COMPRESS_DONE);
+ tt_int_op(0, OP_EQ, len2);
+ if (method == NO_METHOD) {
+ tt_ptr_op(cp1, OP_EQ, cp2);
+ } else {
+ tt_assert(cp1 > cp2); /* Make sure we really added something. */
+ }
- tt_assert(!tor_gzip_uncompress(&buf3, &len2, buf1, 1024-len1,
- ZLIB_METHOD, 1, LOG_WARN));
+ tt_assert(!tor_uncompress(&buf3, &len2, buf1, 1024-len1,
+ method, 1, LOG_WARN));
/* Make sure it compressed right. */
tt_str_op(buf3, OP_EQ, "ABCDEFGHIJABCDEFGHIJ");
- tt_int_op(21,OP_EQ, len2);
+ tt_int_op(21, OP_EQ, len2);
done:
if (state)
- tor_zlib_free(state);
+ tor_compress_free(state);
+ tor_free(buf1);
tor_free(buf2);
tor_free(buf3);
- tor_free(buf1);
+}
+
+/** Run unit tests for compression functions */
+static void
+test_util_compress(void *arg)
+{
+ const char *methodname = arg;
+ tt_assert(methodname);
+
+ compress_method_t method = compression_method_get_by_name(methodname);
+ tt_int_op(method, OP_NE, UNKNOWN_METHOD);
+
+ if (! tor_compress_supports_method(method)) {
+ tt_skip();
+ }
+
+ compression_level_t levels[] = {
+ BEST_COMPRESSION,
+ HIGH_COMPRESSION,
+ MEDIUM_COMPRESSION,
+ LOW_COMPRESSION
+ };
+
+ test_util_compress_impl(method);
+
+ for (unsigned l = 0; l < ARRAY_LENGTH(levels); ++l) {
+ compression_level_t level = levels[l];
+ test_util_compress_stream_impl(method, level);
+ }
+ done:
+ ;
}
static void
@@ -2364,44 +2410,44 @@ test_util_gzip_compression_bomb(void *arg)
char *one_mb = tor_malloc_zero(one_million);
char *result = NULL;
size_t result_len = 0;
- tor_zlib_state_t *state = NULL;
+ tor_compress_state_t *state = NULL;
/* Make sure we can't produce a compression bomb */
setup_full_capture_of_logs(LOG_WARN);
- tt_int_op(-1, OP_EQ, tor_gzip_compress(&result, &result_len,
- one_mb, one_million,
- ZLIB_METHOD));
+ tt_int_op(-1, OP_EQ, tor_compress(&result, &result_len,
+ one_mb, one_million,
+ ZLIB_METHOD));
expect_single_log_msg_containing(
"We compressed something and got an insanely high "
"compression factor; other Tors would think this "
- "was a zlib bomb.");
+ "was a compression bomb.");
teardown_capture_of_logs();
/* Here's a compression bomb that we made manually. */
const char compression_bomb[1039] =
{ 0x78, 0xDA, 0xED, 0xC1, 0x31, 0x01, 0x00, 0x00, 0x00, 0xC2,
0xA0, 0xF5, 0x4F, 0x6D, 0x08, 0x5F, 0xA0 /* .... */ };
- tt_int_op(-1, OP_EQ, tor_gzip_uncompress(&result, &result_len,
- compression_bomb, 1039,
- ZLIB_METHOD, 0, LOG_WARN));
+ tt_int_op(-1, OP_EQ, tor_uncompress(&result, &result_len,
+ compression_bomb, 1039,
+ ZLIB_METHOD, 0, LOG_WARN));
/* Now try streaming that. */
- state = tor_zlib_new(0, ZLIB_METHOD, HIGH_COMPRESSION);
- tor_zlib_output_t r;
+ state = tor_compress_new(0, ZLIB_METHOD, HIGH_COMPRESSION);
+ tor_compress_output_t r;
const char *inp = compression_bomb;
size_t inlen = 1039;
do {
char *outp = one_mb;
size_t outleft = 4096; /* small on purpose */
- r = tor_zlib_process(state, &outp, &outleft, &inp, &inlen, 0);
+ r = tor_compress_process(state, &outp, &outleft, &inp, &inlen, 0);
tt_int_op(inlen, OP_NE, 0);
- } while (r == TOR_ZLIB_BUF_FULL);
+ } while (r == TOR_COMPRESS_BUFFER_FULL);
- tt_int_op(r, OP_EQ, TOR_ZLIB_ERR);
+ tt_int_op(r, OP_EQ, TOR_COMPRESS_ERROR);
done:
tor_free(one_mb);
- tor_zlib_free(state);
+ tor_compress_free(state);
}
/** Run unit tests for mmap() wrapper functionality. */
@@ -3340,6 +3386,13 @@ test_util_memarea(void *arg)
void *malloced_ptr = NULL;
int i;
+#ifdef DISABLE_MEMORY_SENTINELS
+ /* If memory sentinels are disabled, this whole module is just an alias for
+ malloc(), which is free to lay out memory most any way it wants. */
+ if (1)
+ tt_skip();
+#endif
+
(void)arg;
tt_assert(area);
@@ -3933,17 +3986,13 @@ test_util_exit_status(void *ptr)
#endif
#ifndef _WIN32
-/* Check that fgets with a non-blocking pipe returns partial lines and sets
- * EAGAIN, returns full lines and sets no error, and returns NULL on EOF and
- * sets no error */
static void
-test_util_fgets_eagain(void *ptr)
+test_util_string_from_pipe(void *ptr)
{
int test_pipe[2] = {-1, -1};
- int retval;
+ int retval = 0;
+ enum stream_status status = IO_STREAM_TERM;
ssize_t retlen;
- char *retptr;
- FILE *test_stream = NULL;
char buf[4] = { 0 };
(void)ptr;
@@ -3954,91 +4003,115 @@ test_util_fgets_eagain(void *ptr)
retval = pipe(test_pipe);
tt_int_op(retval, OP_EQ, 0);
- /* Set up the read-end to be non-blocking */
- retval = fcntl(test_pipe[0], F_SETFL, O_NONBLOCK);
- tt_int_op(retval, OP_EQ, 0);
+ /* Send in a string. */
+ retlen = write(test_pipe[1], "ABC", 3);
+ tt_int_op(retlen, OP_EQ, 3);
- /* Open it as a stdio stream */
- test_stream = fdopen(test_pipe[0], "r");
- tt_ptr_op(test_stream, OP_NE, NULL);
+ status = get_string_from_pipe(test_pipe[0], buf, sizeof(buf)-1);
+ tt_int_op(errno, OP_EQ, 0);
+ tt_int_op(status, OP_EQ, IO_STREAM_OKAY);
+ tt_str_op(buf, OP_EQ, "ABC");
+ errno = 0;
- /* Send in a partial line */
- retlen = write(test_pipe[1], "A", 1);
+ /* Send in a string that contains a nul. */
+ retlen = write(test_pipe[1], "AB\0", 3);
+ tt_int_op(retlen, OP_EQ, 3);
+
+ status = get_string_from_pipe(test_pipe[0], buf, sizeof(buf)-1);
+ tt_int_op(errno, OP_EQ, 0);
+ tt_int_op(status, OP_EQ, IO_STREAM_OKAY);
+ tt_str_op(buf, OP_EQ, "AB");
+ errno = 0;
+
+ /* Send in a string that contains a nul only. */
+ retlen = write(test_pipe[1], "\0", 1);
tt_int_op(retlen, OP_EQ, 1);
- retptr = fgets(buf, sizeof(buf), test_stream);
- tt_int_op(errno, OP_EQ, EAGAIN);
- tt_ptr_op(retptr, OP_EQ, buf);
- tt_str_op(buf, OP_EQ, "A");
+
+ status = get_string_from_pipe(test_pipe[0], buf, sizeof(buf)-1);
+ tt_int_op(errno, OP_EQ, 0);
+ tt_int_op(status, OP_EQ, IO_STREAM_OKAY);
+ tt_str_op(buf, OP_EQ, "");
errno = 0;
- /* Send in the rest */
- retlen = write(test_pipe[1], "B\n", 2);
- tt_int_op(retlen, OP_EQ, 2);
- retptr = fgets(buf, sizeof(buf), test_stream);
+ /* Send in a string that contains a trailing newline. */
+ retlen = write(test_pipe[1], "AB\n", 3);
+ tt_int_op(retlen, OP_EQ, 3);
+
+ status = get_string_from_pipe(test_pipe[0], buf, sizeof(buf)-1);
+ tt_int_op(errno, OP_EQ, 0);
+ tt_int_op(status, OP_EQ, IO_STREAM_OKAY);
+ tt_str_op(buf, OP_EQ, "AB");
+ errno = 0;
+
+ /* Send in a string that contains a newline only. */
+ retlen = write(test_pipe[1], "\n", 1);
+ tt_int_op(retlen, OP_EQ, 1);
+
+ status = get_string_from_pipe(test_pipe[0], buf, sizeof(buf)-1);
tt_int_op(errno, OP_EQ, 0);
- tt_ptr_op(retptr, OP_EQ, buf);
- tt_str_op(buf, OP_EQ, "B\n");
+ tt_int_op(status, OP_EQ, IO_STREAM_OKAY);
+ tt_str_op(buf, OP_EQ, "");
errno = 0;
- /* Send in a full line */
- retlen = write(test_pipe[1], "CD\n", 3);
+ /* Send in a string and check that we nul terminate return values. */
+ retlen = write(test_pipe[1], "AAA", 3);
tt_int_op(retlen, OP_EQ, 3);
- retptr = fgets(buf, sizeof(buf), test_stream);
+
+ status = get_string_from_pipe(test_pipe[0], buf, sizeof(buf)-1);
tt_int_op(errno, OP_EQ, 0);
- tt_ptr_op(retptr, OP_EQ, buf);
- tt_str_op(buf, OP_EQ, "CD\n");
+ tt_int_op(status, OP_EQ, IO_STREAM_OKAY);
+ tt_str_op(buf, OP_EQ, "AAA");
+ tt_mem_op(buf, OP_EQ, "AAA\0", sizeof(buf));
errno = 0;
- /* Send in a partial line */
- retlen = write(test_pipe[1], "E", 1);
+ retlen = write(test_pipe[1], "B", 1);
tt_int_op(retlen, OP_EQ, 1);
- retptr = fgets(buf, sizeof(buf), test_stream);
- tt_int_op(errno, OP_EQ, EAGAIN);
- tt_ptr_op(retptr, OP_EQ, buf);
- tt_str_op(buf, OP_EQ, "E");
+
+ memset(buf, '\xff', sizeof(buf));
+ status = get_string_from_pipe(test_pipe[0], buf, sizeof(buf)-1);
+ tt_int_op(errno, OP_EQ, 0);
+ tt_int_op(status, OP_EQ, IO_STREAM_OKAY);
+ tt_str_op(buf, OP_EQ, "B");
+ tt_mem_op(buf, OP_EQ, "B\0\xff\xff", sizeof(buf));
errno = 0;
- /* Send in the rest */
- retlen = write(test_pipe[1], "F\n", 2);
- tt_int_op(retlen, OP_EQ, 2);
- retptr = fgets(buf, sizeof(buf), test_stream);
+ /* Send in multiple lines. */
+ retlen = write(test_pipe[1], "A\nB", 3);
+ tt_int_op(retlen, OP_EQ, 3);
+
+ status = get_string_from_pipe(test_pipe[0], buf, sizeof(buf)-1);
tt_int_op(errno, OP_EQ, 0);
- tt_ptr_op(retptr, OP_EQ, buf);
- tt_str_op(buf, OP_EQ, "F\n");
+ tt_int_op(status, OP_EQ, IO_STREAM_OKAY);
+ tt_str_op(buf, OP_EQ, "A\nB");
errno = 0;
- /* Send in a full line and close */
- retlen = write(test_pipe[1], "GH", 2);
+ /* Send in a line and close */
+ retlen = write(test_pipe[1], "AB", 2);
tt_int_op(retlen, OP_EQ, 2);
retval = close(test_pipe[1]);
tt_int_op(retval, OP_EQ, 0);
test_pipe[1] = -1;
- retptr = fgets(buf, sizeof(buf), test_stream);
+
+ status = get_string_from_pipe(test_pipe[0], buf, sizeof(buf)-1);
tt_int_op(errno, OP_EQ, 0);
- tt_ptr_op(retptr, OP_EQ, buf);
- tt_str_op(buf, OP_EQ, "GH");
+ tt_int_op(status, OP_EQ, IO_STREAM_OKAY);
+ tt_str_op(buf, OP_EQ, "AB");
errno = 0;
/* Check for EOF */
- retptr = fgets(buf, sizeof(buf), test_stream);
+ status = get_string_from_pipe(test_pipe[0], buf, sizeof(buf)-1);
tt_int_op(errno, OP_EQ, 0);
- tt_ptr_op(retptr, OP_EQ, NULL);
- retval = feof(test_stream);
- tt_int_op(retval, OP_NE, 0);
+ tt_int_op(status, OP_EQ, IO_STREAM_CLOSED);
errno = 0;
- /* Check that buf is unchanged according to C99 and C11 */
- tt_str_op(buf, OP_EQ, "GH");
-
done:
- if (test_stream != NULL)
- fclose(test_stream);
if (test_pipe[0] != -1)
close(test_pipe[0]);
if (test_pipe[1] != -1)
close(test_pipe[1]);
}
-#endif
+
+#endif // _WIN32
/**
* Test for format_hex_number_sigsafe()
@@ -5664,6 +5737,10 @@ test_util_htonll(void *arg)
#define UTIL_TEST(name, flags) \
{ #name, test_util_ ## name, flags, NULL, NULL }
+#define COMPRESS(name, identifier) \
+ { "compress/" #name, test_util_compress, 0, &passthrough_setup, \
+ (char*)(identifier) }
+
#ifdef _WIN32
#define UTIL_TEST_NO_WIN(n, f) { #n, NULL, TT_SKIP, NULL, NULL }
#define UTIL_TEST_WIN_ONLY(n, f) UTIL_TEST(n, (f))
@@ -5688,7 +5765,11 @@ struct testcase_t util_tests[] = {
UTIL_LEGACY(strmisc),
UTIL_TEST(parse_integer, 0),
UTIL_LEGACY(pow2),
- UTIL_LEGACY(gzip),
+ COMPRESS(zlib, "deflate"),
+ COMPRESS(gzip, "gzip"),
+ COMPRESS(lzma, "x-tor-lzma"),
+ COMPRESS(zstd, "x-zstd"),
+ COMPRESS(none, "identity"),
UTIL_TEST(gzip_compression_bomb, TT_FORK),
UTIL_LEGACY(datadir),
UTIL_LEGACY(memarea),
@@ -5712,7 +5793,7 @@ struct testcase_t util_tests[] = {
UTIL_TEST(num_cpus, 0),
UTIL_TEST_WIN_ONLY(load_win_lib, 0),
UTIL_TEST_NO_WIN(exit_status, 0),
- UTIL_TEST_NO_WIN(fgets_eagain, 0),
+ UTIL_TEST_NO_WIN(string_from_pipe, 0),
UTIL_TEST(format_hex_number, 0),
UTIL_TEST(format_dec_number, 0),
UTIL_TEST(join_win_cmdline, 0),
diff --git a/src/test/test_util_format.c b/src/test/test_util_format.c
index 21a6923c6d..ea0a86499f 100644
--- a/src/test/test_util_format.c
+++ b/src/test/test_util_format.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2016, The Tor Project, Inc. */
+/* Copyright (c) 2010-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -133,48 +133,54 @@ test_util_format_base64_encode(void *ignored)
}
static void
-test_util_format_base64_decode_nopad(void *ignored)
+test_util_format_base64_decode_oddsize(void *ignored)
{
(void)ignored;
int res;
int i;
char *src;
- uint8_t *dst, *real_dst;
- uint8_t expected[] = {0x65, 0x78, 0x61, 0x6D, 0x70, 0x6C, 0x65};
+ char *dst, real_dst[7];
+ char expected[] = {0x65, 0x78, 0x61, 0x6D, 0x70, 0x6C, 0x65};
char real_src[] = "ZXhhbXBsZQ";
+ char expected40[] = "testing40characteroddsizebase64encoding!";
+ char src40[] = "dGVzdGluZzQwY2hhcmFjdGVyb2Rkc2l6ZWJhc2U2NGVuY29kaW5nIQ";
+ char pad40[] = "dGVzdGluZzQwY2hhcmFjdGVyb2Rkc2l6ZWJhc2U2NGVuY29kaW5nIQ==";
src = tor_malloc_zero(256);
dst = tor_malloc_zero(1000);
- real_dst = tor_malloc_zero(10);
for (i=0;i<256;i++) {
src[i] = (char)i;
}
- res = base64_decode_nopad(dst, 1, src, SIZE_T_CEILING);
- tt_int_op(res, OP_EQ, -1);
-
- res = base64_decode_nopad(dst, 1, src, 5);
+ res = base64_decode(dst, 1, src, 5);
tt_int_op(res, OP_EQ, -1);
const char *s = "SGVsbG8gd29ybGQ";
- res = base64_decode_nopad(dst, 1000, s, strlen(s));
+ res = base64_decode(dst, 1000, s, strlen(s));
tt_int_op(res, OP_EQ, 11);
tt_mem_op(dst, OP_EQ, "Hello world", 11);
s = "T3BhIG11bmRv";
- res = base64_decode_nopad(dst, 9, s, strlen(s));
+ res = base64_decode(dst, 9, s, strlen(s));
tt_int_op(res, OP_EQ, 9);
tt_mem_op(dst, OP_EQ, "Opa mundo", 9);
- res = base64_decode_nopad(real_dst, 10, real_src, 10);
+ res = base64_decode(real_dst, sizeof(real_dst), real_src, 10);
tt_int_op(res, OP_EQ, 7);
tt_mem_op(real_dst, OP_EQ, expected, 7);
+ res = base64_decode(dst, 40, src40, strlen(src40));
+ tt_int_op(res, OP_EQ, 40);
+ tt_mem_op(dst, OP_EQ, expected40, 40);
+
+ res = base64_decode(dst, 40, pad40, strlen(pad40));
+ tt_int_op(res, OP_EQ, 40);
+ tt_mem_op(dst, OP_EQ, expected40, 40);
+
done:
tor_free(src);
tor_free(dst);
- tor_free(real_dst);
}
static void
@@ -196,13 +202,10 @@ test_util_format_base64_decode(void *ignored)
src[i] = (char)i;
}
- res = base64_decode(dst, 1, src, SIZE_T_CEILING);
+ res = base64_decode(dst, 1, src, 100);
tt_int_op(res, OP_EQ, -1);
- res = base64_decode(dst, SIZE_T_CEILING+1, src, 10);
- tt_int_op(res, OP_EQ, -1);
-
- res = base64_decode(dst, 1, real_src, SIZE_MAX/3+1);
+ res = base64_decode(dst, 1, real_src, 10);
tt_int_op(res, OP_EQ, -1);
const char *s = "T3BhIG11bmRv";
@@ -370,11 +373,39 @@ test_util_format_base32_decode(void *arg)
tor_free(dst);
}
+static void
+test_util_format_encoded_size(void *arg)
+{
+ (void)arg;
+ uint8_t inbuf[256];
+ char outbuf[1024];
+ unsigned i;
+
+ crypto_rand((char *)inbuf, sizeof(inbuf));
+ for (i = 0; i <= sizeof(inbuf); ++i) {
+ /* XXXX (Once the return values are consistent, check them too.) */
+
+ base32_encode(outbuf, sizeof(outbuf), (char *)inbuf, i);
+ /* The "+ 1" below is an API inconsistency. */
+ tt_int_op(strlen(outbuf) + 1, OP_EQ, base32_encoded_size(i));
+
+ base64_encode(outbuf, sizeof(outbuf), (char *)inbuf, i, 0);
+ tt_int_op(strlen(outbuf), OP_EQ, base64_encode_size(i, 0));
+ base64_encode(outbuf, sizeof(outbuf), (char *)inbuf, i,
+ BASE64_ENCODE_MULTILINE);
+ tt_int_op(strlen(outbuf), OP_EQ,
+ base64_encode_size(i, BASE64_ENCODE_MULTILINE));
+ }
+
+ done:
+ ;
+}
+
struct testcase_t util_format_tests[] = {
{ "unaligned_accessors", test_util_format_unaligned_accessors, 0,
NULL, NULL },
{ "base64_encode", test_util_format_base64_encode, 0, NULL, NULL },
- { "base64_decode_nopad", test_util_format_base64_decode_nopad, 0,
+ { "base64_decode_oddsize", test_util_format_base64_decode_oddsize, 0,
NULL, NULL },
{ "base64_decode", test_util_format_base64_decode, 0, NULL, NULL },
{ "base16_decode", test_util_format_base16_decode, 0, NULL, NULL },
@@ -382,6 +413,7 @@ struct testcase_t util_format_tests[] = {
NULL, NULL },
{ "base32_decode", test_util_format_base32_decode, 0,
NULL, NULL },
+ { "encoded_size", test_util_format_encoded_size, 0, NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_util_process.c b/src/test/test_util_process.c
index 4e75b97f3d..70292f2287 100644
--- a/src/test/test_util_process.c
+++ b/src/test/test_util_process.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2016, The Tor Project, Inc. */
+/* Copyright (c) 2010-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define UTIL_PROCESS_PRIVATE
diff --git a/src/test/test_util_slow.c b/src/test/test_util_slow.c
index 1e7160598c..3e5d78948d 100644
--- a/src/test/test_util_slow.c
+++ b/src/test/test_util_slow.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2016, The Tor Project, Inc. */
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -242,7 +242,7 @@ test_util_spawn_background_partial_read_impl(int exit_early)
#else
/* Check that we didn't read the end of file last time */
tt_assert(!eof);
- pos = tor_read_all_handle(process_handle->stdout_handle, stdout_buf,
+ pos = tor_read_all_handle(process_handle->stdout_pipe, stdout_buf,
sizeof(stdout_buf) - 1, NULL, &eof);
#endif
log_info(LD_GENERAL, "tor_read_all_handle() returned %d", (int)pos);
@@ -273,7 +273,7 @@ test_util_spawn_background_partial_read_impl(int exit_early)
#else
if (!eof) {
/* We should have got all the data, but maybe not the EOF flag */
- pos = tor_read_all_handle(process_handle->stdout_handle, stdout_buf,
+ pos = tor_read_all_handle(process_handle->stdout_pipe, stdout_buf,
sizeof(stdout_buf) - 1,
process_handle, &eof);
tt_int_op(0,OP_EQ, pos);
diff --git a/src/test/test_workqueue.c b/src/test/test_workqueue.c
index ccb8d0c8ca..10714457f7 100644
--- a/src/test/test_workqueue.c
+++ b/src/test/test_workqueue.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2016, The Tor Project, Inc. */
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "or.h"
diff --git a/src/test/testing_common.c b/src/test/testing_common.c
index caeae13a38..d3dc761c77 100644
--- a/src/test/testing_common.c
+++ b/src/test/testing_common.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2016, The Tor Project, Inc. */
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
extern const char tor_git_revision[];
@@ -38,7 +38,6 @@ const char tor_git_revision[] = "";
#ifdef USE_DMALLOC
#include <dmalloc.h>
-#include <openssl/crypto.h>
#include "main.h"
#endif
@@ -238,14 +237,15 @@ main(int c, const char **v)
#ifdef USE_DMALLOC
{
- int r = CRYPTO_set_mem_ex_functions(tor_malloc_, tor_realloc_, tor_free_);
- tor_assert(r);
+ int r = crypto_use_tor_alloc_functions();
+ tor_assert(r == 0);
}
#endif
update_approx_time(time(NULL));
options = options_new();
tor_threads_init();
+ tor_compress_init();
network_init();
diff --git a/src/test/testing_rsakeys.c b/src/test/testing_rsakeys.c
index 134770bb0d..5dff233a69 100644
--- a/src/test/testing_rsakeys.c
+++ b/src/test/testing_rsakeys.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2016, The Tor Project, Inc. */
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"