aboutsummaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
Diffstat (limited to 'src/test')
-rw-r--r--src/test/Makefile.nmake3
-rw-r--r--src/test/bench.c33
-rwxr-xr-xsrc/test/bt_test.py2
-rw-r--r--src/test/ed25519_exts_ref.py38
-rw-r--r--src/test/ed25519_vectors.inc32
-rw-r--r--src/test/fakechans.h2
-rw-r--r--src/test/fuzz/dict/consensus52
-rw-r--r--src/test/fuzz/dict/descriptor41
-rw-r--r--src/test/fuzz/dict/extrainfo32
-rw-r--r--src/test/fuzz/dict/hsdescv28
-rw-r--r--src/test/fuzz/dict/hsdescv36
-rw-r--r--src/test/fuzz/dict/http24
-rw-r--r--src/test/fuzz/dict/iptsv26
-rw-r--r--src/test/fuzz/dict/microdesc7
-rwxr-xr-xsrc/test/fuzz/fixup_filenames.sh19
-rw-r--r--src/test/fuzz/fuzz_consensus.c78
-rw-r--r--src/test/fuzz/fuzz_descriptor.c79
-rw-r--r--src/test/fuzz/fuzz_diff.c69
-rw-r--r--src/test/fuzz/fuzz_diff_apply.c65
-rw-r--r--src/test/fuzz/fuzz_extrainfo.c65
-rw-r--r--src/test/fuzz/fuzz_hsdescv2.c52
-rw-r--r--src/test/fuzz/fuzz_hsdescv3.c99
-rw-r--r--src/test/fuzz/fuzz_http.c133
-rw-r--r--src/test/fuzz/fuzz_http_connect.c106
-rw-r--r--src/test/fuzz/fuzz_iptsv2.c46
-rw-r--r--src/test/fuzz/fuzz_microdesc.c47
-rwxr-xr-xsrc/test/fuzz/fuzz_multi.sh34
-rw-r--r--src/test/fuzz/fuzz_vrs.c82
-rw-r--r--src/test/fuzz/fuzzing.h13
-rw-r--r--src/test/fuzz/fuzzing_common.c192
-rw-r--r--src/test/fuzz/include.am351
-rwxr-xr-xsrc/test/fuzz/minimize.sh14
-rwxr-xr-xsrc/test/fuzz_static_testcases.sh27
-rw-r--r--src/test/hs_build_address.py38
-rw-r--r--src/test/hs_indexes.py70
-rw-r--r--src/test/hs_ntor_ref.py428
-rw-r--r--src/test/hs_test_helpers.c282
-rw-r--r--src/test/hs_test_helpers.h25
-rw-r--r--src/test/include.am114
-rw-r--r--src/test/log_test_helpers.c2
-rw-r--r--src/test/log_test_helpers.h8
-rwxr-xr-xsrc/test/ntor_ref.py2
-rw-r--r--src/test/rend_test_helpers.c18
-rw-r--r--src/test/rend_test_helpers.h5
-rw-r--r--src/test/test-child.c4
-rw-r--r--src/test/test-memwipe.c2
-rwxr-xr-xsrc/test/test-network.sh187
-rw-r--r--src/test/test-timers.c2
-rw-r--r--src/test/test.c102
-rw-r--r--src/test/test.h32
-rw-r--r--src/test/test_addr.c66
-rw-r--r--src/test/test_address.c82
-rw-r--r--src/test/test_bt_cl.c15
-rw-r--r--src/test/test_buffers.c514
-rw-r--r--src/test/test_cell_formats.c37
-rw-r--r--src/test/test_cell_queue.c2
-rw-r--r--src/test/test_channel.c422
-rw-r--r--src/test/test_channelpadding.c1133
-rw-r--r--src/test/test_channeltls.c41
-rw-r--r--src/test/test_checkdir.c4
-rw-r--r--src/test/test_circuitbuild.c133
-rw-r--r--src/test/test_circuitlist.c155
-rw-r--r--src/test/test_circuitmux.c8
-rw-r--r--src/test/test_circuituse.c307
-rw-r--r--src/test/test_compat_libevent.c2
-rw-r--r--src/test/test_config.c1591
-rw-r--r--src/test/test_connection.c425
-rw-r--r--src/test/test_connection.h13
-rw-r--r--src/test/test_conscache.c340
-rw-r--r--src/test/test_consdiff.c1185
-rw-r--r--src/test/test_consdiffmgr.c896
-rw-r--r--src/test/test_containers.c132
-rw-r--r--src/test/test_controller.c320
-rw-r--r--src/test/test_controller_events.c2
-rw-r--r--src/test/test_crypto.c271
-rw-r--r--src/test/test_crypto_openssl.c107
-rw-r--r--src/test/test_crypto_slow.c36
-rw-r--r--src/test/test_data.c2
-rw-r--r--src/test/test_dir.c1610
-rw-r--r--src/test/test_dir_common.c4
-rw-r--r--src/test/test_dir_common.h2
-rw-r--r--src/test/test_dir_handle_get.c219
-rw-r--r--src/test/test_dns.c64
-rw-r--r--src/test/test_entryconn.c148
-rw-r--r--src/test/test_entrynodes.c3205
-rw-r--r--src/test/test_extorport.c30
-rw-r--r--src/test/test_guardfraction.c50
-rw-r--r--src/test/test_handles.c2
-rw-r--r--src/test/test_helpers.c195
-rw-r--r--src/test/test_helpers.h19
-rw-r--r--src/test/test_hs.c510
-rw-r--r--src/test/test_hs_cache.c561
-rw-r--r--src/test/test_hs_cell.c130
-rw-r--r--src/test/test_hs_client.c599
-rw-r--r--src/test/test_hs_common.c1827
-rw-r--r--src/test/test_hs_config.c487
-rw-r--r--src/test/test_hs_descriptor.c897
-rw-r--r--src/test/test_hs_descriptor.inc224
-rw-r--r--src/test/test_hs_intropoint.c928
-rw-r--r--src/test/test_hs_ntor.c114
-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.c1625
-rw-r--r--src/test/test_introduce.c12
-rwxr-xr-xsrc/test/test_key_expiration.sh137
-rw-r--r--src/test/test_keypin.c105
-rw-r--r--src/test/test_link_handshake.c865
-rw-r--r--src/test/test_logging.c10
-rw-r--r--src/test/test_microdesc.c22
-rw-r--r--src/test/test_nodelist.c106
-rw-r--r--src/test/test_ntor_cl.c2
-rw-r--r--src/test/test_oom.c23
-rw-r--r--src/test/test_oos.c20
-rw-r--r--src/test/test_options.c788
-rw-r--r--src/test/test_policy.c383
-rw-r--r--src/test/test_procmon.c2
-rw-r--r--src/test/test_proto_http.c213
-rw-r--r--src/test/test_proto_misc.c263
-rw-r--r--src/test/test_protover.c24
-rw-r--r--src/test/test_pt.c50
-rw-r--r--src/test/test_pubsub.c2
-rw-r--r--src/test/test_relay.c6
-rw-r--r--src/test/test_relaycell.c2
-rw-r--r--src/test/test_rendcache.c79
-rw-r--r--src/test/test_replay.c26
-rw-r--r--src/test/test_router.c112
-rw-r--r--src/test/test_routerkeys.c264
-rw-r--r--src/test/test_routerlist.c94
-rw-r--r--src/test/test_routerset.c46
-rw-r--r--src/test/test_rust.c31
-rwxr-xr-xsrc/test/test_rust.sh18
-rw-r--r--src/test/test_scheduler.c833
-rw-r--r--src/test/test_shared_random.c423
-rw-r--r--src/test/test_slow.c2
-rw-r--r--src/test/test_socks.c595
-rw-r--r--src/test/test_status.c6
-rw-r--r--src/test/test_storagedir.c375
-rw-r--r--src/test/test_switch_id.c10
-rw-r--r--src/test/test_threads.c14
-rw-r--r--src/test/test_tortls.c124
-rw-r--r--src/test/test_util.c1028
-rw-r--r--src/test/test_util_format.c92
-rw-r--r--src/test/test_util_process.c4
-rw-r--r--src/test/test_util_slow.c28
-rw-r--r--src/test/test_workqueue.c14
-rw-r--r--src/test/testing_common.c91
-rw-r--r--src/test/testing_rsakeys.c546
147 files changed, 27665 insertions, 5360 deletions
diff --git a/src/test/Makefile.nmake b/src/test/Makefile.nmake
index 0ba56d7036..605f1a92c3 100644
--- a/src/test/Makefile.nmake
+++ b/src/test/Makefile.nmake
@@ -12,11 +12,12 @@ 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 \
test_cell_formats.obj test_relay.obj test_replay.obj \
+ test_channelpadding.obj \
test_scheduler.obj test_introduce.obj test_hs.obj tinytest.obj
tinytest.obj: ..\ext\tinytest.c
diff --git a/src/test/bench.c b/src/test/bench.c
index 30984fda70..b7b123eee2 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;
@@ -57,7 +58,7 @@ perftime(void)
return timespec_to_nsec(&ts) - nanostart;
}
-#else
+#else /* !(defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_PROCESS_CPUTIME_ID)) */
static struct timeval tv_start = { 0, 0 };
static void
reset_perftime(void)
@@ -72,7 +73,7 @@ perftime(void)
timersub(&now, &tv_start, &out);
return ((uint64_t)out.tv_sec)*1000000000 + out.tv_usec*1000;
}
-#endif
+#endif /* defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_PROCESS_CPUTIME_ID) */
#define NANOCOUNT(start,end,iters) \
( ((double)((end)-(start))) / (iters) )
@@ -120,7 +121,7 @@ bench_onion_TAP(void)
uint64_t start, end;
char os[TAP_ONIONSKIN_CHALLENGE_LEN];
char or[TAP_ONIONSKIN_REPLY_LEN];
- crypto_dh_t *dh_out;
+ crypto_dh_t *dh_out = NULL;
key = crypto_pk_new();
key2 = crypto_pk_new();
@@ -175,6 +176,7 @@ bench_onion_TAP(void)
NANOCOUNT(start, end, iters)/1e3);
done:
+ crypto_dh_free(dh_out);
crypto_pk_free(key);
crypto_pk_free(key2);
}
@@ -198,6 +200,7 @@ bench_onion_ntor_impl(void)
curve25519_public_key_generate(&keypair2.pubkey, &keypair2.seckey);
dimap_add_entry(&keymap, keypair1.pubkey.public_key, &keypair1);
dimap_add_entry(&keymap, keypair2.pubkey.public_key, &keypair2);
+ crypto_rand((char *)nodeid, sizeof(nodeid));
reset_perftime();
start = perftime();
@@ -672,6 +675,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..f84d3002d3 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
"""
@@ -32,8 +32,7 @@ def curve25519ToEd25519(c, sign):
return encodepoint([x,y])
def blindESK(esk, param):
- h = H("Derive temporary signing key" + param)
- mult = 2**(b-2) + sum(2**i * bit(h,i) for i in range(3,b-2))
+ mult = 2**(b-2) + sum(2**i * bit(param,i) for i in range(3,b-2))
s = decodeint(esk[:32])
s_prime = (s * mult) % ell
k = esk[32:]
@@ -42,8 +41,7 @@ def blindESK(esk, param):
return encodeint(s_prime) + k_prime
def blindPK(pk, param):
- h = H("Derive temporary signing key" + param)
- mult = 2**(b-2) + sum(2**i * bit(h,i) for i in range(3,b-2))
+ mult = 2**(b-2) + sum(2**i * bit(param,i) for i in range(3,b-2))
P = decodepoint(pk)
return encodepoint(scalarmult(P, mult))
@@ -69,6 +67,11 @@ def signatureWithESK(m,h,pk):
def newSK():
return os.urandom(32)
+def random_scalar(entropy_f): # 0..L-1 inclusive
+ # reduce the bias to a safe level by generating 256 extra bits
+ oversized = int(binascii.hexlify(entropy_f(32+32)), 16)
+ return oversized % ell
+
# ------------------------------------------------------------
MSG = "This is extremely silly. But it is also incredibly serious business!"
@@ -126,6 +129,31 @@ class SelfTest(unittest.TestCase):
self._testSignatures(besk, bpk)
+ def testIdentity(self):
+ # Base point:
+ # B is the unique point (x, 4/5) \in E for which x is positive
+ By = 4 * inv(5)
+ Bx = xrecover(By)
+ B = [Bx % q,By % q]
+
+ # Get identity E by doing: E = l*B, where l is the group order
+ identity = scalarmult(B, ell)
+
+ # Get identity E by doing: E = l*A, where A is a random point
+ sk = newSK()
+ pk = decodepoint(publickey(sk))
+ identity2 = scalarmult(pk, ell)
+
+ # Check that identities match
+ assert(identity == identity2)
+ # Check that identity is the point (0,1)
+ assert(identity == [0L,1L])
+
+ # Check identity element: a*E = E, where a is a random scalar
+ scalar = random_scalar(os.urandom)
+ result = scalarmult(identity, scalar)
+ assert(result == identity == identity2)
+
# ------------------------------------------------------------
# From pprint.pprint([ binascii.b2a_hex(os.urandom(32)) for _ in xrange(8) ])
diff --git a/src/test/ed25519_vectors.inc b/src/test/ed25519_vectors.inc
index 760bafb971..60c863beba 100644
--- a/src/test/ed25519_vectors.inc
+++ b/src/test/ed25519_vectors.inc
@@ -91,21 +91,21 @@ static const char *ED25519_BLINDING_PARAMS[] = {
* blinding parameter.
*/
static const char *ED25519_BLINDED_SECRET_KEYS[] = {
- "014e83abadb2ca9a27e0ffe23920333d817729f48700e97656ec2823d694050e171d43"
+ "293c3acff4e902f6f63ddc5d5caa2a57e771db4f24de65d4c28df3232f47fa01171d43"
"f24e3f53e70ec7ac280044ac77d4942dee5d6807118a59bdf3ee647e89",
- "fad8cca0b4335847795288b1452508752b253e64e6c7c78d4a02dbbd7d46aa0eb8ceff"
+ "38b88f9f9440358da544504ee152fb475528f7c51c285bd1c68b14ade8e29a07b8ceff"
"20dfcf53eb52b891fc078c934efbf0353af7242e7dc51bb32a093afa29",
- "116eb0ae0a4a91763365bdf86db427b00862db448487808788cc339ac10e5e089217f5"
+ "4d03ce16a3f3249846aac9de0a0075061495c3b027248eeee47da4ddbaf9e0049217f5"
"2e92797462bd890fc274672e05c98f2c82970d640084781334aae0f940",
- "bd1fbb0ee5acddc4adbcf5f33e95d9445f40326ce579fdd764a24483a9ccb20f509ece"
+ "51d7db01aaa0d937a9fd7c8c7381445a14d8fa61f43347af5460d7cd8fda9904509ece"
"e77082ce088f7c19d5a00e955eeef8df6fa41686abc1030c2d76807733",
- "237f5345cefe8573ce9fa7e216381a1172796c9e3f70668ab503b1352952530fb57b95"
+ "1f76cab834e222bd2546efa7e073425680ab88df186ff41327d3e40770129b00b57b95"
"a440570659a440a3e4771465022a8e67af86bdf2d0990c54e7bb87ff9a",
- "ba8ff23bc4ad2b739e1ccffc9fbc7837053ea81cdfdb15073f56411cfbae1d0ec492fc"
+ "c23588c23ee76093419d07b27c6df5922a03ac58f96c53671456a7d1bdbf560ec492fc"
"87d5ec2a1b185ca5a40541fdef0b1e128fd5c2380c888bfa924711bcab",
- "0fa68f969de038c7a90a4a74ee6167c77582006f2dedecc1956501ba6b6fb10391b476"
+ "3ed249c6932d076e1a2f6916975914b14e8c739da00992358b8f37d3e790650691b476"
"8f8e556d78f4bdcb9a13b6f6066fe81d3134ae965dc48cd0785b3af2b8",
- "deaa3456d1c21944d5dcd361a646858c6cf9336b0a6851d925717eb1ae186902053d9c"
+ "288cbfd923cb286d48c084555b5bdd06c05e92fb81acdb45271367f57515380e053d9c"
"00c81e1331c06ab50087be8cfc7dc11691b132614474f1aa9c2503cccd",
};
@@ -115,14 +115,14 @@ static const char *ED25519_BLINDED_SECRET_KEYS[] = {
* blinding parameter.
*/
static const char *ED25519_BLINDED_PUBLIC_KEYS[] = {
- "722d6da6348e618967ef782e71061e27163a8b35f21856475d9d2023f65b6495",
- "1dffa0586da6cbfcff2024eedf4fc6c818242d9a82dbbe635d6da1b975a1160d",
- "5ed81f98fed5a6acda4ea6da2c34fab0ab359d950c510c256473f1f33ff438b4",
- "6e6f92a54fb282120c46d9603df41135f025bc1f58f283809d04be96aeb04040",
- "cda236f28edc4c7e02d18007b8dab49d669265b0f7aefb1824d7cc8e73a2cd63",
- "367b03b17b67ca7329b89a520bdab91782402a41cd67264e34b5541a4b3f875b",
- "8d486b03ac4e3b486b7a1d563706c7fdac75aee789a7cf6f22789eedeff61a31",
- "9f297ff0aa2ceda91c5ab1b6446f12533d145940de6d850dc323417afde0cb78",
+ "1fc1fa4465bd9d4956fdbdc9d3acb3c7019bb8d5606b951c2e1dfe0b42eaeb41",
+ "1cbbd4a88ce8f165447f159d9f628ada18674158c4f7c5ead44ce8eb0fa6eb7e",
+ "c5419ad133ffde7e0ac882055d942f582054132b092de377d587435722deb028",
+ "3e08d0dc291066272e313014bfac4d39ad84aa93c038478a58011f431648105f",
+ "59381f06acb6bf1389ba305f70874eed3e0f2ab57cdb7bc69ed59a9b8899ff4d",
+ "2b946a484344eb1c17c89dd8b04196a84f3b7222c876a07a4cece85f676f87d9",
+ "c6b585129b135f8769df2eba987e76e089e80ba3a2a6729134d3b28008ac098e",
+ "0eefdc795b59cabbc194c6174e34ba9451e8355108520554ec285acabebb34ac",
};
/**
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/consensus b/src/test/fuzz/dict/consensus
new file mode 100644
index 0000000000..3fcd9ee7ff
--- /dev/null
+++ b/src/test/fuzz/dict/consensus
@@ -0,0 +1,52 @@
+"a"
+"additional-digest"
+"additional-signature"
+"bandwidth-weights"
+"client-versions"
+"consensus-digest"
+"consensus-method"
+"consensus-methods"
+"contact"
+"dir-address"
+"directory-footer"
+"directory-signature"
+"dir-identity-key"
+"dir-key-certificate-version"
+"dir-key-certification"
+"dir-key-crosscert"
+"dir-key-expires"
+"dir-key-published"
+"dir-signing-key"
+"dir-source"
+"fingerprint"
+"fresh-until"
+"id"
+"known-flags"
+"legacy-dir-key"
+"m"
+"network-status-version"
+"opt"
+"p"
+"package"
+"params"
+"pr"
+"published"
+"r"
+"recommended-client-protocols"
+"recommended-relay-protocols"
+"required-client-protocols"
+"required-relay-protocols"
+"s"
+"server-versions"
+"shared-rand-commit"
+"shared-rand-current-value"
+"shared-rand-participate"
+"shared-rand-previous-value"
+"signing-ed25519"
+"v"
+"valid-after"
+"valid-until"
+"vote-digest"
+"vote-status"
+"voting-delay"
+"w"
diff --git a/src/test/fuzz/dict/descriptor b/src/test/fuzz/dict/descriptor
new file mode 100644
index 0000000000..110ee3e820
--- /dev/null
+++ b/src/test/fuzz/dict/descriptor
@@ -0,0 +1,41 @@
+"reject"
+"accept"
+"reject6"
+"accept6"
+"router"
+"ipv6-policy"
+"signing-key"
+"onion-key"
+"ntor-onion-key"
+"router-signature"
+"published"
+"uptime"
+"fingerprint"
+"hibernating"
+"platform"
+"proto"
+"contact"
+"read-history"
+"write-history"
+"extra-info-digest"
+"hidden-service-dir"
+"identity-ed25519"
+"master-key-ed25519"
+"router-sig-ed25519"
+"onion-key-crosscert"
+"ntor-onion-key-crosscert"
+"allow-single-hop-exits"
+"family"
+"caches-extra-info"
+"or-address"
+"opt"
+ "bandwidth"
+"@purpose"
+"tunnelled-dir-server"
+"-----BEGIN"
+"-----END"
+"-----"
+"ED25519 CERT"
+"RSA PUBLIC KEY"
+"CROSSCERT"
+"SIGNATURE"
diff --git a/src/test/fuzz/dict/extrainfo b/src/test/fuzz/dict/extrainfo
new file mode 100644
index 0000000000..eba7a1e4ce
--- /dev/null
+++ b/src/test/fuzz/dict/extrainfo
@@ -0,0 +1,32 @@
+"cell-circuits-per-decile"
+"cell-processed-cells"
+"cell-queued-cells"
+"cell-stats-end"
+"cell-time-in-queue"
+"dirreq-stats-end"
+"dirreq-v2-direct-dl"
+"dirreq-v2-ips"
+"dirreq-v2-reqs"
+"dirreq-v2-resp"
+"dirreq-v2-share"
+"dirreq-v2-tunneled-dl"
+"dirreq-v3-direct-dl"
+"dirreq-v3-ips"
+"dirreq-v3-reqs"
+"dirreq-v3-resp"
+"dirreq-v3-share"
+"dirreq-v3-tunneled-dl"
+"entry-ips"
+"entry-stats-end"
+"exit-kibibytes-read"
+"exit-kibibytes-written"
+"exit-stats-end"
+"exit-streams-opened"
+"extra-info"
+"identity-ed25519"
+"opt"
+"published"
+"read-history"
+"router-sig-ed25519"
+"router-signature"
+"write-history"
diff --git a/src/test/fuzz/dict/hsdescv2 b/src/test/fuzz/dict/hsdescv2
new file mode 100644
index 0000000000..48788301dc
--- /dev/null
+++ b/src/test/fuzz/dict/hsdescv2
@@ -0,0 +1,8 @@
+"introduction-points"
+"permanent-key"
+"protocol-versions"
+"publication-time"
+"rendezvous-service-descriptor"
+"secret-id-part"
+"signature"
+"version"
diff --git a/src/test/fuzz/dict/hsdescv3 b/src/test/fuzz/dict/hsdescv3
new file mode 100644
index 0000000000..84e8db578a
--- /dev/null
+++ b/src/test/fuzz/dict/hsdescv3
@@ -0,0 +1,6 @@
+"hs-descriptor"
+"descriptor-lifetime"
+"descriptor-signing-key-cert"
+"revision-counter"
+"superencrypted"
+"signature"
diff --git a/src/test/fuzz/dict/http b/src/test/fuzz/dict/http
new file mode 100644
index 0000000000..3b0531579d
--- /dev/null
+++ b/src/test/fuzz/dict/http
@@ -0,0 +1,24 @@
+#
+# AFL dictionary for the Tor Directory protocol's HTTP headers
+# ------------------------------------------------------------
+#
+# Extracted from directory_handle_command() in the tor source code
+#
+# Copyright (c) 2016-2017, The Tor Project, Inc.
+# See LICENSE for licensing information
+#
+# Usage:
+# Select the dictionaries relevant to the part of the directory protocol you
+# are fuzzing, and feed them to your fuzzer (if it supports dictionaries).
+
+http_header_body_delimiter = "\x0d\x0a\x0d\x0a"
+http_header_header_delimiter = "\x0d\x0a"
+# multi-character tokens only
+#http_header_value_delimiter = " "
+
+content_length_header = "Content-Length:"
+forwarded_for_header = "Forwarded-For:"
+x_forwarded_for_header = "X-Forwarded-For:"
+
+get_command = "GET"
+post_command = "POST"
diff --git a/src/test/fuzz/dict/iptsv2 b/src/test/fuzz/dict/iptsv2
new file mode 100644
index 0000000000..57791c5e3c
--- /dev/null
+++ b/src/test/fuzz/dict/iptsv2
@@ -0,0 +1,6 @@
+"introduction-point"
+"ip-address"
+"onion-port"
+"onion-key"
+"service-key"
+
diff --git a/src/test/fuzz/dict/microdesc b/src/test/fuzz/dict/microdesc
new file mode 100644
index 0000000000..fdd0567b65
--- /dev/null
+++ b/src/test/fuzz/dict/microdesc
@@ -0,0 +1,7 @@
+"onion-key"
+"ntor-onion-key"
+"id"
+"a"
+"family"
+"p"
+"p6"
diff --git a/src/test/fuzz/fixup_filenames.sh b/src/test/fuzz/fixup_filenames.sh
new file mode 100755
index 0000000000..68efc1abc5
--- /dev/null
+++ b/src/test/fuzz/fixup_filenames.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+set -e
+
+if [ ! -d "$1" ] ; then
+ echo "I need a directory"
+ exit 1
+fi
+
+for fn in "$1"/* ; do
+ prev=`basename "$fn"`
+ post=`sha256sum "$fn" | sed -e 's/ .*//;'`
+ if [ "$prev" == "$post" ] ; then
+ echo "OK $prev"
+ else
+ echo "mv $prev $post"
+ mv "$fn" "$1/$post"
+ fi
+done
diff --git a/src/test/fuzz/fuzz_consensus.c b/src/test/fuzz/fuzz_consensus.c
new file mode 100644
index 0000000000..6610ade7ad
--- /dev/null
+++ b/src/test/fuzz/fuzz_consensus.c
@@ -0,0 +1,78 @@
+/* Copyright (c) 2016-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+#define ROUTERPARSE_PRIVATE
+#include "or.h"
+#include "routerparse.h"
+#include "networkstatus.h"
+#include "fuzzing.h"
+
+static void
+mock_dump_desc__nodump(const char *desc, const char *type)
+{
+ (void)desc;
+ (void)type;
+}
+
+static int
+mock_router_produce_hash_final__nohash(char *digest,
+ const char *start, size_t len,
+ digest_algorithm_t alg)
+{
+ (void)start;
+ (void)len;
+ /* we could look at start[..] */
+ if (alg == DIGEST_SHA1)
+ memset(digest, 0x01, 20);
+ else
+ memset(digest, 0x02, 32);
+ return 0;
+}
+
+static int
+mock_signed_digest_equals__yes(const uint8_t *d1, const uint8_t *d2,
+ size_t len)
+{
+ (void) tor_memeq(d1, d2, len);
+ return 1;
+}
+
+int
+fuzz_init(void)
+{
+ disable_signature_checking();
+ MOCK(dump_desc, mock_dump_desc__nodump);
+ MOCK(router_compute_hash_final, mock_router_produce_hash_final__nohash);
+ MOCK(signed_digest_equals, mock_signed_digest_equals__yes);
+ ed25519_init();
+ return 0;
+}
+
+int
+fuzz_cleanup(void)
+{
+ return 0;
+}
+
+int
+fuzz_main(const uint8_t *data, size_t sz)
+{
+ networkstatus_t *ns;
+ char *str = tor_memdup_nulterm(data, sz);
+ const char *eos = NULL;
+ networkstatus_type_t tp = NS_TYPE_CONSENSUS;
+ if (tor_memstr(data, MIN(sz, 1024), "tus vote"))
+ tp = NS_TYPE_VOTE;
+ const char *what = (tp == NS_TYPE_CONSENSUS) ? "consensus" : "vote";
+ ns = networkstatus_parse_vote_from_string(str,
+ &eos,
+ tp);
+ if (ns) {
+ log_debug(LD_GENERAL, "Parsing as %s okay", what);
+ networkstatus_vote_free(ns);
+ } else {
+ log_debug(LD_GENERAL, "Parsing as %s failed", what);
+ }
+ tor_free(str);
+ return 0;
+}
+
diff --git a/src/test/fuzz/fuzz_descriptor.c b/src/test/fuzz/fuzz_descriptor.c
new file mode 100644
index 0000000000..1a50beae17
--- /dev/null
+++ b/src/test/fuzz/fuzz_descriptor.c
@@ -0,0 +1,79 @@
+/* Copyright (c) 2016-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+#define ROUTERPARSE_PRIVATE
+#include "or.h"
+#include "routerparse.h"
+#include "routerlist.h"
+#include "routerkeys.h"
+#include "fuzzing.h"
+
+static int
+mock_check_tap_onion_key_crosscert__nocheck(const uint8_t *crosscert,
+ int crosscert_len,
+ const crypto_pk_t *onion_pkey,
+ const ed25519_public_key_t *master_id_pkey,
+ const uint8_t *rsa_id_digest)
+{
+ tor_assert(crosscert && onion_pkey && master_id_pkey && rsa_id_digest);
+ /* we could look at crosscert[..] */
+ (void) crosscert_len;
+ return 0;
+}
+
+static void
+mock_dump_desc__nodump(const char *desc, const char *type)
+{
+ (void)desc;
+ (void)type;
+}
+
+static int
+mock_router_produce_hash_final__nohash(char *digest,
+ const char *start, size_t len,
+ digest_algorithm_t alg)
+{
+ (void)start;
+ (void)len;
+ /* we could look at start[..] */
+ if (alg == DIGEST_SHA1)
+ memset(digest, 0x01, 20);
+ else
+ memset(digest, 0x02, 32);
+ return 0;
+}
+
+int
+fuzz_init(void)
+{
+ disable_signature_checking();
+ MOCK(check_tap_onion_key_crosscert,
+ mock_check_tap_onion_key_crosscert__nocheck);
+ MOCK(dump_desc, mock_dump_desc__nodump);
+ MOCK(router_compute_hash_final, mock_router_produce_hash_final__nohash);
+ ed25519_init();
+ return 0;
+}
+
+int
+fuzz_cleanup(void)
+{
+ return 0;
+}
+
+int
+fuzz_main(const uint8_t *data, size_t sz)
+{
+ routerinfo_t *ri;
+ const char *str = (const char*) data;
+ ri = router_parse_entry_from_string((const char *)str,
+ str+sz,
+ 0, 0, 0, NULL);
+ if (ri) {
+ log_debug(LD_GENERAL, "Parsing okay");
+ routerinfo_free(ri);
+ } else {
+ log_debug(LD_GENERAL, "Parsing failed");
+ }
+ return 0;
+}
+
diff --git a/src/test/fuzz/fuzz_diff.c b/src/test/fuzz/fuzz_diff.c
new file mode 100644
index 0000000000..642380b512
--- /dev/null
+++ b/src/test/fuzz/fuzz_diff.c
@@ -0,0 +1,69 @@
+/* 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_);
+ MOCK(consensus_compute_digest_as_signed, mock_consensus_compute_digest_);
+ return 0;
+}
+
+int
+fuzz_cleanup(void)
+{
+ UNMOCK(consensus_compute_digest);
+ UNMOCK(consensus_compute_digest_as_signed);
+ 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
new file mode 100644
index 0000000000..2a3de7ecf7
--- /dev/null
+++ b/src/test/fuzz/fuzz_extrainfo.c
@@ -0,0 +1,65 @@
+/* Copyright (c) 2016-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+#define ROUTERPARSE_PRIVATE
+#include "or.h"
+#include "routerparse.h"
+#include "routerlist.h"
+#include "routerkeys.h"
+#include "fuzzing.h"
+
+static void
+mock_dump_desc__nodump(const char *desc, const char *type)
+{
+ (void)desc;
+ (void)type;
+}
+
+static int
+mock_router_produce_hash_final__nohash(char *digest,
+ const char *start, size_t len,
+ digest_algorithm_t alg)
+{
+ (void)start;
+ (void)len;
+ /* we could look at start[..] */
+ if (alg == DIGEST_SHA1)
+ memset(digest, 0x01, 20);
+ else
+ memset(digest, 0x02, 32);
+ return 0;
+}
+
+int
+fuzz_init(void)
+{
+ disable_signature_checking();
+ MOCK(dump_desc, mock_dump_desc__nodump);
+ MOCK(router_compute_hash_final, mock_router_produce_hash_final__nohash);
+ ed25519_init();
+ return 0;
+}
+
+int
+fuzz_cleanup(void)
+{
+ return 0;
+}
+
+int
+fuzz_main(const uint8_t *data, size_t sz)
+{
+ extrainfo_t *ei;
+ const char *str = (const char*) data;
+ int again = 0;
+ ei = extrainfo_parse_entry_from_string((const char *)str,
+ str+sz,
+ 0, NULL, &again);
+ if (ei) {
+ log_debug(LD_GENERAL, "Parsing okay");
+ extrainfo_free(ei);
+ } else {
+ log_debug(LD_GENERAL, "Parsing failed");
+ }
+ return 0;
+}
+
diff --git a/src/test/fuzz/fuzz_hsdescv2.c b/src/test/fuzz/fuzz_hsdescv2.c
new file mode 100644
index 0000000000..19db265716
--- /dev/null
+++ b/src/test/fuzz/fuzz_hsdescv2.c
@@ -0,0 +1,52 @@
+/* Copyright (c) 2016-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+#define ROUTERPARSE_PRIVATE
+#include "or.h"
+#include "routerparse.h"
+#include "rendcommon.h"
+#include "fuzzing.h"
+
+static void
+mock_dump_desc__nodump(const char *desc, const char *type)
+{
+ (void)desc;
+ (void)type;
+}
+
+int
+fuzz_init(void)
+{
+ disable_signature_checking();
+ MOCK(dump_desc, mock_dump_desc__nodump);
+ ed25519_init();
+ return 0;
+}
+
+int
+fuzz_cleanup(void)
+{
+ return 0;
+}
+
+int
+fuzz_main(const uint8_t *data, size_t sz)
+{
+ rend_service_descriptor_t *desc = NULL;
+ char desc_id[64];
+ char *ipts = NULL;
+ size_t ipts_size, esize;
+ const char *next;
+ char *str = tor_memdup_nulterm(data, sz);
+ (void) rend_parse_v2_service_descriptor(&desc, desc_id, &ipts, &ipts_size,
+ &esize, &next, str, 1);
+ if (desc) {
+ log_debug(LD_GENERAL, "Parsing okay");
+ rend_service_descriptor_free(desc);
+ } else {
+ log_debug(LD_GENERAL, "Parsing failed");
+ }
+ tor_free(ipts);
+ tor_free(str);
+ return 0;
+}
+
diff --git a/src/test/fuzz/fuzz_hsdescv3.c b/src/test/fuzz/fuzz_hsdescv3.c
new file mode 100644
index 0000000000..428774e330
--- /dev/null
+++ b/src/test/fuzz/fuzz_hsdescv3.c
@@ -0,0 +1,99 @@
+/* Copyright (c) 2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#define ROUTERPARSE_PRIVATE
+#define HS_DESCRIPTOR_PRIVATE
+
+#include "or.h"
+#include "ed25519_cert.h" /* Trunnel interface. */
+#include "crypto_ed25519.h"
+#include "hs_descriptor.h"
+#include "routerparse.h"
+#include "util.h"
+
+#include "fuzzing.h"
+
+static void
+mock_dump_desc__nodump(const char *desc, const char *type)
+{
+ (void)desc;
+ (void)type;
+}
+
+static int
+mock_rsa_ed25519_crosscert_check(const uint8_t *crosscert,
+ const size_t crosscert_len,
+ const crypto_pk_t *rsa_id_key,
+ const ed25519_public_key_t *master_key,
+ const time_t reject_if_expired_before)
+{
+ (void) crosscert;
+ (void) crosscert_len;
+ (void) rsa_id_key;
+ (void) master_key;
+ (void) reject_if_expired_before;
+ return 0;
+}
+
+static size_t
+mock_decrypt_desc_layer(const hs_descriptor_t *desc,
+ const uint8_t *encrypted_blob,
+ size_t encrypted_blob_size,
+ int is_superencrypted_layer,
+ char **decrypted_out)
+{
+ (void)is_superencrypted_layer;
+ (void)desc;
+ const size_t overhead = HS_DESC_ENCRYPTED_SALT_LEN + DIGEST256_LEN;
+ if (encrypted_blob_size < overhead)
+ return 0;
+ *decrypted_out = tor_memdup_nulterm(
+ encrypted_blob + HS_DESC_ENCRYPTED_SALT_LEN,
+ encrypted_blob_size - overhead);
+ size_t result = strlen(*decrypted_out);
+ if (result) {
+ return result;
+ } else {
+ tor_free(*decrypted_out);
+ return 0;
+ }
+}
+
+int
+fuzz_init(void)
+{
+ disable_signature_checking();
+ MOCK(dump_desc, mock_dump_desc__nodump);
+ MOCK(rsa_ed25519_crosscert_check, mock_rsa_ed25519_crosscert_check);
+ MOCK(decrypt_desc_layer, mock_decrypt_desc_layer);
+ ed25519_init();
+ return 0;
+}
+
+int
+fuzz_cleanup(void)
+{
+ return 0;
+}
+
+int
+fuzz_main(const uint8_t *data, size_t sz)
+{
+ hs_descriptor_t *desc = NULL;
+ uint8_t subcredential[DIGEST256_LEN];
+
+ char *fuzzing_data = tor_memdup_nulterm(data, sz);
+ memset(subcredential, 'A', sizeof(subcredential));
+
+ hs_desc_decode_descriptor(fuzzing_data, subcredential, &desc);
+ if (desc) {
+ log_debug(LD_GENERAL, "Decoding okay");
+ hs_descriptor_free(desc);
+ } else {
+ log_debug(LD_GENERAL, "Decoding failed");
+ }
+
+ tor_free(fuzzing_data);
+ return 0;
+}
+
diff --git a/src/test/fuzz/fuzz_http.c b/src/test/fuzz/fuzz_http.c
new file mode 100644
index 0000000000..2ffeb60244
--- /dev/null
+++ b/src/test/fuzz/fuzz_http.c
@@ -0,0 +1,133 @@
+/* Copyright (c) 2016-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+
+#define BUFFERS_PRIVATE
+#define DIRECTORY_PRIVATE
+
+#include "or.h"
+#include "backtrace.h"
+#include "buffers.h"
+#include "config.h"
+#include "connection.h"
+#include "directory.h"
+#include "torlog.h"
+
+#include "fuzzing.h"
+
+static void
+mock_connection_write_to_buf_impl_(const char *string, size_t len,
+ connection_t *conn, int compressed)
+{
+ log_debug(LD_GENERAL, "%sResponse:\n%u\nConnection: %p\n%s\n",
+ compressed ? "Compressed " : "", (unsigned)len, conn, string);
+}
+
+static int
+mock_directory_handle_command_get(dir_connection_t *conn,
+ const char *headers,
+ const char *body,
+ size_t body_len)
+{
+ (void)conn;
+
+ log_debug(LD_GENERAL, "Method:\nGET\n");
+
+ if (headers) {
+ log_debug(LD_GENERAL, "Header-Length:\n%u\n", (unsigned)strlen(headers));
+ log_debug(LD_GENERAL, "Headers:\n%s\n", headers);
+ }
+
+ log_debug(LD_GENERAL, "Body-Length:\n%u\n", (unsigned)body_len);
+ if (body) {
+ log_debug(LD_GENERAL, "Body:\n%s\n", body);
+ }
+
+ /* Always tell the caller we succeeded */
+ return 0;
+}
+
+static int
+mock_directory_handle_command_post(dir_connection_t *conn,
+ const char *headers,
+ const char *body,
+ size_t body_len)
+{
+ (void)conn;
+
+ log_debug(LD_GENERAL, "Method:\nPOST\n");
+
+ if (headers) {
+ log_debug(LD_GENERAL, "Header-Length:\n%u\n", (unsigned)strlen(headers));
+ log_debug(LD_GENERAL, "Headers:\n%s\n", headers);
+ }
+
+ log_debug(LD_GENERAL, "Body-Length:\n%u\n", (unsigned)body_len);
+ if (body) {
+ log_debug(LD_GENERAL, "Body:\n%s\n", body);
+ }
+
+ /* Always tell the caller we succeeded */
+ return 0;
+}
+
+int
+fuzz_init(void)
+{
+ /* Set up fake response handler */
+ MOCK(connection_write_to_buf_impl_, mock_connection_write_to_buf_impl_);
+ /* Set up the fake handler functions */
+ MOCK(directory_handle_command_get, mock_directory_handle_command_get);
+ MOCK(directory_handle_command_post, mock_directory_handle_command_post);
+
+ return 0;
+}
+
+int
+fuzz_cleanup(void)
+{
+ UNMOCK(connection_write_to_buf_impl_);
+ UNMOCK(directory_handle_command_get);
+ UNMOCK(directory_handle_command_post);
+ return 0;
+}
+
+int
+fuzz_main(const uint8_t *stdin_buf, size_t data_size)
+{
+ dir_connection_t dir_conn;
+
+ /* Set up the fake connection */
+ memset(&dir_conn, 0, sizeof(dir_connection_t));
+ dir_conn.base_.type = CONN_TYPE_DIR;
+ /* Apparently tor sets this before directory_handle_command() is called. */
+ dir_conn.base_.address = tor_strdup("replace-this-address.example.com");
+
+ dir_conn.base_.inbuf = buf_new_with_data((char*)stdin_buf, data_size);
+ if (!dir_conn.base_.inbuf) {
+ log_debug(LD_GENERAL, "Zero-Length-Input\n");
+ goto done;
+ }
+
+ /* Parse the headers */
+ int rv = directory_handle_command(&dir_conn);
+
+ /* TODO: check the output is correctly parsed based on the input */
+
+ /* Report the parsed origin address */
+ if (dir_conn.base_.address) {
+ log_debug(LD_GENERAL, "Address:\n%s\n", dir_conn.base_.address);
+ }
+
+ log_debug(LD_GENERAL, "Result:\n%d\n", rv);
+
+ done:
+ /* Reset. */
+ tor_free(dir_conn.base_.address);
+ buf_free(dir_conn.base_.inbuf);
+ dir_conn.base_.inbuf = NULL;
+
+ return 0;
+}
+
diff --git a/src/test/fuzz/fuzz_http_connect.c b/src/test/fuzz/fuzz_http_connect.c
new file mode 100644
index 0000000000..dc674070b2
--- /dev/null
+++ b/src/test/fuzz/fuzz_http_connect.c
@@ -0,0 +1,106 @@
+/* Copyright (c) 2016-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+
+#define BUFFERS_PRIVATE
+#define CONNECTION_EDGE_PRIVATE
+
+#include "or.h"
+#include "backtrace.h"
+#include "buffers.h"
+#include "config.h"
+#include "connection.h"
+#include "connection_edge.h"
+#include "proto_socks.h"
+#include "torlog.h"
+
+#include "fuzzing.h"
+
+static void
+mock_connection_write_to_buf_impl_(const char *string, size_t len,
+ connection_t *conn, int compressed)
+{
+ log_debug(LD_GENERAL, "%sResponse:\n%u\nConnection: %p\n%s\n",
+ compressed ? "Compressed " : "", (unsigned)len, conn, string);
+}
+
+static void
+mock_connection_mark_unattached_ap_(entry_connection_t *conn, int endreason,
+ int line, const char *file)
+{
+ (void)conn;
+ (void)endreason;
+ (void)line;
+ (void)file;
+}
+
+static int
+mock_connection_ap_rewrite_and_attach_if_allowed(entry_connection_t *conn,
+ origin_circuit_t *circ,
+ crypt_path_t *cpath)
+{
+ (void)conn;
+ (void)circ;
+ (void)cpath;
+ return 0;
+}
+
+int
+fuzz_init(void)
+{
+ /* Set up fake response handler */
+ MOCK(connection_write_to_buf_impl_, mock_connection_write_to_buf_impl_);
+ /* Set up the fake handler functions */
+ MOCK(connection_mark_unattached_ap_, mock_connection_mark_unattached_ap_);
+ MOCK(connection_ap_rewrite_and_attach_if_allowed,
+ mock_connection_ap_rewrite_and_attach_if_allowed);
+
+ return 0;
+}
+
+int
+fuzz_cleanup(void)
+{
+ UNMOCK(connection_write_to_buf_impl_);
+ UNMOCK(connection_mark_unattached_ap_);
+ UNMOCK(connection_ap_rewrite_and_attach_if_allowed);
+ return 0;
+}
+
+int
+fuzz_main(const uint8_t *stdin_buf, size_t data_size)
+{
+ entry_connection_t conn;
+
+ /* Set up the fake connection */
+ memset(&conn, 0, sizeof(conn));
+ conn.edge_.base_.type = CONN_TYPE_AP;
+ conn.edge_.base_.state = AP_CONN_STATE_HTTP_CONNECT_WAIT;
+ conn.socks_request = tor_malloc_zero(sizeof(socks_request_t));
+ conn.socks_request->listener_type = CONN_TYPE_AP_HTTP_CONNECT_LISTENER;
+
+ conn.edge_.base_.inbuf = buf_new_with_data((char*)stdin_buf, data_size);
+ if (!conn.edge_.base_.inbuf) {
+ log_debug(LD_GENERAL, "Zero-Length-Input\n");
+ goto done;
+ }
+
+ /* Parse the headers */
+ int rv = connection_ap_process_http_connect(&conn);
+
+ /* TODO: check the output is correctly parsed based on the input */
+
+ log_debug(LD_GENERAL, "Result:\n%d\n", rv);
+
+ goto done;
+
+ done:
+ /* Reset. */
+ socks_request_free(conn.socks_request);
+ buf_free(conn.edge_.base_.inbuf);
+ conn.edge_.base_.inbuf = NULL;
+
+ return 0;
+}
+
diff --git a/src/test/fuzz/fuzz_iptsv2.c b/src/test/fuzz/fuzz_iptsv2.c
new file mode 100644
index 0000000000..4abde0c16d
--- /dev/null
+++ b/src/test/fuzz/fuzz_iptsv2.c
@@ -0,0 +1,46 @@
+/* Copyright (c) 2016-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+#define ROUTERPARSE_PRIVATE
+#include "or.h"
+#include "routerparse.h"
+#include "rendcommon.h"
+#include "fuzzing.h"
+
+static void
+mock_dump_desc__nodump(const char *desc, const char *type)
+{
+ (void)desc;
+ (void)type;
+}
+
+int
+fuzz_init(void)
+{
+ disable_signature_checking();
+ MOCK(dump_desc, mock_dump_desc__nodump);
+ ed25519_init();
+ return 0;
+}
+
+int
+fuzz_cleanup(void)
+{
+ return 0;
+}
+
+int
+fuzz_main(const uint8_t *data, size_t sz)
+{
+ rend_service_descriptor_t *desc =
+ tor_malloc_zero(sizeof(rend_service_descriptor_t));
+ const char *str = (const char*) data;
+ int r = rend_parse_introduction_points(desc, str, sz);
+ if (r >= 0) {
+ log_debug(LD_GENERAL, "Parsing okay: %d", r);
+ } else {
+ log_debug(LD_GENERAL, "Parsing failed");
+ }
+ rend_service_descriptor_free(desc);
+ return 0;
+}
+
diff --git a/src/test/fuzz/fuzz_microdesc.c b/src/test/fuzz/fuzz_microdesc.c
new file mode 100644
index 0000000000..396115026e
--- /dev/null
+++ b/src/test/fuzz/fuzz_microdesc.c
@@ -0,0 +1,47 @@
+/* Copyright (c) 2016-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+#define ROUTERPARSE_PRIVATE
+#include "or.h"
+#include "routerparse.h"
+#include "microdesc.h"
+#include "fuzzing.h"
+
+static void
+mock_dump_desc__nodump(const char *desc, const char *type)
+{
+ (void)desc;
+ (void)type;
+}
+
+int
+fuzz_init(void)
+{
+ disable_signature_checking();
+ MOCK(dump_desc, mock_dump_desc__nodump);
+ ed25519_init();
+ return 0;
+}
+
+int
+fuzz_cleanup(void)
+{
+ return 0;
+}
+
+int
+fuzz_main(const uint8_t *data, size_t sz)
+{
+ const char *str = (const char*) data;
+ smartlist_t *result = microdescs_parse_from_string((const char *)str,
+ str+sz,
+ 0, SAVED_NOWHERE, NULL);
+ if (result) {
+ log_debug(LD_GENERAL, "Parsing okay: %d", smartlist_len(result));
+ SMARTLIST_FOREACH(result, microdesc_t *, md, microdesc_free(md));
+ smartlist_free(result);
+ } else {
+ log_debug(LD_GENERAL, "Parsing failed");
+ }
+ return 0;
+}
+
diff --git a/src/test/fuzz/fuzz_multi.sh b/src/test/fuzz/fuzz_multi.sh
new file mode 100755
index 0000000000..b4a17ed8cb
--- /dev/null
+++ b/src/test/fuzz/fuzz_multi.sh
@@ -0,0 +1,34 @@
+MEMLIMIT_BYTES=21990500990976
+
+N_CPUS=1
+if [ $# -ge 1 ]; then
+ N_CPUS="$1"
+ shift
+fi
+
+FILTER=echo
+
+for i in `seq -w "$N_CPUS"`; do
+ if [ "$i" -eq 1 ]; then
+ if [ "$N_CPUS" -eq 1 ]; then
+ INSTANCE=""
+ NUMBER=""
+ else
+ INSTANCE="-M"
+ NUMBER="$i"
+ fi
+ else
+ INSTANCE="-S"
+ NUMBER="$i"
+ fi
+ # use whatever remains on the command-line to prefix the fuzzer command
+ # you have to copy and paste and run these commands yourself
+ "$FILTER" "$@" \
+ ../afl/afl-fuzz \
+ -i src/test/fuzz/fuzz_dir_testcase \
+ -o src/test/fuzz/fuzz_dir_findings \
+ -x src/test/fuzz/fuzz_dir_dictionary/fuzz_dir_http_header.dct \
+ -m "$MEMLIMIT_BYTES" \
+ "$INSTANCE" "$NUMBER" \
+ -- src/test/fuzz_dir
+done
diff --git a/src/test/fuzz/fuzz_vrs.c b/src/test/fuzz/fuzz_vrs.c
new file mode 100644
index 0000000000..baf0610a0b
--- /dev/null
+++ b/src/test/fuzz/fuzz_vrs.c
@@ -0,0 +1,82 @@
+/* Copyright (c) 2016-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+#define ROUTERPARSE_PRIVATE
+#define NETWORKSTATUS_PRIVATE
+#include "or.h"
+#include "routerparse.h"
+#include "memarea.h"
+#include "microdesc.h"
+#include "networkstatus.h"
+#include "fuzzing.h"
+
+static void
+mock_dump_desc__nodump(const char *desc, const char *type)
+{
+ (void)desc;
+ (void)type;
+}
+
+static networkstatus_t *dummy_vote = NULL;
+static memarea_t *area = NULL;
+
+int
+fuzz_init(void)
+{
+ disable_signature_checking();
+ MOCK(dump_desc, mock_dump_desc__nodump);
+ ed25519_init();
+ area = memarea_new();
+ dummy_vote = tor_malloc_zero(sizeof(*dummy_vote));
+ dummy_vote->known_flags = smartlist_new();
+ smartlist_split_string(dummy_vote->known_flags,
+ "Authority BadExit Exit Fast Guard HSDir "
+ "NoEdConsensus Running Stable V2Dir Valid",
+ " ", 0, 0);
+ return 0;
+}
+
+int
+fuzz_cleanup(void)
+{
+ SMARTLIST_FOREACH(dummy_vote->known_flags, char *, cp, tor_free(cp));
+ smartlist_free(dummy_vote->known_flags);
+ tor_free(dummy_vote);
+ return 0;
+}
+
+int
+fuzz_main(const uint8_t *data, size_t sz)
+{
+ char *str = tor_memdup_nulterm(data, sz);
+ const char *s;
+ routerstatus_t *rs_ns = NULL, *rs_md = NULL, *rs_vote = NULL;
+ vote_routerstatus_t *vrs = tor_malloc_zero(sizeof(*vrs));
+ smartlist_t *tokens = smartlist_new();
+
+ s = str;
+ rs_ns = routerstatus_parse_entry_from_string(area, &s, tokens,
+ NULL, NULL, 26, FLAV_NS);
+ tor_assert(smartlist_len(tokens) == 0);
+
+ s = str;
+ rs_md = routerstatus_parse_entry_from_string(area, &s, tokens,
+ NULL, NULL, 26, FLAV_MICRODESC);
+ tor_assert(smartlist_len(tokens) == 0);
+
+ s = str;
+ rs_vote = routerstatus_parse_entry_from_string(area, &s, tokens,
+ dummy_vote, vrs, 26, FLAV_NS);
+ tor_assert(smartlist_len(tokens) == 0);
+
+ log_debug(LD_GENERAL,
+ "ns=%p, md=%p, vote=%p", rs_ns, rs_md, rs_vote);
+
+ routerstatus_free(rs_md);
+ routerstatus_free(rs_ns);
+ vote_routerstatus_free(vrs);
+ memarea_clear(area);
+ smartlist_free(tokens);
+ tor_free(str);
+ return 0;
+}
+
diff --git a/src/test/fuzz/fuzzing.h b/src/test/fuzz/fuzzing.h
new file mode 100644
index 0000000000..aecdbb4e52
--- /dev/null
+++ b/src/test/fuzz/fuzzing.h
@@ -0,0 +1,13 @@
+/* Copyright (c) 2016-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+#ifndef FUZZING_H
+#define FUZZING_H
+
+int fuzz_init(void);
+int fuzz_cleanup(void);
+int fuzz_main(const uint8_t *data, size_t sz);
+
+void disable_signature_checking(void);
+
+#endif /* FUZZING_H */
+
diff --git a/src/test/fuzz/fuzzing_common.c b/src/test/fuzz/fuzzing_common.c
new file mode 100644
index 0000000000..1e98eb6c85
--- /dev/null
+++ b/src/test/fuzz/fuzzing_common.c
@@ -0,0 +1,192 @@
+/* Copyright (c) 2016-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+#define CRYPTO_ED25519_PRIVATE
+#include "orconfig.h"
+#include "or.h"
+#include "backtrace.h"
+#include "config.h"
+#include "fuzzing.h"
+#include "crypto.h"
+#include "crypto_ed25519.h"
+
+extern const char tor_git_revision[];
+const char tor_git_revision[] = "";
+
+static or_options_t *mock_options = NULL;
+static const or_options_t *
+mock_get_options(void)
+{
+ return mock_options;
+}
+
+static int
+mock_crypto_pk_public_checksig__nocheck(const crypto_pk_t *env, char *to,
+ size_t tolen,
+ const char *from, size_t fromlen)
+{
+ tor_assert(env && to && from);
+ (void)fromlen;
+ /* We could look at from[0..fromlen-1] ... */
+ tor_assert(tolen >= crypto_pk_keysize(env));
+ size_t siglen = MIN(20, crypto_pk_keysize(env));
+ memset(to, 0x01, siglen);
+ return (int)siglen;
+}
+
+static int
+mock_crypto_pk_public_checksig_digest__nocheck(crypto_pk_t *env,
+ const char *data,
+ size_t datalen,
+ const char *sig,
+ size_t siglen)
+{
+ tor_assert(env && data && sig);
+ (void)datalen;
+ (void)siglen;
+ /* We could look at data[..] and sig[..] */
+ return 0;
+}
+
+static int
+mock_ed25519_checksig__nocheck(const ed25519_signature_t *signature,
+ const uint8_t *msg, size_t len,
+ const ed25519_public_key_t *pubkey)
+{
+ tor_assert(signature && msg && pubkey);
+ /* We could look at msg[0..len-1] ... */
+ (void)len;
+ return 0;
+}
+
+static int
+mock_ed25519_checksig_batch__nocheck(int *okay_out,
+ const ed25519_checkable_t *checkable,
+ int n_checkable)
+{
+ tor_assert(checkable);
+ int i;
+ for (i = 0; i < n_checkable; ++i) {
+ /* We could look at messages and signatures XXX */
+ tor_assert(checkable[i].pubkey);
+ tor_assert(checkable[i].msg);
+ if (okay_out)
+ okay_out[i] = 1;
+ }
+ return 0;
+}
+
+static int
+mock_ed25519_impl_spot_check__nocheck(void)
+{
+ return 0;
+}
+
+void
+disable_signature_checking(void)
+{
+ MOCK(crypto_pk_public_checksig,
+ mock_crypto_pk_public_checksig__nocheck);
+ MOCK(crypto_pk_public_checksig_digest,
+ mock_crypto_pk_public_checksig_digest__nocheck);
+ MOCK(ed25519_checksig, mock_ed25519_checksig__nocheck);
+ MOCK(ed25519_checksig_batch, mock_ed25519_checksig_batch__nocheck);
+ MOCK(ed25519_impl_spot_check, mock_ed25519_impl_spot_check__nocheck);
+}
+
+static void
+global_init(void)
+{
+ tor_threads_init();
+ tor_compress_init();
+ {
+ struct sipkey sipkey = { 1337, 7331 };
+ siphash_set_global_key(&sipkey);
+ }
+
+ /* Initialise logging first */
+ init_logging(1);
+ configure_backtrace_handler(get_version());
+
+ /* set up the options. */
+ mock_options = tor_malloc_zero(sizeof(or_options_t));
+ MOCK(get_options, mock_get_options);
+
+ /* Make BUG() and nonfatal asserts crash */
+ tor_set_failed_assertion_callback(abort);
+}
+
+#ifdef LLVM_FUZZ
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
+int
+LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
+{
+ static int initialized = 0;
+ if (!initialized) {
+ global_init();
+ if (fuzz_init() < 0)
+ abort();
+ initialized = 1;
+ }
+
+ return fuzz_main(Data, Size);
+}
+
+#else /* Not LLVM_FUZZ, so AFL. */
+
+int
+main(int argc, char **argv)
+{
+ size_t size;
+
+ global_init();
+
+ /* Disable logging by default to speed up fuzzing. */
+ int loglevel = LOG_ERR;
+
+ for (int i = 1; i < argc; ++i) {
+ if (!strcmp(argv[i], "--warn")) {
+ loglevel = LOG_WARN;
+ } else if (!strcmp(argv[i], "--notice")) {
+ loglevel = LOG_NOTICE;
+ } else if (!strcmp(argv[i], "--info")) {
+ loglevel = LOG_INFO;
+ } else if (!strcmp(argv[i], "--debug")) {
+ loglevel = LOG_DEBUG;
+ }
+ }
+
+ {
+ log_severity_list_t s;
+ memset(&s, 0, sizeof(s));
+ set_log_severity_config(loglevel, LOG_ERR, &s);
+ /* ALWAYS log bug warnings. */
+ s.masks[LOG_WARN-LOG_ERR] |= LD_BUG;
+ add_stream_log(&s, "", fileno(stdout));
+ }
+
+ if (fuzz_init() < 0)
+ abort();
+
+#ifdef __AFL_HAVE_MANUAL_CONTROL
+ /* Tell AFL to pause and fork here - ignored if not using AFL */
+ __AFL_INIT();
+#endif
+
+#define MAX_FUZZ_SIZE (128*1024)
+ char *input = read_file_to_str_until_eof(0, MAX_FUZZ_SIZE, &size);
+ tor_assert(input);
+ char *raw = tor_memdup(input, size); /* Because input is nul-terminated */
+ tor_free(input);
+ fuzz_main((const uint8_t*)raw, size);
+ tor_free(raw);
+
+ if (fuzz_cleanup() < 0)
+ abort();
+
+ tor_free(mock_options);
+ UNMOCK(get_options);
+ return 0;
+}
+
+#endif
+
diff --git a/src/test/fuzz/include.am b/src/test/fuzz/include.am
new file mode 100644
index 0000000000..cd16dc05be
--- /dev/null
+++ b/src/test/fuzz/include.am
@@ -0,0 +1,351 @@
+# 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 = \
+ $(AM_CFLAGS) $(TEST_CFLAGS)
+FUZZING_LDFLAG = \
+ @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ @TOR_LDFLAGS_libevent@
+FUZZING_LIBS = \
+ src/or/libtor-testing.a \
+ src/common/libor-crypto-testing.a \
+ $(LIBKECCAK_TINY) \
+ $(LIBDONNA) \
+ src/common/libor-testing.a \
+ src/common/libor-ctime-testing.a \
+ src/common/libor-event-testing.a \
+ src/trunnel/libor-trunnel-testing.a \
+ $(rust_ldadd) \
+ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \
+ @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \
+ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ @CURVE25519_LIBS@ \
+ @TOR_SYSTEMD_LIBS@ \
+ @TOR_LZMA_LIBS@ \
+ @TOR_ZSTD_LIBS@
+
+oss-fuzz-prereqs: \
+ src/or/libtor-testing.a \
+ src/common/libor-crypto-testing.a \
+ $(LIBKECCAK_TINY) \
+ $(LIBDONNA) \
+ src/common/libor-testing.a \
+ src/common/libor-ctime-testing.a \
+ src/common/libor-event-testing.a \
+ src/trunnel/libor-trunnel-testing.a
+
+noinst_HEADERS += \
+ src/test/fuzz/fuzzing.h
+
+LIBFUZZER = -lFuzzer
+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
+src_test_fuzz_fuzz_consensus_CPPFLAGS = $(FUZZING_CPPFLAGS)
+src_test_fuzz_fuzz_consensus_CFLAGS = $(FUZZING_CFLAGS)
+src_test_fuzz_fuzz_consensus_LDFLAGS = $(FUZZING_LDFLAG)
+src_test_fuzz_fuzz_consensus_LDADD = $(FUZZING_LIBS)
+
+src_test_fuzz_fuzz_descriptor_SOURCES = \
+ src/test/fuzz/fuzzing_common.c \
+ src/test/fuzz/fuzz_descriptor.c
+src_test_fuzz_fuzz_descriptor_CPPFLAGS = $(FUZZING_CPPFLAGS)
+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_diff_SOURCES = \
+ src/test/fuzz/fuzzing_common.c \
+ 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 \
+ src/test/fuzz/fuzz_hsdescv2.c
+src_test_fuzz_fuzz_hsdescv2_CPPFLAGS = $(FUZZING_CPPFLAGS)
+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_hsdescv3_SOURCES = \
+ src/test/fuzz/fuzzing_common.c \
+ src/test/fuzz/fuzz_hsdescv3.c
+src_test_fuzz_fuzz_hsdescv3_CPPFLAGS = $(FUZZING_CPPFLAGS)
+src_test_fuzz_fuzz_hsdescv3_CFLAGS = $(FUZZING_CFLAGS)
+src_test_fuzz_fuzz_hsdescv3_LDFLAGS = $(FUZZING_LDFLAG)
+src_test_fuzz_fuzz_hsdescv3_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_http_connect_SOURCES = \
+ src/test/fuzz/fuzzing_common.c \
+ src/test/fuzz/fuzz_http_connect.c
+src_test_fuzz_fuzz_http_connect_CPPFLAGS = $(FUZZING_CPPFLAGS)
+src_test_fuzz_fuzz_http_connect_CFLAGS = $(FUZZING_CFLAGS)
+src_test_fuzz_fuzz_http_connect_LDFLAGS = $(FUZZING_LDFLAG)
+src_test_fuzz_fuzz_http_connect_LDADD = $(FUZZING_LIBS)
+
+src_test_fuzz_fuzz_iptsv2_SOURCES = \
+ src/test/fuzz/fuzzing_common.c \
+ src/test/fuzz/fuzz_iptsv2.c
+src_test_fuzz_fuzz_iptsv2_CPPFLAGS = $(FUZZING_CPPFLAGS)
+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_microdesc_SOURCES = \
+ src/test/fuzz/fuzzing_common.c \
+ src/test/fuzz/fuzz_microdesc.c
+src_test_fuzz_fuzz_microdesc_CPPFLAGS = $(FUZZING_CPPFLAGS)
+src_test_fuzz_fuzz_microdesc_CFLAGS = $(FUZZING_CFLAGS)
+src_test_fuzz_fuzz_microdesc_LDFLAGS = $(FUZZING_LDFLAG)
+src_test_fuzz_fuzz_microdesc_LDADD = $(FUZZING_LIBS)
+
+src_test_fuzz_fuzz_vrs_SOURCES = \
+ src/test/fuzz/fuzzing_common.c \
+ src/test/fuzz/fuzz_vrs.c
+src_test_fuzz_fuzz_vrs_CPPFLAGS = $(FUZZING_CPPFLAGS)
+src_test_fuzz_fuzz_vrs_CFLAGS = $(FUZZING_CFLAGS)
+src_test_fuzz_fuzz_vrs_LDFLAGS = $(FUZZING_LDFLAG)
+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-hsdescv2 \
+ src/test/fuzz/fuzz-hsdescv3 \
+ src/test/fuzz/fuzz-http \
+ src/test/fuzz/fuzz-http-connect \
+ src/test/fuzz/fuzz-iptsv2 \
+ src/test/fuzz/fuzz-microdesc \
+ src/test/fuzz/fuzz-vrs
+
+# ===== libfuzzer
+
+if LIBFUZZER_ENABLED
+src_test_fuzz_lf_fuzz_consensus_SOURCES = \
+ $(src_test_fuzz_fuzz_consensus_SOURCES)
+src_test_fuzz_lf_fuzz_consensus_CPPFLAGS = $(LIBFUZZER_CPPFLAGS)
+src_test_fuzz_lf_fuzz_consensus_CFLAGS = $(LIBFUZZER_CFLAGS)
+src_test_fuzz_lf_fuzz_consensus_LDFLAGS = $(LIBFUZZER_LDFLAG)
+src_test_fuzz_lf_fuzz_consensus_LDADD = $(LIBFUZZER_LIBS)
+
+src_test_fuzz_lf_fuzz_descriptor_SOURCES = \
+ $(src_test_fuzz_fuzz_descriptor_SOURCES)
+src_test_fuzz_lf_fuzz_descriptor_CPPFLAGS = $(LIBFUZZER_CPPFLAGS)
+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)
+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_hsdescv2_SOURCES = \
+ $(src_test_fuzz_fuzz_hsdescv2_SOURCES)
+src_test_fuzz_lf_fuzz_hsdescv2_CPPFLAGS = $(LIBFUZZER_CPPFLAGS)
+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_hsdescv3_SOURCES = \
+ $(src_test_fuzz_fuzz_hsdescv3_SOURCES)
+src_test_fuzz_lf_fuzz_hsdescv3_CPPFLAGS = $(LIBFUZZER_CPPFLAGS)
+src_test_fuzz_lf_fuzz_hsdescv3_CFLAGS = $(LIBFUZZER_CFLAGS)
+src_test_fuzz_lf_fuzz_hsdescv3_LDFLAGS = $(LIBFUZZER_LDFLAG)
+src_test_fuzz_lf_fuzz_hsdescv3_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_http_connect_SOURCES = \
+ $(src_test_fuzz_fuzz_http_connect_SOURCES)
+src_test_fuzz_lf_fuzz_http_connect_CPPFLAGS = $(LIBFUZZER_CPPFLAGS)
+src_test_fuzz_lf_fuzz_http_connect_CFLAGS = $(LIBFUZZER_CFLAGS)
+src_test_fuzz_lf_fuzz_http_connect_LDFLAGS = $(LIBFUZZER_LDFLAG)
+src_test_fuzz_lf_fuzz_http_connect_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)
+src_test_fuzz_lf_fuzz_iptsv2_CFLAGS = $(LIBFUZZER_CFLAGS)
+src_test_fuzz_lf_fuzz_iptsv2_LDFLAGS = $(LIBFUZZER_LDFLAG)
+src_test_fuzz_lf_fuzz_iptsv2_LDADD = $(LIBFUZZER_LIBS)
+
+src_test_fuzz_lf_fuzz_microdesc_SOURCES = \
+ $(src_test_fuzz_fuzz_microdesc_SOURCES)
+src_test_fuzz_lf_fuzz_microdesc_CPPFLAGS = $(LIBFUZZER_CPPFLAGS)
+src_test_fuzz_lf_fuzz_microdesc_CFLAGS = $(LIBFUZZER_CFLAGS)
+src_test_fuzz_lf_fuzz_microdesc_LDFLAGS = $(LIBFUZZER_LDFLAG)
+src_test_fuzz_lf_fuzz_microdesc_LDADD = $(LIBFUZZER_LIBS)
+
+src_test_fuzz_lf_fuzz_vrs_SOURCES = \
+ $(src_test_fuzz_fuzz_vrs_SOURCES)
+src_test_fuzz_lf_fuzz_vrs_CPPFLAGS = $(LIBFUZZER_CPPFLAGS)
+src_test_fuzz_lf_fuzz_vrs_CFLAGS = $(LIBFUZZER_CFLAGS)
+src_test_fuzz_lf_fuzz_vrs_LDFLAGS = $(LIBFUZZER_LDFLAG)
+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-hsdescv2 \
+ src/test/fuzz/lf-fuzz-hsdescv3 \
+ src/test/fuzz/lf-fuzz-http \
+ src/test/fuzz/lf-fuzz-http-connect \
+ src/test/fuzz/lf-fuzz-iptsv2 \
+ src/test/fuzz/lf-fuzz-microdesc \
+ src/test/fuzz/lf-fuzz-vrs
+
+else
+LIBFUZZER_FUZZERS =
+endif
+
+# ===== 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)
+src_test_fuzz_liboss_fuzz_consensus_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS)
+
+src_test_fuzz_liboss_fuzz_descriptor_a_SOURCES = \
+ $(src_test_fuzz_fuzz_descriptor_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_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_hsdescv3_a_SOURCES = \
+ $(src_test_fuzz_fuzz_hsdescv3_SOURCES)
+src_test_fuzz_liboss_fuzz_hsdescv3_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS)
+src_test_fuzz_liboss_fuzz_hsdescv3_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_http_connect_a_SOURCES = \
+ $(src_test_fuzz_fuzz_http_connect_SOURCES)
+src_test_fuzz_liboss_fuzz_http_connect_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS)
+src_test_fuzz_liboss_fuzz_http_connect_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)
+src_test_fuzz_liboss_fuzz_iptsv2_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS)
+
+src_test_fuzz_liboss_fuzz_microdesc_a_SOURCES = \
+ $(src_test_fuzz_fuzz_microdesc_SOURCES)
+src_test_fuzz_liboss_fuzz_microdesc_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS)
+src_test_fuzz_liboss_fuzz_microdesc_a_CFLAGS = $(LIBOSS_FUZZ_CFLAGS)
+
+src_test_fuzz_liboss_fuzz_vrs_a_SOURCES = \
+ $(src_test_fuzz_fuzz_vrs_SOURCES)
+src_test_fuzz_liboss_fuzz_vrs_a_CPPFLAGS = $(LIBOSS_FUZZ_CPPFLAGS)
+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-hsdescv2.a \
+ src/test/fuzz/liboss-fuzz-hsdescv3.a \
+ src/test/fuzz/liboss-fuzz-http.a \
+ src/test/fuzz/liboss-fuzz-http-connect.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
+
+noinst_PROGRAMS += $(FUZZERS) $(LIBFUZZER_FUZZERS)
+noinst_LIBRARIES += $(OSS_FUZZ_FUZZERS)
+oss-fuzz-fuzzers: oss-fuzz-prereqs $(OSS_FUZZ_FUZZERS)
+fuzzers: $(FUZZERS) $(LIBFUZZER_FUZZERS)
+
+test-fuzz-corpora: $(FUZZERS)
+ $(top_srcdir)/src/test/fuzz_static_testcases.sh
diff --git a/src/test/fuzz/minimize.sh b/src/test/fuzz/minimize.sh
new file mode 100755
index 0000000000..87d3dda13c
--- /dev/null
+++ b/src/test/fuzz/minimize.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+set -e
+
+if [ ! -d "$1" ] ; then
+ echo "I need a directory"
+ exit 1
+fi
+
+which=`basename "$1"`
+
+mkdir "$1.out"
+afl-cmin -i "$1" -o "$1.out" -m none "./src/test/fuzz/fuzz-${which}"
+
diff --git a/src/test/fuzz_static_testcases.sh b/src/test/fuzz_static_testcases.sh
new file mode 100755
index 0000000000..3cb45ad5e6
--- /dev/null
+++ b/src/test/fuzz_static_testcases.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+# Copyright (c) 2016-2017, The Tor Project, Inc.
+# See LICENSE for licensing information
+
+set -e
+
+if [ -z "${TOR_FUZZ_CORPORA}" ] || [ ! -d "${TOR_FUZZ_CORPORA}" ] ; then
+ echo "You need to set TOR_FUZZ_CORPORA to point to a checkout of "
+ echo "the 'fuzzing-corpora' repository."
+ exit 77
+fi
+
+
+
+for fuzzer in "${builddir:-.}"/src/test/fuzz/fuzz-* ; do
+ f=`basename $fuzzer`
+ case="${f#fuzz-}"
+ if [ -d "${TOR_FUZZ_CORPORA}/${case}" ]; then
+ echo "Running tests for ${case}"
+ for entry in "${TOR_FUZZ_CORPORA}/${case}/"*; do
+ "${fuzzer}" "--err" < "$entry"
+ done
+ else
+ echo "No tests found for ${case}"
+ fi
+done
diff --git a/src/test/hs_build_address.py b/src/test/hs_build_address.py
new file mode 100644
index 0000000000..7ff22c3a9a
--- /dev/null
+++ b/src/test/hs_build_address.py
@@ -0,0 +1,38 @@
+import sys
+import hashlib
+import struct
+import base64
+
+# Python 3.6+, the SHA3 is available in hashlib natively. Else this requires
+# the pysha3 package (pip install pysha3).
+if sys.version_info < (3, 6):
+ import sha3
+
+# Test vector to make sure the right sha3 version will be used. pysha3 < 1.0
+# used the old Keccak implementation. During the finalization of SHA3, NIST
+# changed the delimiter suffix from 0x01 to 0x06. The Keccak sponge function
+# stayed the same. pysha3 1.0 provides the previous Keccak hash, too.
+TEST_VALUE = "e167f68d6563d75bb25f3aa49c29ef612d41352dc00606de7cbd630bb2665f51"
+if TEST_VALUE != sha3.sha3_256(b"Hello World").hexdigest():
+ print("pysha3 version is < 1.0. Please install from:")
+ print("https://github.com/tiran/pysha3https://github.com/tiran/pysha3")
+ sys.exit(1)
+
+# Checksum is built like so:
+# CHECKSUM = SHA3(".onion checksum" || PUBKEY || VERSION)
+PREFIX = ".onion checksum".encode()
+# 32 bytes ed25519 pubkey from first test vector of
+# https://tools.ietf.org/html/draft-josefsson-eddsa-ed25519-02#section-6
+PUBKEY = "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a".decode('hex')
+# Version 3 is proposal224
+VERSION = 3
+
+data = struct.pack('15s32sb', PREFIX, PUBKEY, VERSION)
+checksum = hashlib.sha3_256(data).digest()
+
+# Onion address is built like so:
+# onion_address = base32(PUBKEY || CHECKSUM || VERSION) + ".onion"
+address = struct.pack('!32s2sb', PUBKEY, checksum, VERSION)
+onion_addr = base64.b32encode(address).decode().lower()
+
+print("%s" % (onion_addr))
diff --git a/src/test/hs_indexes.py b/src/test/hs_indexes.py
new file mode 100644
index 0000000000..af0b81f8de
--- /dev/null
+++ b/src/test/hs_indexes.py
@@ -0,0 +1,70 @@
+#
+# The hidden service subsystem has two type of index. The first type is a
+# value that each node in the network gets assigned to using their identity
+# key which is their position in the hashring. (hs_build_hsdir_index()).
+#
+# The second type is a value that both the client and service computes to
+# store/fetch the descriptor on the hashring. (hs_build_hs_index()).
+#
+
+import sys
+import hashlib
+import struct
+import base64
+
+# Python 3.6+, the SHA3 is available in hashlib natively. Else this requires
+# the pysha3 package (pip install pysha3).
+if sys.version_info < (3, 6):
+ import sha3
+ # Test vector to make sure the right sha3 version will be used. pysha3 < 1.0
+ # used the old Keccak implementation. During the finalization of SHA3, NIST
+ # changed the delimiter suffix from 0x01 to 0x06. The Keccak sponge function
+ # stayed the same. pysha3 1.0 provides the previous Keccak hash, too.
+ TEST_VALUE = "e167f68d6563d75bb25f3aa49c29ef612d41352dc00606de7cbd630bb2665f51"
+ if TEST_VALUE != sha3.sha3_256(b"Hello World").hexdigest():
+ print("pysha3 version is < 1.0. Please install from:")
+ print("https://github.com/tiran/pysha3https://github.com/tiran/pysha3")
+ sys.exit(1)
+
+# The first index we'll build is the position index in the hashring that is
+# constructed by the hs_build_hsdir_index() function. Construction is:
+# SHA3-256("node-idx" | node_identity |
+# shared_random_value | INT_8(period_length) | INT_8(period_num) )
+
+PREFIX = "node-idx".encode()
+# 32 bytes ed25519 pubkey.
+IDENTITY = ("\x42" * 32).encode()
+# SRV is 32 bytes.
+SRV = ("\x43" * 32).encode()
+# Time period length is a 8 bytes value.
+PERIOD_LEN = 1440
+# Period number is a 8 bytes value.
+PERIOD_NUM = 42
+
+data = struct.pack('!8s32s32sQQ', PREFIX, IDENTITY, SRV, PERIOD_NUM,
+ PERIOD_LEN)
+hsdir_index = hashlib.sha3_256(data).hexdigest()
+
+print("[hs_build_hsdir_index] %s" % (hsdir_index))
+
+# The second index we'll build is where the HS stores and the client fetches
+# the descriptor on the hashring. It is constructed by the hs_build_hs_index()
+# function and the construction is:
+# SHA3-256("store-at-idx" | blinded_public_key |
+# INT_8(replicanum) | INT_8(period_num) | INT_8(period_length) )
+
+PREFIX = "store-at-idx".encode()
+# 32 bytes ed25519 pubkey.
+PUBKEY = ("\x42" * 32).encode()
+# Replica number is a 8 bytes value.
+REPLICA_NUM = 1
+# Time period length is a 8 bytes value.
+PERIOD_LEN = 1440
+# Period number is a 8 bytes value.
+PERIOD_NUM = 42
+
+data = struct.pack('!12s32sQQQ', PREFIX, PUBKEY, REPLICA_NUM, PERIOD_LEN,
+ PERIOD_NUM)
+hs_index = hashlib.sha3_256(data).hexdigest()
+
+print("[hs_build_hs_index] %s" % (hs_index))
diff --git a/src/test/hs_ntor_ref.py b/src/test/hs_ntor_ref.py
new file mode 100644
index 0000000000..542b02d2e0
--- /dev/null
+++ b/src/test/hs_ntor_ref.py
@@ -0,0 +1,428 @@
+#!/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
+
+import hashlib
+try:
+ import sha3
+except ImportError:
+ # In python 3.6, the sha3 functions are in hashlib whether we
+ # import sha3 or not.
+ sha3 = None
+
+try:
+ # Pull the sha3 functions in.
+ from hashlib import sha3_256, shake_256
+ shake_squeeze = shake_256.digest
+except ImportError:
+ if hasattr(sha3, "SHA3256"):
+ # If this happens, then we have the old "sha3" module which
+ # hashlib and pysha3 superseded.
+ sha3_256 = sha3.SHA3256
+ shake_256 = sha3.SHAKE256
+ shake_squeeze = shake_256.squeeze
+ else:
+ # 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 = b"tor-hs-ntor-curve25519-sha3-256-1"
+T_HSENC = PROTOID + b":hs_key_extract"
+T_HSVERIFY = PROTOID + b":hs_verify"
+T_HSMAC = PROTOID + b":hs_mac"
+M_HSEXPAND = PROTOID + b":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_256()
+ 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 = shake_256()
+ kdf.update(secret + T_HSENC + info)
+ key_material = shake_squeeze(kdf, 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 = shake_256()
+ kdf.update(secret + T_HSENC + info)
+ key_material = shake_squeeze(kdf, 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 + b"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 + b"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 = "./src/test/test-hs-ntor-cl"
+if sys.version_info[0] >= 3:
+ enhex=lambda s: binascii.b2a_hex(s).decode("ascii")
+else:
+ 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/hs_test_helpers.c b/src/test/hs_test_helpers.c
new file mode 100644
index 0000000000..5c1b9123d8
--- /dev/null
+++ b/src/test/hs_test_helpers.c
@@ -0,0 +1,282 @@
+/* Copyright (c) 2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "or.h"
+#include "crypto_ed25519.h"
+#include "test.h"
+#include "torcert.h"
+
+#include "hs_common.h"
+#include "hs_test_helpers.h"
+
+hs_desc_intro_point_t *
+hs_helper_build_intro_point(const ed25519_keypair_t *signing_kp, time_t now,
+ const char *addr, int legacy)
+{
+ int ret;
+ ed25519_keypair_t auth_kp;
+ hs_desc_intro_point_t *intro_point = NULL;
+ hs_desc_intro_point_t *ip = hs_desc_intro_point_new();
+
+ /* For a usable intro point we need at least two link specifiers: One legacy
+ * keyid and one ipv4 */
+ {
+ hs_desc_link_specifier_t *ls_legacy = tor_malloc_zero(sizeof(*ls_legacy));
+ hs_desc_link_specifier_t *ls_v4 = tor_malloc_zero(sizeof(*ls_v4));
+ ls_legacy->type = LS_LEGACY_ID;
+ memcpy(ls_legacy->u.legacy_id, "0299F268FCA9D55CD157976D39AE92B4B455B3A8",
+ DIGEST_LEN);
+ ls_v4->u.ap.port = 9001;
+ int family = tor_addr_parse(&ls_v4->u.ap.addr, addr);
+ switch (family) {
+ case AF_INET:
+ ls_v4->type = LS_IPV4;
+ break;
+ case AF_INET6:
+ ls_v4->type = LS_IPV6;
+ break;
+ default:
+ /* Stop the test, not suppose to have an error. */
+ tt_int_op(family, OP_EQ, AF_INET);
+ }
+ smartlist_add(ip->link_specifiers, ls_legacy);
+ smartlist_add(ip->link_specifiers, ls_v4);
+ }
+
+ ret = ed25519_keypair_generate(&auth_kp, 0);
+ tt_int_op(ret, ==, 0);
+ ip->auth_key_cert = tor_cert_create(signing_kp, CERT_TYPE_AUTH_HS_IP_KEY,
+ &auth_kp.pubkey, now,
+ HS_DESC_CERT_LIFETIME,
+ CERT_FLAG_INCLUDE_SIGNING_KEY);
+ tt_assert(ip->auth_key_cert);
+
+ if (legacy) {
+ ip->legacy.key = crypto_pk_new();
+ tt_assert(ip->legacy.key);
+ ret = crypto_pk_generate_key(ip->legacy.key);
+ tt_int_op(ret, ==, 0);
+ ssize_t cert_len = tor_make_rsa_ed25519_crosscert(
+ &signing_kp->pubkey, ip->legacy.key,
+ now + HS_DESC_CERT_LIFETIME,
+ &ip->legacy.cert.encoded);
+ tt_assert(ip->legacy.cert.encoded);
+ tt_u64_op(cert_len, OP_GT, 0);
+ ip->legacy.cert.len = cert_len;
+ }
+
+ /* Encryption key. */
+ {
+ int signbit;
+ curve25519_keypair_t curve25519_kp;
+ ed25519_keypair_t ed25519_kp;
+ tor_cert_t *cross_cert;
+
+ ret = curve25519_keypair_generate(&curve25519_kp, 0);
+ tt_int_op(ret, ==, 0);
+ ed25519_keypair_from_curve25519_keypair(&ed25519_kp, &signbit,
+ &curve25519_kp);
+ cross_cert = tor_cert_create(signing_kp, CERT_TYPE_CROSS_HS_IP_KEYS,
+ &ed25519_kp.pubkey, time(NULL),
+ HS_DESC_CERT_LIFETIME,
+ CERT_FLAG_INCLUDE_SIGNING_KEY);
+ tt_assert(cross_cert);
+ ip->enc_key_cert = cross_cert;
+ }
+
+ intro_point = ip;
+ done:
+ if (intro_point == NULL)
+ tor_free(ip);
+
+ return intro_point;
+}
+
+/* Return a valid hs_descriptor_t object. If no_ip is set, no introduction
+ * points are added. */
+static hs_descriptor_t *
+hs_helper_build_hs_desc_impl(unsigned int no_ip,
+ const ed25519_keypair_t *signing_kp)
+{
+ time_t now = approx_time();
+ ed25519_keypair_t blinded_kp;
+ hs_descriptor_t *descp = NULL, *desc = tor_malloc_zero(sizeof(*desc));
+
+ desc->plaintext_data.version = HS_DESC_SUPPORTED_FORMAT_VERSION_MAX;
+
+ /* Copy only the public key into the descriptor. */
+ memcpy(&desc->plaintext_data.signing_pubkey, &signing_kp->pubkey,
+ sizeof(ed25519_public_key_t));
+
+ uint64_t current_time_period = hs_get_time_period_num(0);
+ hs_build_blinded_keypair(signing_kp, NULL, 0,
+ current_time_period, &blinded_kp);
+ /* Copy only the public key into the descriptor. */
+ memcpy(&desc->plaintext_data.blinded_pubkey, &blinded_kp.pubkey,
+ sizeof(ed25519_public_key_t));
+
+ desc->plaintext_data.signing_key_cert =
+ tor_cert_create(&blinded_kp, CERT_TYPE_SIGNING_HS_DESC,
+ &signing_kp->pubkey, now, 3600,
+ CERT_FLAG_INCLUDE_SIGNING_KEY);
+ tt_assert(desc->plaintext_data.signing_key_cert);
+ desc->plaintext_data.revision_counter = 42;
+ desc->plaintext_data.lifetime_sec = 3 * 60 * 60;
+
+ hs_get_subcredential(&signing_kp->pubkey, &blinded_kp.pubkey,
+ desc->subcredential);
+
+ /* Setup encrypted data section. */
+ desc->encrypted_data.create2_ntor = 1;
+ desc->encrypted_data.intro_auth_types = smartlist_new();
+ desc->encrypted_data.single_onion_service = 1;
+ 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. */
+ smartlist_add(desc->encrypted_data.intro_points,
+ hs_helper_build_intro_point(signing_kp, now, "1.2.3.4", 0));
+ smartlist_add(desc->encrypted_data.intro_points,
+ hs_helper_build_intro_point(signing_kp, now, "[2600::1]", 0));
+ smartlist_add(desc->encrypted_data.intro_points,
+ hs_helper_build_intro_point(signing_kp, now, "3.2.1.4", 1));
+ smartlist_add(desc->encrypted_data.intro_points,
+ hs_helper_build_intro_point(signing_kp, now, "5.6.7.8", 1));
+ }
+
+ descp = desc;
+ done:
+ if (descp == NULL)
+ tor_free(desc);
+
+ return descp;
+}
+
+/** Helper function to get the HS subcredential using the identity keypair of
+ * an HS. Used to decrypt descriptors in unittests. */
+void
+hs_helper_get_subcred_from_identity_keypair(ed25519_keypair_t *signing_kp,
+ uint8_t *subcred_out)
+{
+ ed25519_keypair_t blinded_kp;
+ uint64_t current_time_period = hs_get_time_period_num(approx_time());
+ hs_build_blinded_keypair(signing_kp, NULL, 0,
+ current_time_period, &blinded_kp);
+
+ hs_get_subcredential(&signing_kp->pubkey, &blinded_kp.pubkey,
+ subcred_out);
+}
+
+/* Build a descriptor with introduction points. */
+hs_descriptor_t *
+hs_helper_build_hs_desc_with_ip(const ed25519_keypair_t *signing_kp)
+{
+ return hs_helper_build_hs_desc_impl(0, signing_kp);
+}
+
+/* Build a descriptor without any introduction points. */
+hs_descriptor_t *
+hs_helper_build_hs_desc_no_ip(const ed25519_keypair_t *signing_kp)
+{
+ return hs_helper_build_hs_desc_impl(1, signing_kp);
+}
+
+void
+hs_helper_desc_equal(const hs_descriptor_t *desc1,
+ const hs_descriptor_t *desc2)
+{
+ char *addr1 = NULL, *addr2 = NULL;
+ /* Plaintext data section. */
+ tt_int_op(desc1->plaintext_data.version, OP_EQ,
+ desc2->plaintext_data.version);
+ tt_uint_op(desc1->plaintext_data.lifetime_sec, OP_EQ,
+ desc2->plaintext_data.lifetime_sec);
+ tt_assert(tor_cert_eq(desc1->plaintext_data.signing_key_cert,
+ desc2->plaintext_data.signing_key_cert));
+ tt_mem_op(desc1->plaintext_data.signing_pubkey.pubkey, OP_EQ,
+ desc2->plaintext_data.signing_pubkey.pubkey,
+ ED25519_PUBKEY_LEN);
+ tt_mem_op(desc1->plaintext_data.blinded_pubkey.pubkey, OP_EQ,
+ desc2->plaintext_data.blinded_pubkey.pubkey,
+ ED25519_PUBKEY_LEN);
+ tt_u64_op(desc1->plaintext_data.revision_counter, ==,
+ desc2->plaintext_data.revision_counter);
+
+ /* NOTE: We can't compare the encrypted blob because when encoding the
+ * descriptor, the object is immutable thus we don't update it with the
+ * encrypted blob. As contrast to the decoding process where we populate a
+ * descriptor object. */
+
+ /* Encrypted data section. */
+ tt_uint_op(desc1->encrypted_data.create2_ntor, ==,
+ desc2->encrypted_data.create2_ntor);
+
+ /* Authentication type. */
+ 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));
+ }
+ }
+
+ /* Introduction points. */
+ {
+ tt_assert(desc1->encrypted_data.intro_points);
+ tt_assert(desc2->encrypted_data.intro_points);
+ tt_int_op(smartlist_len(desc1->encrypted_data.intro_points), ==,
+ smartlist_len(desc2->encrypted_data.intro_points));
+ for (int i=0; i < smartlist_len(desc1->encrypted_data.intro_points); i++) {
+ hs_desc_intro_point_t *ip1 = smartlist_get(desc1->encrypted_data
+ .intro_points, i),
+ *ip2 = smartlist_get(desc2->encrypted_data
+ .intro_points, i);
+ tt_assert(tor_cert_eq(ip1->auth_key_cert, ip2->auth_key_cert));
+ if (ip1->legacy.key) {
+ tt_int_op(crypto_pk_cmp_keys(ip1->legacy.key, ip2->legacy.key),
+ OP_EQ, 0);
+ } else {
+ tt_mem_op(&ip1->enc_key, OP_EQ, &ip2->enc_key, CURVE25519_PUBKEY_LEN);
+ }
+
+ tt_int_op(smartlist_len(ip1->link_specifiers), ==,
+ smartlist_len(ip2->link_specifiers));
+ for (int j = 0; j < smartlist_len(ip1->link_specifiers); j++) {
+ hs_desc_link_specifier_t *ls1 = smartlist_get(ip1->link_specifiers, j),
+ *ls2 = smartlist_get(ip2->link_specifiers, j);
+ tt_int_op(ls1->type, ==, ls2->type);
+ switch (ls1->type) {
+ case LS_IPV4:
+ case LS_IPV6:
+ {
+ addr1 = tor_addr_to_str_dup(&ls1->u.ap.addr);
+ addr2 = tor_addr_to_str_dup(&ls2->u.ap.addr);
+ tt_str_op(addr1, OP_EQ, addr2);
+ tor_free(addr1);
+ tor_free(addr2);
+ tt_int_op(ls1->u.ap.port, ==, ls2->u.ap.port);
+ }
+ break;
+ case LS_LEGACY_ID:
+ tt_mem_op(ls1->u.legacy_id, OP_EQ, ls2->u.legacy_id,
+ sizeof(ls1->u.legacy_id));
+ break;
+ default:
+ /* Unknown type, caught it and print its value. */
+ tt_int_op(ls1->type, OP_EQ, -1);
+ }
+ }
+ }
+ }
+
+ done:
+ tor_free(addr1);
+ tor_free(addr2);
+}
+
diff --git a/src/test/hs_test_helpers.h b/src/test/hs_test_helpers.h
new file mode 100644
index 0000000000..b1b0490f05
--- /dev/null
+++ b/src/test/hs_test_helpers.h
@@ -0,0 +1,25 @@
+/* Copyright (c) 2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_HS_TEST_HELPERS_H
+#define TOR_HS_TEST_HELPERS_H
+
+#include "ed25519_cert.h"
+#include "hs_descriptor.h"
+
+/* Set of functions to help build and test descriptors. */
+hs_desc_intro_point_t *hs_helper_build_intro_point(
+ const ed25519_keypair_t *signing_kp, time_t now,
+ const char *addr, int legacy);
+hs_descriptor_t *hs_helper_build_hs_desc_no_ip(
+ const ed25519_keypair_t *signing_kp);
+hs_descriptor_t *hs_helper_build_hs_desc_with_ip(
+ const ed25519_keypair_t *signing_kp);
+void hs_helper_desc_equal(const hs_descriptor_t *desc1,
+ const hs_descriptor_t *desc2);
+void
+hs_helper_get_subcred_from_identity_keypair(ed25519_keypair_t *signing_kp,
+ uint8_t *subcred_out);
+
+#endif /* !defined(TOR_HS_TEST_HELPERS_H) */
+
diff --git a/src/test/include.am b/src/test/include.am
index 0ee3d1169f..2f6789c58d 100644
--- a/src/test/include.am
+++ b/src/test/include.am
@@ -5,10 +5,15 @@ TESTS_ENVIRONMENT = \
export PYTHON="$(PYTHON)"; \
export SHELL="$(SHELL)"; \
export abs_top_srcdir="$(abs_top_srcdir)"; \
+ export abs_top_builddir="$(abs_top_builddir)"; \
export builddir="$(builddir)"; \
- export TESTING_TOR_BINARY="$(TESTING_TOR_BINARY)";
+ export TESTING_TOR_BINARY="$(TESTING_TOR_BINARY)"; \
+ export CARGO="$(CARGO)"; \
+ export CARGO_ONLINE="$(CARGO_ONLINE)";
-TESTSCRIPTS = src/test/test_zero_length_keys.sh \
+TESTSCRIPTS = \
+ src/test/fuzz_static_testcases.sh \
+ src/test/test_zero_length_keys.sh \
src/test/test_workqueue_cancel.sh \
src/test/test_workqueue_efd.sh \
src/test/test_workqueue_efd2.sh \
@@ -17,23 +22,32 @@ TESTSCRIPTS = src/test/test_zero_length_keys.sh \
src/test/test_workqueue_socketpair.sh \
src/test/test_switch_id.sh
+if USE_RUST
+TESTSCRIPTS += \
+ src/test/test_rust.sh
+endif
+
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 \
src/test/test_workqueue \
src/test/test_keygen.sh \
+ src/test/test_key_expiration.sh \
src/test/test-timers \
$(TESTSCRIPTS)
# These flavors are run using automake's test-driver and test-network.sh
-TEST_CHUTNEY_FLAVORS = basic-min bridges-min hs-min single-onion
+TEST_CHUTNEY_FLAVORS = basic-min bridges-min hs-v2-min hs-v3-min \
+ single-onion-v23
# only run if we can ping6 ::1 (localhost)
-TEST_CHUTNEY_FLAVORS_IPV6 = bridges+ipv6-min ipv6-exit-min hs-ipv6 \
- single-onion-ipv6
+# IPv6-only v3 single onion services don't work yet, so we don't test the
+# single-onion-v23-ipv6-md flavor
+TEST_CHUTNEY_FLAVORS_IPV6 = bridges+ipv6-min ipv6-exit-min hs-v23-ipv6-md \
+ single-onion-ipv6-md
# only run if we can find a stable (or simply another) version of tor
-TEST_CHUTNEY_FLAVORS_MIXED = mixed
+TEST_CHUTNEY_FLAVORS_MIXED = mixed+hs-v2
### This is a lovely feature, but it requires automake >= 1.12, and Tor
### doesn't require that yet.
@@ -67,6 +81,7 @@ src_test_AM_CPPFLAGS = -DSHARE_DATADIR="\"$(datadir)\"" \
src_test_test_SOURCES = \
src/test/log_test_helpers.c \
+ src/test/hs_test_helpers.c \
src/test/rend_test_helpers.c \
src/test/test.c \
src/test/test_accounting.c \
@@ -77,17 +92,24 @@ src_test_test_SOURCES = \
src/test/test_cell_formats.c \
src/test/test_cell_queue.c \
src/test/test_channel.c \
+ src/test/test_channelpadding.c \
src/test/test_channeltls.c \
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_dos.c \
src/test/test_data.c \
src/test/test_dir.c \
@@ -98,7 +120,16 @@ src_test_test_SOURCES = \
src/test/test_guardfraction.c \
src/test/test_extorport.c \
src/test/test_hs.c \
+ src/test/test_hs_common.c \
+ src/test/test_hs_config.c \
+ src/test/test_hs_cell.c \
+ src/test/test_hs_ntor.c \
+ src/test/test_hs_service.c \
+ src/test/test_hs_client.c \
+ src/test/test_hs_intropoint.c \
src/test/test_handles.c \
+ src/test/test_hs_cache.c \
+ src/test/test_hs_descriptor.c \
src/test/test_introduce.c \
src/test/test_keypin.c \
src/test/test_link_handshake.c \
@@ -110,6 +141,8 @@ src_test_test_SOURCES = \
src/test/test_options.c \
src/test/test_policy.c \
src/test/test_procmon.c \
+ src/test/test_proto_http.c \
+ src/test/test_proto_misc.c \
src/test/test_protover.c \
src/test/test_pt.c \
src/test/test_pubsub.c \
@@ -117,13 +150,16 @@ src_test_test_SOURCES = \
src/test/test_relaycell.c \
src/test/test_rendcache.c \
src/test/test_replay.c \
+ src/test/test_router.c \
src/test/test_routerkeys.c \
src/test/test_routerlist.c \
src/test/test_routerset.c \
+ src/test/test_rust.c \
src/test/test_scheduler.c \
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 \
@@ -132,6 +168,7 @@ src_test_test_SOURCES = \
src/test/test_helpers.c \
src/test/test_dns.c \
src/test/testing_common.c \
+ src/test/testing_rsakeys.c \
src/ext/tinytest.c
src_test_test_slow_SOURCES = \
@@ -139,6 +176,7 @@ src_test_test_slow_SOURCES = \
src/test/test_crypto_slow.c \
src/test/test_util_slow.c \
src/test/testing_common.c \
+ src/test/testing_rsakeys.c \
src/ext/tinytest.c
src_test_test_memwipe_SOURCES = \
@@ -167,7 +205,10 @@ 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@
+ $(rust_ldadd) \
+ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \
+ @TOR_LIB_WS32@ @TOR_LIB_USERENV@ \
+ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
src_test_test_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \
@TOR_LDFLAGS_libevent@
@@ -179,9 +220,12 @@ 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 \
+ $(rust_ldadd) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
- @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ \
- @TOR_SYSTEMD_LIBS@
+ @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
+ @CURVE25519_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)
@@ -202,9 +246,12 @@ 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 \
+ $(rust_ldadd) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
- @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ \
- @TOR_SYSTEMD_LIBS@
+ @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
+ @CURVE25519_LIBS@ \
+ @TOR_SYSTEMD_LIBS@ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
src_test_test_workqueue_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \
@TOR_LDFLAGS_libevent@
@@ -213,8 +260,12 @@ 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 \
+ $(rust_ldadd) \
@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@ @TOR_LIB_USERENV@ \
+ @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)
@@ -223,53 +274,82 @@ src_test_test_timers_LDADD = \
src/common/libor-ctime-testing.a \
src/common/libor-event-testing.a \
src/common/libor-crypto-testing.a $(LIBKECCAK_TINY) $(LIBDONNA) \
+ $(rust_ldadd) \
@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@ @TOR_LIB_USERENV@ \
+ @CURVE25519_LIBS@ \
+ @TOR_LZMA_LIBS@
src_test_test_timers_LDFLAGS = $(src_test_test_LDFLAGS)
noinst_HEADERS+= \
src/test/fakechans.h \
+ src/test/hs_test_helpers.h \
src/test/log_test_helpers.h \
src/test/rend_test_helpers.h \
src/test/test.h \
src/test/test_helpers.h \
src/test/test_dir_common.h \
+ src/test/test_connection.h \
src/test/test_descriptors.inc \
src/test/example_extrainfo.inc \
src/test/failing_routerdescs.inc \
src/test/ed25519_vectors.inc \
src/test/test_descriptors.inc \
+ src/test/test_hs_descriptor.inc \
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 \
+ $(rust_ldadd) \
@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@ @TOR_LIB_USERENV@ \
+ @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 \
+ $(rust_ldadd) \
@TOR_LIB_MATH@ \
- @TOR_LIB_WS32@ @TOR_LIB_GDI@
+ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@
src_test_test_bt_cl_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
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/hs_build_address.py \
+ src/test/hs_indexes.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_key_expiration.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_rust.sh \
src/test/test_switch_id.sh \
src/test/test_workqueue_cancel.sh \
src/test/test_workqueue_efd.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..70c584eb37 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) \
@@ -101,5 +101,5 @@ void mock_dump_saved_logs(void);
assert_log_predicate(!mock_saved_log_has_entry(), \
"expected log to not contain entries");
-#endif
+#endif /* !defined(TOR_LOG_TEST_HELPERS_H) */
diff --git a/src/test/ntor_ref.py b/src/test/ntor_ref.py
index 5ec117f2bd..51f218f512 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..095bfecf21 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"
@@ -71,3 +71,19 @@ create_descriptor(rend_service_descriptor_t **generated, char **service_id,
crypto_pk_free(pk2);
}
+rend_data_t *
+mock_rend_data(const char *onion_address)
+{
+ rend_data_v2_t *v2_data = tor_malloc_zero(sizeof(*v2_data));
+ rend_data_t *rend_query = &v2_data->base_;
+ rend_query->version = 2;
+
+ strlcpy(v2_data->onion_address, onion_address,
+ sizeof(v2_data->onion_address));
+ v2_data->auth_type = REND_NO_AUTH;
+ rend_query->hsdirs_fp = smartlist_new();
+ smartlist_add(rend_query->hsdirs_fp, tor_memdup("aaaaaaaaaaaaaaaaaaaaaaaa",
+ DIGEST_LEN));
+ return rend_query;
+}
+
diff --git a/src/test/rend_test_helpers.h b/src/test/rend_test_helpers.h
index 180a4e8fde..abf4324988 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"
@@ -10,6 +10,7 @@ void generate_desc(int time_diff, rend_encoded_v2_service_descriptor_t **desc,
char **service_id, int intro_points);
void create_descriptor(rend_service_descriptor_t **generated,
char **service_id, int intro_points);
+rend_data_t *mock_rend_data(const char *onion_address);
-#endif
+#endif /* !defined(TOR_REND_TEST_HELPERS_H) */
diff --git a/src/test/test-child.c b/src/test/test-child.c
index fdf3ccec0a..f78a829107 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"
@@ -8,7 +8,7 @@
#include <windows.h>
#else
#include <unistd.h>
-#endif
+#endif /* defined(_WIN32) */
#include <string.h>
#ifdef _WIN32
diff --git a/src/test/test-memwipe.c b/src/test/test-memwipe.c
index fd6457416a..484f13dd05 100644
--- a/src/test/test-memwipe.c
+++ b/src/test/test-memwipe.c
@@ -36,7 +36,7 @@ const char *s = NULL;
sum += (unsigned char)buf[i]; \
}
-#ifdef __OpenBSD__
+#ifdef OpenBSD
/* Disable some of OpenBSD's malloc protections for this test. This helps
* us do bad things, such as access freed buffers, without crashing. */
const char *malloc_options="sufjj";
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 6330eb9b93..a935ac36a6 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 */
/**
@@ -20,7 +20,7 @@
#include <direct.h>
#else
#include <dirent.h>
-#endif
+#endif /* defined(_WIN32) */
#include <math.h>
@@ -38,13 +38,13 @@
#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"
@@ -136,7 +136,8 @@ test_bad_onion_handshake(void *arg)
/* Server: Case 1: the encrypted data is degenerate. */
memset(junk_buf, 0, sizeof(junk_buf));
- crypto_pk_public_hybrid_encrypt(pk, junk_buf2, TAP_ONIONSKIN_CHALLENGE_LEN,
+ crypto_pk_obsolete_public_hybrid_encrypt(pk,
+ junk_buf2, TAP_ONIONSKIN_CHALLENGE_LEN,
junk_buf, DH_KEY_LEN, PK_PKCS1_OAEP_PADDING, 1);
tt_int_op(-1, OP_EQ,
onion_skin_TAP_server_handshake(junk_buf2, pk, NULL,
@@ -402,11 +403,11 @@ test_circuit_timeout(void *arg)
} while (fabs(circuit_build_times_cdf(&initial, timeout0) -
circuit_build_times_cdf(&initial, timeout1)) > 0.02);
- tt_assert(estimate.total_build_times <= CBT_NCIRCUITS_TO_OBSERVE);
+ tt_int_op(estimate.total_build_times, OP_LE, CBT_NCIRCUITS_TO_OBSERVE);
circuit_build_times_update_state(&estimate, state);
circuit_build_times_free_timeouts(&final);
- tt_assert(circuit_build_times_parse_state(&final, state) == 0);
+ tt_int_op(circuit_build_times_parse_state(&final, state), OP_EQ, 0);
circuit_build_times_update_alpha(&final);
timeout2 = circuit_build_times_calculate_timeout(&final,
@@ -484,7 +485,7 @@ test_circuit_timeout(void *arg)
}
}
- tt_assert(estimate.liveness.after_firsthop_idx == 0);
+ tt_int_op(estimate.liveness.after_firsthop_idx, OP_EQ, 0);
tt_assert(final.liveness.after_firsthop_idx ==
CBT_DEFAULT_MAX_RECENT_TIMEOUT_COUNT-1);
@@ -527,25 +528,8 @@ test_rend_fns(void *arg)
size_t intro_points_size;
size_t encoded_size;
int i;
- char address1[] = "fooaddress.onion";
- char address2[] = "aaaaaaaaaaaaaaaa.onion";
- char address3[] = "fooaddress.exit";
- char address4[] = "www.torproject.org";
- char address5[] = "foo.abcdefghijklmnop.onion";
- char address6[] = "foo.bar.abcdefghijklmnop.onion";
- char address7[] = ".abcdefghijklmnop.onion";
(void)arg;
- tt_assert(BAD_HOSTNAME == parse_extended_hostname(address1));
- tt_assert(ONION_HOSTNAME == parse_extended_hostname(address2));
- tt_str_op(address2,OP_EQ, "aaaaaaaaaaaaaaaa");
- tt_assert(EXIT_HOSTNAME == parse_extended_hostname(address3));
- tt_assert(NORMAL_HOSTNAME == parse_extended_hostname(address4));
- tt_assert(ONION_HOSTNAME == parse_extended_hostname(address5));
- tt_str_op(address5,OP_EQ, "abcdefghijklmnop");
- tt_assert(ONION_HOSTNAME == parse_extended_hostname(address6));
- tt_str_op(address6,OP_EQ, "abcdefghijklmnop");
- tt_assert(BAD_HOSTNAME == parse_extended_hostname(address7));
/* Initialize the service cache. */
rend_cache_init();
@@ -581,20 +565,21 @@ test_rend_fns(void *arg)
intro->intro_key = crypto_pk_dup_key(pk2);
smartlist_add(generated->intro_nodes, intro);
}
- tt_assert(rend_encode_v2_descriptors(descs, generated, now, 0,
- REND_NO_AUTH, NULL, NULL) > 0);
- tt_assert(rend_compute_v2_desc_id(computed_desc_id, service_id_base32,
- NULL, now, 0) == 0);
+ int rv = rend_encode_v2_descriptors(descs, generated, now, 0,
+ REND_NO_AUTH, NULL, NULL);
+ tt_int_op(rv, OP_GT, 0);
+ rv = rend_compute_v2_desc_id(computed_desc_id, service_id_base32, NULL,
+ now, 0);
+ tt_int_op(rv, OP_EQ, 0);
tt_mem_op(((rend_encoded_v2_service_descriptor_t *)
smartlist_get(descs, 0))->desc_id, OP_EQ,
computed_desc_id, DIGEST_LEN);
- tt_assert(rend_parse_v2_service_descriptor(&parsed, parsed_desc_id,
- &intro_points_encrypted,
- &intro_points_size,
- &encoded_size,
- &next_desc,
- ((rend_encoded_v2_service_descriptor_t *)
- smartlist_get(descs, 0))->desc_str, 1) == 0);
+ rv = rend_parse_v2_service_descriptor(&parsed, parsed_desc_id,
+ &intro_points_encrypted, &intro_points_size, &encoded_size,
+ &next_desc,
+ ((rend_encoded_v2_service_descriptor_t *)smartlist_get(descs, 0))
+ ->desc_str, 1);
+ tt_int_op(rv, OP_EQ, 0);
tt_assert(parsed);
tt_mem_op(((rend_encoded_v2_service_descriptor_t *)
smartlist_get(descs, 0))->desc_id,OP_EQ, parsed_desc_id, DIGEST_LEN);
@@ -796,7 +781,7 @@ test_geoip(void *arg)
/* Start testing bridge statistics by making sure that we don't output
* bridge stats without initializing them. */
s = geoip_format_bridge_stats(now + 86400);
- tt_assert(!s);
+ tt_ptr_op(s, OP_EQ, NULL);
/* Initialize stats and generate the bridge-stats history string out of
* the connecting clients added above. */
@@ -810,7 +795,7 @@ test_geoip(void *arg)
* string anymore. */
geoip_bridge_stats_term();
s = geoip_format_bridge_stats(now + 86400);
- tt_assert(!s);
+ tt_ptr_op(s, OP_EQ, NULL);
/* Stop being a bridge and start being a directory mirror that gathers
* directory request statistics. */
@@ -824,7 +809,7 @@ test_geoip(void *arg)
SET_TEST_ADDRESS(100);
geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, NULL, now);
s = geoip_format_dirreq_stats(now + 86400);
- tt_assert(!s);
+ tt_ptr_op(s, OP_EQ, NULL);
/* Initialize stats, note one connecting client, and generate the
* dirreq-stats history string. */
@@ -841,7 +826,7 @@ test_geoip(void *arg)
SET_TEST_ADDRESS(101);
geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, NULL, now);
s = geoip_format_dirreq_stats(now + 86400);
- tt_assert(!s);
+ tt_ptr_op(s, OP_EQ, NULL);
/* Re-start stats, add a connecting client, reset stats, and make sure
* that we get an all empty history string. */
@@ -877,7 +862,7 @@ test_geoip(void *arg)
SET_TEST_ADDRESS(100);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL, now);
s = geoip_format_entry_stats(now + 86400);
- tt_assert(!s);
+ tt_ptr_op(s, OP_EQ, NULL);
/* Initialize stats, note one connecting client, and generate the
* entry-stats history string. */
@@ -894,7 +879,7 @@ test_geoip(void *arg)
SET_TEST_ADDRESS(101);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL, now);
s = geoip_format_entry_stats(now + 86400);
- tt_assert(!s);
+ tt_ptr_op(s, OP_EQ, NULL);
/* Re-start stats, add a connecting client, reset stats, and make sure
* that we get an all empty history string. */
@@ -1023,7 +1008,7 @@ test_stats(void *arg)
rep_hist_note_exit_stream_opened(80);
rep_hist_note_exit_bytes(80, 100, 10000);
s = rep_hist_format_exit_stats(now + 86400);
- tt_assert(!s);
+ tt_ptr_op(s, OP_EQ, NULL);
/* Initialize stats, note some streams and bytes, and generate history
* string. */
@@ -1061,7 +1046,7 @@ test_stats(void *arg)
rep_hist_exit_stats_term();
rep_hist_note_exit_bytes(80, 100, 10000);
s = rep_hist_format_exit_stats(now + 86400);
- tt_assert(!s);
+ tt_ptr_op(s, OP_EQ, NULL);
/* Re-start stats, add some bytes, reset stats, and see what history we
* get when observing no streams or bytes at all. */
@@ -1080,7 +1065,7 @@ test_stats(void *arg)
* conn stats without initializing them. */
rep_hist_note_or_conn_bytes(1, 20, 400, now);
s = rep_hist_format_conn_stats(now + 86400);
- tt_assert(!s);
+ tt_ptr_op(s, OP_EQ, NULL);
/* Initialize stats, note bytes, and generate history string. */
rep_hist_conn_stats_init(now);
@@ -1097,7 +1082,7 @@ test_stats(void *arg)
rep_hist_conn_stats_term();
rep_hist_note_or_conn_bytes(2, 400000, 30000, now + 15);
s = rep_hist_format_conn_stats(now + 86400);
- tt_assert(!s);
+ tt_ptr_op(s, OP_EQ, NULL);
/* Re-start stats, add some bytes, reset stats, and see what history we
* get when observing no bytes at all. */
@@ -1115,7 +1100,7 @@ test_stats(void *arg)
* stats without initializing them. */
rep_hist_add_buffer_stats(2.0, 2.0, 20);
s = rep_hist_format_buffer_stats(now + 86400);
- tt_assert(!s);
+ tt_ptr_op(s, OP_EQ, NULL);
/* Initialize stats, add statistics for a single circuit, and generate
* the history string. */
@@ -1150,7 +1135,7 @@ test_stats(void *arg)
rep_hist_buffer_stats_term();
rep_hist_add_buffer_stats(2.0, 2.0, 20);
s = rep_hist_format_buffer_stats(now + 86400);
- tt_assert(!s);
+ tt_ptr_op(s, OP_EQ, NULL);
/* Re-start stats, add statistics for one circuit, reset stats, and make
* sure that the history has all zeros. */
@@ -1199,17 +1184,24 @@ struct testgroup_t testgroups[] = {
{ "cellfmt/", cell_format_tests },
{ "cellqueue/", cell_queue_tests },
{ "channel/", channel_tests },
+ { "channelpadding/", channelpadding_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 },
{ "dos/", dos_tests },
{ "dir/", dir_tests },
{ "dir_handle_get/", dir_handle_get_tests },
@@ -1218,7 +1210,16 @@ struct testgroup_t testgroups[] = {
{ "entrynodes/", entrynodes_tests },
{ "guardfraction/", guardfraction_tests },
{ "extorport/", extorport_tests },
- { "hs/", hs_tests },
+ { "legacy_hs/", hs_tests },
+ { "hs_cache/", hs_cache },
+ { "hs_cell/", hs_cell_tests },
+ { "hs_common/", hs_common_tests },
+ { "hs_config/", hs_config_tests },
+ { "hs_descriptor/", hs_descriptor },
+ { "hs_ntor/", hs_ntor_tests },
+ { "hs_service/", hs_service_tests },
+ { "hs_client/", hs_client_tests },
+ { "hs_intropoint/", hs_intropoint_tests },
{ "introduce/", introduce_tests },
{ "keypin/", keypin_tests },
{ "link-handshake/", link_handshake_tests },
@@ -1228,19 +1229,24 @@ struct testgroup_t testgroups[] = {
{ "options/", options_tests },
{ "policy/" , policy_tests },
{ "procmon/", procmon_tests },
+ { "proto/http/", proto_http_tests },
+ { "proto/misc/", proto_misc_tests },
{ "protover/", protover_tests },
{ "pt/", pt_tests },
{ "relay/" , relay_tests },
{ "relaycell/", relaycell_tests },
{ "rend_cache/", rend_cache_tests },
{ "replaycache/", replaycache_tests },
+ { "router/", router_tests },
{ "routerkeys/", routerkeys_tests },
{ "routerlist/", routerlist_tests },
{ "routerset/" , routerset_tests },
+ { "rust/", rust_tests },
{ "scheduler/", scheduler_tests },
{ "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 028082386e..3c12d2b673 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
@@ -45,8 +45,8 @@
* you're doing. */
#define tt_double_eq(a,b) \
STMT_BEGIN \
- tt_double_op((a), >=, (b)); \
- tt_double_op((a), <=, (b)); \
+ tt_double_op((a), OP_GE, (b)); \
+ tt_double_op((a), OP_LE, (b)); \
STMT_END
#ifdef _MSC_VER
@@ -55,7 +55,7 @@
#else
#define U64_PRINTF_TYPE unsigned long long
#define I64_PRINTF_TYPE long long
-#endif
+#endif /* defined(_MSC_VER) */
#define tt_size_op(a,op,b) \
tt_assert_test_fmt_type(a,b,#a" "#op" "#b,size_t,(val1_ op val2_), \
@@ -75,6 +75,8 @@
const char *get_fname(const char *name);
const char *get_fname_rnd(const char *name);
struct crypto_pk_t *pk_generate(int idx);
+void init_pregenerated_keys(void);
+void free_pregenerated_keys(void);
#define US2_CONCAT_2__(a, b) a ## __ ## b
#define US_CONCAT_2__(a, b) a ## _ ## b
@@ -180,17 +182,24 @@ extern struct testcase_t buffer_tests[];
extern struct testcase_t cell_format_tests[];
extern struct testcase_t cell_queue_tests[];
extern struct testcase_t channel_tests[];
+extern struct testcase_t channelpadding_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 dos_tests[];
extern struct testcase_t dir_tests[];
extern struct testcase_t dir_handle_get_tests[];
@@ -199,6 +208,15 @@ extern struct testcase_t entrynodes_tests[];
extern struct testcase_t guardfraction_tests[];
extern struct testcase_t extorport_tests[];
extern struct testcase_t hs_tests[];
+extern struct testcase_t hs_cache[];
+extern struct testcase_t hs_cell_tests[];
+extern struct testcase_t hs_common_tests[];
+extern struct testcase_t hs_config_tests[];
+extern struct testcase_t hs_descriptor[];
+extern struct testcase_t hs_ntor_tests[];
+extern struct testcase_t hs_service_tests[];
+extern struct testcase_t hs_client_tests[];
+extern struct testcase_t hs_intropoint_tests[];
extern struct testcase_t introduce_tests[];
extern struct testcase_t keypin_tests[];
extern struct testcase_t link_handshake_tests[];
@@ -210,6 +228,8 @@ extern struct testcase_t oos_tests[];
extern struct testcase_t options_tests[];
extern struct testcase_t policy_tests[];
extern struct testcase_t procmon_tests[];
+extern struct testcase_t proto_http_tests[];
+extern struct testcase_t proto_misc_tests[];
extern struct testcase_t protover_tests[];
extern struct testcase_t pubsub_tests[];
extern struct testcase_t pt_tests[];
@@ -221,7 +241,9 @@ extern struct testcase_t router_tests[];
extern struct testcase_t routerkeys_tests[];
extern struct testcase_t routerlist_tests[];
extern struct testcase_t routerset_tests[];
+extern struct testcase_t rust_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[];
@@ -251,5 +273,5 @@ extern const char AUTHORITY_SIGNKEY_3[];
extern const char AUTHORITY_SIGNKEY_C_DIGEST[];
extern const char AUTHORITY_SIGNKEY_C_DIGEST256[];
-#endif
+#endif /* !defined(TOR_TEST_H) */
diff --git a/src/test/test_addr.c b/src/test/test_addr.c
index be440a0925..e1a40b7e60 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
@@ -9,6 +9,24 @@
#include "test.h"
#include "addressmap.h"
+/** Mocking replacement: only handles localhost. */
+static int
+mock_tor_addr_lookup(const char *name, uint16_t family, tor_addr_t *addr_out)
+{
+ if (!strcmp(name, "localhost")) {
+ if (family == AF_INET || family == AF_UNSPEC) {
+ tor_addr_from_ipv4h(addr_out, 0x7f000001);
+ return 0;
+ } else if (family == AF_INET6) {
+ char bytes[16] = { 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1 };
+ tor_addr_from_ipv6_bytes(addr_out, bytes);
+ return 0;
+ }
+ }
+ return -1;
+}
+
static void
test_addr_basic(void *arg)
{
@@ -29,6 +47,9 @@ test_addr_basic(void *arg)
tt_int_op(u32,OP_EQ, 0x04030201u);
tt_int_op(u16,OP_EQ, 99);
tor_free(cp);
+
+ MOCK(tor_addr_lookup, mock_tor_addr_lookup);
+
tt_assert(!addr_port_lookup(LOG_WARN, "nonexistent.address:4040",
&cp, NULL, &u16));
tt_str_op(cp,OP_EQ, "nonexistent.address");
@@ -36,8 +57,8 @@ test_addr_basic(void *arg)
tor_free(cp);
tt_assert(!addr_port_lookup(LOG_WARN, "localhost:9999", &cp, &u32, &u16));
tt_str_op(cp,OP_EQ, "localhost");
- tt_int_op(u32,OP_EQ, 0x7f000001u);
tt_int_op(u16,OP_EQ, 9999);
+ tt_int_op(u32,OP_EQ, 0x7f000001u);
tor_free(cp);
u32 = 3;
tt_assert(!addr_port_lookup(LOG_WARN, "localhost", NULL, &u32, &u16));
@@ -75,6 +96,7 @@ test_addr_basic(void *arg)
}
done:
+ UNMOCK(tor_addr_lookup);
tor_free(cp);
}
@@ -429,10 +451,10 @@ test_addr_ip6_helpers(void *arg)
"::ffff:6.0.0.0"); /* XXXX wrong. */
tor_addr_parse_mask_ports("[::ffff:2.3.4.5]", 0, &t1, NULL, NULL, NULL);
tor_addr_parse_mask_ports("2.3.4.5", 0, &t2, NULL, NULL, NULL);
- tt_assert(tor_addr_compare(&t1, &t2, CMP_SEMANTIC) == 0);
+ tt_int_op(tor_addr_compare(&t1, &t2, CMP_SEMANTIC), OP_EQ, 0);
tor_addr_parse_mask_ports("[::ffff:2.3.4.4]", 0, &t1, NULL, NULL, NULL);
tor_addr_parse_mask_ports("2.3.4.5", 0, &t2, NULL, NULL, NULL);
- tt_assert(tor_addr_compare(&t1, &t2, CMP_SEMANTIC) < 0);
+ tt_int_op(tor_addr_compare(&t1, &t2, CMP_SEMANTIC), OP_LT, 0);
/* test compare_masked */
test_addr_compare_masked("ffff::", OP_EQ, "ffff::0", 128);
@@ -615,7 +637,7 @@ test_addr_ip6_helpers(void *arg)
/* Try some long addresses. */
r=tor_addr_parse_mask_ports("[ffff:1111:1111:1111:1111:1111:1111:1111]",
0, &t1, NULL, NULL, NULL);
- tt_assert(r == AF_INET6);
+ tt_int_op(r, OP_EQ, AF_INET6);
r=tor_addr_parse_mask_ports("[ffff:1111:1111:1111:1111:1111:1111:11111]",
0, &t1, NULL, NULL, NULL);
tt_int_op(r, OP_EQ, -1);
@@ -664,38 +686,38 @@ test_addr_ip6_helpers(void *arg)
tt_int_op(r, OP_EQ, -1);
r=tor_addr_parse_mask_ports("*6",0,&t1, &mask, NULL, NULL);
tt_int_op(r, OP_EQ, -1);
- tt_assert(r == -1);
+ tt_int_op(r, OP_EQ, -1);
/* Try a mask with a wildcard. */
r=tor_addr_parse_mask_ports("*/16",0,&t1, &mask, NULL, NULL);
- tt_assert(r == -1);
+ tt_int_op(r, OP_EQ, -1);
r=tor_addr_parse_mask_ports("*4/16",TAPMP_EXTENDED_STAR,
&t1, &mask, NULL, NULL);
- tt_assert(r == -1);
+ tt_int_op(r, OP_EQ, -1);
r=tor_addr_parse_mask_ports("*6/30",TAPMP_EXTENDED_STAR,
&t1, &mask, NULL, NULL);
- tt_assert(r == -1);
+ tt_int_op(r, OP_EQ, -1);
/* Basic mask tests*/
r=tor_addr_parse_mask_ports("1.1.2.2/31",0,&t1, &mask, NULL, NULL);
- tt_assert(r == AF_INET);
+ tt_int_op(r, OP_EQ, AF_INET);
tt_int_op(mask,OP_EQ,31);
tt_int_op(tor_addr_family(&t1),OP_EQ,AF_INET);
tt_int_op(tor_addr_to_ipv4h(&t1),OP_EQ,0x01010202);
r=tor_addr_parse_mask_ports("3.4.16.032:1-2",0,&t1, &mask, &port1, &port2);
- tt_assert(r == AF_INET);
+ tt_int_op(r, OP_EQ, AF_INET);
tt_int_op(mask,OP_EQ,32);
tt_int_op(tor_addr_family(&t1),OP_EQ,AF_INET);
tt_int_op(tor_addr_to_ipv4h(&t1),OP_EQ,0x03041020);
- tt_assert(port1 == 1);
- tt_assert(port2 == 2);
+ tt_uint_op(port1, OP_EQ, 1);
+ tt_uint_op(port2, OP_EQ, 2);
r=tor_addr_parse_mask_ports("1.1.2.3/255.255.128.0",0,&t1, &mask,NULL,NULL);
- tt_assert(r == AF_INET);
+ tt_int_op(r, OP_EQ, AF_INET);
tt_int_op(mask,OP_EQ,17);
tt_int_op(tor_addr_family(&t1),OP_EQ,AF_INET);
tt_int_op(tor_addr_to_ipv4h(&t1),OP_EQ,0x01010203);
r=tor_addr_parse_mask_ports("[efef::]/112",0,&t1, &mask, &port1, &port2);
- tt_assert(r == AF_INET6);
- tt_assert(port1 == 1);
- tt_assert(port2 == 65535);
+ tt_int_op(r, OP_EQ, AF_INET6);
+ tt_uint_op(port1, OP_EQ, 1);
+ tt_uint_op(port2, OP_EQ, 65535);
/* Try regular wildcard behavior without TAPMP_EXTENDED_STAR */
r=tor_addr_parse_mask_ports("*:80-443",0,&t1,&mask,&port1,&port2);
tt_int_op(r,OP_EQ,AF_INET); /* Old users of this always get inet */
@@ -730,15 +752,17 @@ test_addr_ip6_helpers(void *arg)
tt_int_op(port2,OP_EQ,65535);
/* make sure inet address lengths >= max */
- tt_assert(INET_NTOA_BUF_LEN >= sizeof("255.255.255.255"));
- tt_assert(TOR_ADDR_BUF_LEN >=
- sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"));
+ tt_int_op(INET_NTOA_BUF_LEN, OP_GE, sizeof("255.255.255.255"));
+ tt_int_op(TOR_ADDR_BUF_LEN, OP_GE,
+ sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"));
tt_assert(sizeof(tor_addr_t) >= sizeof(struct in6_addr));
/* get interface addresses */
r = get_interface_address6(LOG_DEBUG, AF_INET, &t1);
+ tt_int_op(r, OP_LE, 0); // "it worked or it didn't"
i = get_interface_address6(LOG_DEBUG, AF_INET6, &t2);
+ tt_int_op(i, OP_LE, 0); // "it worked or it didn't"
TT_BLATHER(("v4 address: %s (family=%d)", fmt_addr(&t1),
tor_addr_family(&t1)));
@@ -988,7 +1012,7 @@ test_addr_sockaddr_to_str(void *arg)
s_un.sun_family = AF_UNIX;
strlcpy(s_un.sun_path, "/here/is/a/path", sizeof(s_un.sun_path));
CHECK(s_un, "unix:/here/is/a/path");
-#endif
+#endif /* defined(HAVE_SYS_UN_H) */
memset(&sin6,0,sizeof(sin6));
sin6.sin6_family = AF_INET6;
diff --git a/src/test/test_address.c b/src/test/test_address.c
index 0d142ad483..f36ff6998b 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
@@ -21,7 +21,7 @@
#include <sys/ioctl.h>
#endif
#include <net/if.h>
-#endif
+#endif /* defined(HAVE_IFCONF_TO_SMARTLIST) */
#include "or.h"
#include "address.h"
@@ -224,7 +224,7 @@ test_address_ifaddrs_to_smartlist(void *arg)
smartlist = ifaddrs_to_smartlist(ifa, AF_UNSPEC);
tt_assert(smartlist);
- tt_assert(smartlist_len(smartlist) == 3);
+ tt_int_op(smartlist_len(smartlist), OP_EQ, 3);
sockaddr_to_check = tor_malloc(sizeof(struct sockaddr_in6));
@@ -233,7 +233,7 @@ test_address_ifaddrs_to_smartlist(void *arg)
tor_addr_to_sockaddr(tor_addr,0,sockaddr_to_check,
sizeof(struct sockaddr_in));
- tt_int_op(addr_len,==,sizeof(struct sockaddr_in));
+ tt_int_op(addr_len,OP_EQ,sizeof(struct sockaddr_in));
tt_assert(sockaddr_in_are_equal((struct sockaddr_in *)sockaddr_to_check,
ipv4_sockaddr_local));
@@ -242,7 +242,7 @@ test_address_ifaddrs_to_smartlist(void *arg)
tor_addr_to_sockaddr(tor_addr,0,sockaddr_to_check,
sizeof(struct sockaddr_in));
- tt_int_op(addr_len,==,sizeof(struct sockaddr_in));
+ tt_int_op(addr_len,OP_EQ,sizeof(struct sockaddr_in));
tt_assert(sockaddr_in_are_equal((struct sockaddr_in *)sockaddr_to_check,
ipv4_sockaddr_remote));
@@ -251,7 +251,7 @@ test_address_ifaddrs_to_smartlist(void *arg)
tor_addr_to_sockaddr(tor_addr,0,sockaddr_to_check,
sizeof(struct sockaddr_in6));
- tt_int_op(addr_len,==,sizeof(struct sockaddr_in6));
+ tt_int_op(addr_len,OP_EQ,sizeof(struct sockaddr_in6));
tt_assert(sockaddr_in6_are_equal((struct sockaddr_in6*)sockaddr_to_check,
ipv6_sockaddr));
@@ -305,7 +305,7 @@ test_address_get_if_addrs_ifaddrs(void *arg)
return;
}
-#endif
+#endif /* defined(HAVE_IFADDRS_TO_SMARTLIST) */
#ifdef HAVE_IP_ADAPTER_TO_SMARTLIST
@@ -319,7 +319,7 @@ test_address_get_if_addrs_win32(void *arg)
results = get_interface_addresses_win32(LOG_ERR, AF_UNSPEC);
- tt_int_op(smartlist_len(results),>=,1);
+ tt_int_op(smartlist_len(results),OP_GE,1);
tt_assert(smartlist_contains_localhost_tor_addr(results));
tt_assert(!smartlist_contains_null_tor_addr(results));
@@ -384,7 +384,7 @@ test_address_ip_adapter_addresses_to_smartlist(void *arg)
result = ip_adapter_addresses_to_smartlist(addrs1);
tt_assert(result);
- tt_assert(smartlist_len(result) == 3);
+ tt_int_op(smartlist_len(result), OP_EQ, 3);
tor_addr = smartlist_get(result,0);
@@ -421,7 +421,7 @@ test_address_ip_adapter_addresses_to_smartlist(void *arg)
tor_free(sockaddr_to_check);
return;
}
-#endif
+#endif /* defined(HAVE_IP_ADAPTER_TO_SMARTLIST) */
#ifdef HAVE_IFCONF_TO_SMARTLIST
@@ -456,14 +456,14 @@ test_address_ifreq_to_smartlist(void *arg)
ifc->ifc_ifcu.ifcu_req = ifr;
results = ifreq_to_smartlist(ifc->ifc_buf,ifc->ifc_len);
- tt_int_op(smartlist_len(results),==,1);
+ tt_int_op(smartlist_len(results),OP_EQ,1);
tor_addr = smartlist_get(results, 0);
addr_len =
tor_addr_to_sockaddr(tor_addr,0,(struct sockaddr *)sockaddr_to_check,
sizeof(struct sockaddr_in));
- tt_int_op(addr_len,==,sizeof(struct sockaddr_in));
+ tt_int_op(addr_len,OP_EQ,sizeof(struct sockaddr_in));
tt_assert(sockaddr_in_are_equal(sockaddr,sockaddr_to_check));
ifr = tor_realloc(ifr,2*sizeof(struct ifreq));
@@ -479,14 +479,14 @@ test_address_ifreq_to_smartlist(void *arg)
smartlist_free(results);
results = ifreq_to_smartlist(ifc->ifc_buf,ifc->ifc_len);
- tt_int_op(smartlist_len(results),==,2);
+ tt_int_op(smartlist_len(results),OP_EQ,2);
tor_addr = smartlist_get(results, 0);
addr_len =
tor_addr_to_sockaddr(tor_addr,0,(struct sockaddr *)sockaddr_to_check,
sizeof(struct sockaddr_in));
- tt_int_op(addr_len,==,sizeof(struct sockaddr_in));
+ tt_int_op(addr_len,OP_EQ,sizeof(struct sockaddr_in));
tt_assert(sockaddr_in_are_equal(sockaddr,sockaddr_to_check));
tor_addr = smartlist_get(results, 1);
@@ -494,7 +494,7 @@ test_address_ifreq_to_smartlist(void *arg)
tor_addr_to_sockaddr(tor_addr,0,(struct sockaddr *)sockaddr_to_check,
sizeof(struct sockaddr_in));
- tt_int_op(addr_len,==,sizeof(struct sockaddr_in));
+ tt_int_op(addr_len,OP_EQ,sizeof(struct sockaddr_in));
tt_assert(sockaddr_in_are_equal(sockaddr_eth1,sockaddr_to_check));
done:
@@ -543,7 +543,7 @@ test_address_get_if_addrs_ioctl(void *arg)
return;
}
-#endif
+#endif /* defined(HAVE_IFCONF_TO_SMARTLIST) */
#define FAKE_SOCKET_FD (42)
@@ -633,7 +633,7 @@ test_address_udp_socket_trick_whitebox(void *arg)
get_interface_address6_via_udp_socket_hack(LOG_DEBUG,
AF_INET, addr_from_hack);
- tt_int_op(hack_retval,==,0);
+ tt_int_op(hack_retval,OP_EQ,0);
tt_assert(tor_addr_eq_ipv4h(addr_from_hack, 0x1720f676));
/* Now, lets do an IPv6 case. */
@@ -648,7 +648,7 @@ test_address_udp_socket_trick_whitebox(void *arg)
get_interface_address6_via_udp_socket_hack(LOG_DEBUG,
AF_INET6, addr_from_hack);
- tt_int_op(hack_retval,==,0);
+ tt_int_op(hack_retval,OP_EQ,0);
tor_addr_to_sockaddr(addr_from_hack,0,(struct sockaddr *)ipv6_to_check,
sizeof(struct sockaddr_in6));
@@ -693,7 +693,7 @@ test_address_udp_socket_trick_blackbox(void *arg)
AF_INET,
&addr4_to_check);
- tt_int_op(retval,==,retval_reference);
+ tt_int_op(retval,OP_EQ,retval_reference);
tt_assert( (retval == -1 && retval_reference == -1) ||
(tor_addr_compare(&addr4,&addr4_to_check,CMP_EXACT) == 0) );
@@ -702,11 +702,11 @@ test_address_udp_socket_trick_blackbox(void *arg)
AF_INET6,
&addr6_to_check);
- tt_int_op(retval,==,retval_reference);
+ tt_int_op(retval,OP_EQ,retval_reference);
tt_assert( (retval == -1 && retval_reference == -1) ||
(tor_addr_compare(&addr6,&addr6_to_check,CMP_EXACT) == 0) );
-#else
+#else /* !(0) */
/* Both of the blackbox test cases fail horribly if:
* * The host has no external addreses.
* * There are multiple interfaces with either AF_INET or AF_INET6.
@@ -721,7 +721,7 @@ test_address_udp_socket_trick_blackbox(void *arg)
(void)addr6_to_check;
(void)addr6;
(void) retval_reference;
-#endif
+#endif /* 0 */
/* When family is neither AF_INET nor AF_INET6, we want _hack to
* fail and return -1.
@@ -730,7 +730,7 @@ test_address_udp_socket_trick_blackbox(void *arg)
retval = get_interface_address6_via_udp_socket_hack(LOG_DEBUG,
AF_INET+AF_INET6,&addr4);
- tt_assert(retval == -1);
+ tt_int_op(retval, OP_EQ, -1);
done:
return;
@@ -745,11 +745,11 @@ test_address_get_if_addrs_list_internal(void *arg)
results = get_interface_address_list(LOG_ERR, 1);
- tt_assert(results != NULL);
+ tt_ptr_op(results, OP_NE, NULL);
/* When the network is down, a system might not have any non-local
* non-multicast addresseses, not even internal ones.
* Unit tests shouldn't fail because of this. */
- tt_int_op(smartlist_len(results),>=,0);
+ tt_int_op(smartlist_len(results),OP_GE,0);
tt_assert(!smartlist_contains_localhost_tor_addr(results));
tt_assert(!smartlist_contains_multicast_tor_addr(results));
@@ -776,9 +776,9 @@ test_address_get_if_addrs_list_no_internal(void *arg)
results = get_interface_address_list(LOG_ERR, 0);
- tt_assert(results != NULL);
+ tt_ptr_op(results, OP_NE, NULL);
/* Work even on systems with only internal IPv4 addresses */
- tt_int_op(smartlist_len(results),>=,0);
+ tt_int_op(smartlist_len(results),OP_GE,0);
tt_assert(!smartlist_contains_localhost_tor_addr(results));
tt_assert(!smartlist_contains_multicast_tor_addr(results));
@@ -818,9 +818,9 @@ test_address_get_if_addrs6_list_internal(void *arg)
}
teardown_capture_of_logs();
- tt_assert(results != NULL);
+ tt_ptr_op(results, OP_NE, NULL);
/* Work even on systems without IPv6 interfaces */
- tt_int_op(smartlist_len(results),>=,0);
+ tt_int_op(smartlist_len(results),OP_GE,0);
tt_assert(!smartlist_contains_localhost_tor_addr(results));
tt_assert(!smartlist_contains_multicast_tor_addr(results));
@@ -861,9 +861,9 @@ test_address_get_if_addrs6_list_no_internal(void *arg)
}
teardown_capture_of_logs();
- tt_assert(results != NULL);
+ tt_ptr_op(results, OP_NE, NULL);
/* Work even on systems without IPv6 interfaces */
- tt_int_op(smartlist_len(results),>=,0);
+ tt_int_op(smartlist_len(results),OP_GE,0);
tt_assert(!smartlist_contains_localhost_tor_addr(results));
tt_assert(!smartlist_contains_multicast_tor_addr(results));
@@ -927,18 +927,18 @@ test_address_get_if_addrs_internal_fail(void *arg)
mock_get_interface_address6_via_udp_socket_hack_fail);
results1 = get_interface_address6_list(LOG_ERR, AF_INET6, 1);
- tt_assert(results1 != NULL);
- tt_int_op(smartlist_len(results1),==,0);
+ tt_ptr_op(results1, OP_NE, NULL);
+ tt_int_op(smartlist_len(results1),OP_EQ,0);
results2 = get_interface_address_list(LOG_ERR, 1);
- tt_assert(results2 != NULL);
- tt_int_op(smartlist_len(results2),==,0);
+ tt_ptr_op(results2, OP_NE, NULL);
+ tt_int_op(smartlist_len(results2),OP_EQ,0);
rv = get_interface_address6(LOG_ERR, AF_INET6, &ipv6_addr);
- tt_assert(rv == -1);
+ tt_int_op(rv, OP_EQ, -1);
rv = get_interface_address(LOG_ERR, &ipv4h_addr);
- tt_assert(rv == -1);
+ tt_int_op(rv, OP_EQ, -1);
done:
UNMOCK(get_interface_addresses_raw);
@@ -961,12 +961,12 @@ test_address_get_if_addrs_no_internal_fail(void *arg)
mock_get_interface_address6_via_udp_socket_hack_fail);
results1 = get_interface_address6_list(LOG_ERR, AF_INET6, 0);
- tt_assert(results1 != NULL);
- tt_int_op(smartlist_len(results1),==,0);
+ tt_ptr_op(results1, OP_NE, NULL);
+ tt_int_op(smartlist_len(results1),OP_EQ,0);
results2 = get_interface_address_list(LOG_ERR, 0);
- tt_assert(results2 != NULL);
- tt_int_op(smartlist_len(results2),==,0);
+ tt_ptr_op(results2, OP_NE, NULL);
+ tt_int_op(smartlist_len(results2),OP_EQ,0);
done:
UNMOCK(get_interface_addresses_raw);
diff --git a/src/test/test_bt_cl.c b/src/test/test_bt_cl.c
index 95b4f48f11..b5c8d7cf9e 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"
@@ -19,14 +19,12 @@ static int crashtype = 0;
#ifdef __GNUC__
#define NOINLINE __attribute__((noinline))
-#define NORETURN __attribute__((noreturn))
#endif
int crash(int x) NOINLINE;
int oh_what(int x) NOINLINE;
int a_tangled_web(int x) NOINLINE;
int we_weave(int x) NOINLINE;
-static void abort_handler(int s) NORETURN;
#ifdef HAVE_CFLAG_WNULL_DEREFERENCE
DISABLE_GCC_WARNING(null-dereference)
@@ -40,7 +38,7 @@ crash(int x)
* don't need to see us dereference NULL. */
#else
*(volatile int *)0 = 0;
-#endif
+#endif /* defined(__clang_analyzer__) || defined(__COVERITY__) */
} else if (crashtype == 1) {
tor_assert(1 == 0);
} else if (crashtype == -1) {
@@ -76,13 +74,6 @@ we_weave(int x)
return a_tangled_web(x) + a_tangled_web(x+1);
}
-static void
-abort_handler(int s)
-{
- (void)s;
- exit(0);
-}
-
int
main(int argc, char **argv)
{
@@ -120,8 +111,6 @@ main(int argc, char **argv)
configure_backtrace_handler(NULL);
- signal(SIGABRT, abort_handler);
-
printf("%d\n", we_weave(2));
clean_up_backtrace_handler();
diff --git a/src/test/test_buffers.c b/src/test/test_buffers.c
index 3408da3aa9..9f4e19bc5f 100644
--- a/src/test/test_buffers.c
+++ b/src/test/test_buffers.c
@@ -1,12 +1,15 @@
/* 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
+#define PROTO_HTTP_PRIVATE
#include "or.h"
#include "buffers.h"
-#include "ext_orport.h"
+#include "buffers_tls.h"
+#include "proto_http.h"
+#include "proto_socks.h"
#include "test.h"
/** Run unit tests for buffers.c */
@@ -38,15 +41,15 @@ test_buffers_basic(void *arg)
for (j=0;j<256;++j) {
str[j] = (char)j;
}
- write_to_buf(str, 256, buf);
- write_to_buf(str, 256, buf);
+ buf_add(buf, str, 256);
+ buf_add(buf, str, 256);
tt_int_op(buf_datalen(buf),OP_EQ, 512);
- fetch_from_buf(str2, 200, buf);
+ buf_get_bytes(buf, str2, 200);
tt_mem_op(str,OP_EQ, str2, 200);
tt_int_op(buf_datalen(buf),OP_EQ, 312);
memset(str2, 0, sizeof(str2));
- fetch_from_buf(str2, 256, buf);
+ buf_get_bytes(buf, str2, 256);
tt_mem_op(str+200,OP_EQ, str2, 56);
tt_mem_op(str,OP_EQ, str2+56, 200);
tt_int_op(buf_datalen(buf),OP_EQ, 56);
@@ -54,16 +57,16 @@ test_buffers_basic(void *arg)
/* Okay, now we should be 512 bytes into the 4096-byte buffer. If we add
* another 3584 bytes, we hit the end. */
for (j=0;j<15;++j) {
- write_to_buf(str, 256, buf);
+ buf_add(buf, str, 256);
}
- assert_buf_ok(buf);
+ buf_assert_ok(buf);
tt_int_op(buf_datalen(buf),OP_EQ, 3896);
- fetch_from_buf(str2, 56, buf);
+ buf_get_bytes(buf, str2, 56);
tt_int_op(buf_datalen(buf),OP_EQ, 3840);
tt_mem_op(str+200,OP_EQ, str2, 56);
for (j=0;j<15;++j) {
memset(str2, 0, sizeof(str2));
- fetch_from_buf(str2, 256, buf);
+ buf_get_bytes(buf, str2, 256);
tt_mem_op(str,OP_EQ, str2, 256);
}
tt_int_op(buf_datalen(buf),OP_EQ, 0);
@@ -73,38 +76,38 @@ test_buffers_basic(void *arg)
/* Okay, now make sure growing can work. */
buf = buf_new_with_capacity(16);
//test_eq(buf_capacity(buf), 16);
- write_to_buf(str+1, 255, buf);
+ buf_add(buf, str+1, 255);
//test_eq(buf_capacity(buf), 256);
- fetch_from_buf(str2, 254, buf);
+ buf_get_bytes(buf, str2, 254);
tt_mem_op(str+1,OP_EQ, str2, 254);
//test_eq(buf_capacity(buf), 256);
- assert_buf_ok(buf);
- write_to_buf(str, 32, buf);
+ buf_assert_ok(buf);
+ buf_add(buf, str, 32);
//test_eq(buf_capacity(buf), 256);
- assert_buf_ok(buf);
- write_to_buf(str, 256, buf);
- assert_buf_ok(buf);
+ buf_assert_ok(buf);
+ buf_add(buf, str, 256);
+ buf_assert_ok(buf);
//test_eq(buf_capacity(buf), 512);
tt_int_op(buf_datalen(buf),OP_EQ, 33+256);
- fetch_from_buf(str2, 33, buf);
+ buf_get_bytes(buf, str2, 33);
tt_int_op(*str2,OP_EQ, str[255]);
tt_mem_op(str2+1,OP_EQ, str, 32);
//test_eq(buf_capacity(buf), 512);
tt_int_op(buf_datalen(buf),OP_EQ, 256);
- fetch_from_buf(str2, 256, buf);
+ buf_get_bytes(buf, str2, 256);
tt_mem_op(str,OP_EQ, str2, 256);
/* now try shrinking: case 1. */
buf_free(buf);
buf = buf_new_with_capacity(33668);
for (j=0;j<67;++j) {
- write_to_buf(str,255, buf);
+ buf_add(buf, str,255);
}
//test_eq(buf_capacity(buf), 33668);
tt_int_op(buf_datalen(buf),OP_EQ, 17085);
for (j=0; j < 40; ++j) {
- fetch_from_buf(str2, 255,buf);
+ buf_get_bytes(buf, str2, 255);
tt_mem_op(str2,OP_EQ, str, 255);
}
@@ -112,18 +115,18 @@ test_buffers_basic(void *arg)
buf_free(buf);
buf = buf_new_with_capacity(33668);
for (j=0;j<67;++j) {
- write_to_buf(str,255, buf);
+ buf_add(buf, str, 255);
}
for (j=0; j < 20; ++j) {
- fetch_from_buf(str2, 255,buf);
+ buf_get_bytes(buf, str2, 255);
tt_mem_op(str2,OP_EQ, str, 255);
}
for (j=0;j<80;++j) {
- write_to_buf(str,255, buf);
+ buf_add(buf, str, 255);
}
//test_eq(buf_capacity(buf),33668);
for (j=0; j < 120; ++j) {
- fetch_from_buf(str2, 255,buf);
+ buf_get_bytes(buf, str2, 255);
tt_mem_op(str2,OP_EQ, str, 255);
}
@@ -132,27 +135,27 @@ test_buffers_basic(void *arg)
buf = buf_new_with_capacity(4096);
buf2 = buf_new_with_capacity(4096);
for (j=0;j<100;++j)
- write_to_buf(str, 255, buf);
+ buf_add(buf, str, 255);
tt_int_op(buf_datalen(buf),OP_EQ, 25500);
for (j=0;j<100;++j) {
r = 10;
- move_buf_to_buf(buf2, buf, &r);
+ buf_move_to_buf(buf2, buf, &r);
tt_int_op(r,OP_EQ, 0);
}
tt_int_op(buf_datalen(buf),OP_EQ, 24500);
tt_int_op(buf_datalen(buf2),OP_EQ, 1000);
for (j=0;j<3;++j) {
- fetch_from_buf(str2, 255, buf2);
+ buf_get_bytes(buf2, str2, 255);
tt_mem_op(str2,OP_EQ, str, 255);
}
r = 8192; /*big move*/
- move_buf_to_buf(buf2, buf, &r);
+ buf_move_to_buf(buf2, buf, &r);
tt_int_op(r,OP_EQ, 0);
r = 30000; /* incomplete move */
- move_buf_to_buf(buf2, buf, &r);
+ buf_move_to_buf(buf2, buf, &r);
tt_int_op(r,OP_EQ, 13692);
for (j=0;j<97;++j) {
- fetch_from_buf(str2, 255, buf2);
+ buf_get_bytes(buf2, str2, 255);
tt_mem_op(str2,OP_EQ, str, 255);
}
buf_free(buf);
@@ -162,7 +165,7 @@ test_buffers_basic(void *arg)
buf = buf_new_with_capacity(5);
cp = "Testing. This is a moderately long Testing string.";
for (j = 0; cp[j]; j++)
- write_to_buf(cp+j, 1, buf);
+ buf_add(buf, cp+j, 1);
tt_int_op(0,OP_EQ, buf_find_string_offset(buf, "Testing", 7));
tt_int_op(1,OP_EQ, buf_find_string_offset(buf, "esting", 6));
tt_int_op(1,OP_EQ, buf_find_string_offset(buf, "est", 3));
@@ -180,7 +183,7 @@ test_buffers_basic(void *arg)
{
char *mem = tor_malloc_zero(65536);
buf = buf_new();
- write_to_buf(mem, 65536, buf);
+ buf_add(buf, mem, 65536);
tor_free(mem);
tt_int_op(buf_datalen(buf), OP_EQ, 65536);
@@ -215,8 +218,7 @@ test_buffer_pullup(void *arg)
/* There are a bunch of cases for pullup. One is the trivial case. Let's
mess around with an empty buffer. */
- buf_pullup(buf, 16);
- buf_get_first_chunk_data(buf, &cp, &sz);
+ buf_pullup(buf, 16, &cp, &sz);
tt_ptr_op(cp, OP_EQ, NULL);
tt_uint_op(sz, OP_EQ, 0);
@@ -227,65 +229,62 @@ test_buffer_pullup(void *arg)
/* Let's add some data. */
crypto_rand(stuff, 16384);
- write_to_buf(stuff, 3000, buf);
- write_to_buf(stuff+3000, 3000, buf);
- buf_get_first_chunk_data(buf, &cp, &sz);
+ buf_add(buf, stuff, 3000);
+ buf_add(buf, stuff+3000, 3000);
+ buf_pullup(buf, 0, &cp, &sz);
tt_ptr_op(cp, OP_NE, NULL);
tt_int_op(sz, OP_LE, 4096);
/* Make room for 3000 bytes in the first chunk, so that the pullup-move code
* can get tested. */
- tt_int_op(fetch_from_buf(tmp, 3000, buf), OP_EQ, 3000);
+ tt_int_op(buf_get_bytes(buf, tmp, 3000), OP_EQ, 3000);
tt_mem_op(tmp,OP_EQ, stuff, 3000);
- buf_pullup(buf, 2048);
- assert_buf_ok(buf);
- buf_get_first_chunk_data(buf, &cp, &sz);
+ buf_pullup(buf, 2048, &cp, &sz);
+ buf_assert_ok(buf);
tt_ptr_op(cp, OP_NE, NULL);
tt_int_op(sz, OP_GE, 2048);
tt_mem_op(cp,OP_EQ, stuff+3000, 2048);
tt_int_op(3000, OP_EQ, buf_datalen(buf));
- tt_int_op(fetch_from_buf(tmp, 3000, buf), OP_EQ, 0);
+ tt_int_op(buf_get_bytes(buf, tmp, 3000), OP_EQ, 0);
tt_mem_op(tmp,OP_EQ, stuff+3000, 2048);
buf_free(buf);
/* Now try the large-chunk case. */
buf = buf_new_with_capacity(3000); /* rounds up to next power of 2. */
- write_to_buf(stuff, 4000, buf);
- write_to_buf(stuff+4000, 4000, buf);
- write_to_buf(stuff+8000, 4000, buf);
- write_to_buf(stuff+12000, 4000, buf);
+ buf_add(buf, stuff, 4000);
+ buf_add(buf, stuff+4000, 4000);
+ buf_add(buf, stuff+8000, 4000);
+ buf_add(buf, stuff+12000, 4000);
tt_int_op(buf_datalen(buf), OP_EQ, 16000);
- buf_get_first_chunk_data(buf, &cp, &sz);
+ buf_pullup(buf, 0, &cp, &sz);
tt_ptr_op(cp, OP_NE, NULL);
tt_int_op(sz, OP_LE, 4096);
- buf_pullup(buf, 12500);
- assert_buf_ok(buf);
- buf_get_first_chunk_data(buf, &cp, &sz);
+ buf_pullup(buf, 12500, &cp, &sz);
+ buf_assert_ok(buf);
tt_ptr_op(cp, OP_NE, NULL);
tt_int_op(sz, OP_GE, 12500);
tt_mem_op(cp,OP_EQ, stuff, 12500);
tt_int_op(buf_datalen(buf), OP_EQ, 16000);
- fetch_from_buf(tmp, 12400, buf);
+ buf_get_bytes(buf, tmp, 12400);
tt_mem_op(tmp,OP_EQ, stuff, 12400);
tt_int_op(buf_datalen(buf), OP_EQ, 3600);
- fetch_from_buf(tmp, 3500, buf);
+ buf_get_bytes(buf, tmp, 3500);
tt_mem_op(tmp,OP_EQ, stuff+12400, 3500);
- fetch_from_buf(tmp, 100, buf);
+ buf_get_bytes(buf, tmp, 100);
tt_mem_op(tmp,OP_EQ, stuff+15900, 10);
buf_free(buf);
/* Make sure that the pull-up-whole-buffer case works */
buf = buf_new_with_capacity(3000); /* rounds up to next power of 2. */
- write_to_buf(stuff, 4000, buf);
- write_to_buf(stuff+4000, 4000, buf);
- fetch_from_buf(tmp, 100, buf); /* dump 100 bytes from first chunk */
- buf_pullup(buf, 16000); /* Way too much. */
- assert_buf_ok(buf);
- buf_get_first_chunk_data(buf, &cp, &sz);
+ buf_add(buf, stuff, 4000);
+ buf_add(buf, stuff+4000, 4000);
+ buf_get_bytes(buf, tmp, 100); /* dump 100 bytes from first chunk */
+ buf_pullup(buf, 16000, &cp, &sz);
+ buf_assert_ok(buf);
tt_ptr_op(cp, OP_NE, NULL);
tt_int_op(sz, OP_EQ, 7900);
tt_mem_op(cp,OP_EQ, stuff+100, 7900);
@@ -321,23 +320,23 @@ test_buffer_copy(void *arg)
/* Now try with a short buffer. */
s = "And now comes an act of enormous enormance!";
len = strlen(s);
- write_to_buf(s, len, buf);
+ buf_add(buf, s, len);
tt_int_op(len, OP_EQ, buf_datalen(buf));
/* Add junk to buf2 so we can test replacing.*/
- write_to_buf("BLARG", 5, buf2);
+ buf_add(buf2, "BLARG", 5);
tt_int_op(0, OP_EQ, buf_set_to_copy(&buf2, buf));
tt_int_op(len, OP_EQ, buf_datalen(buf2));
- fetch_from_buf(b, len, buf2);
+ buf_get_bytes(buf2, b, len);
tt_mem_op(b, OP_EQ, s, len);
/* Now free buf2 and retry so we can test allocating */
buf_free(buf2);
buf2 = NULL;
tt_int_op(0, OP_EQ, buf_set_to_copy(&buf2, buf));
tt_int_op(len, OP_EQ, buf_datalen(buf2));
- fetch_from_buf(b, len, buf2);
+ buf_get_bytes(buf2, b, len);
tt_mem_op(b, OP_EQ, s, len);
/* Clear buf for next test */
- fetch_from_buf(b, len, buf);
+ buf_get_bytes(buf, b, len);
tt_int_op(buf_datalen(buf),OP_EQ,0);
/* Okay, now let's try a bigger buffer. */
@@ -347,13 +346,13 @@ test_buffer_copy(void *arg)
len = strlen(s);
for (i = 0; i < 256; ++i) {
b[0]=i;
- write_to_buf(b, 1, buf);
- write_to_buf(s, len, buf);
+ buf_add(buf, b, 1);
+ buf_add(buf, s, len);
}
tt_int_op(0, OP_EQ, buf_set_to_copy(&buf2, buf));
tt_int_op(buf_datalen(buf2), OP_EQ, buf_datalen(buf));
for (i = 0; i < 256; ++i) {
- fetch_from_buf(b, len+1, buf2);
+ buf_get_bytes(buf2, b, len+1);
tt_int_op((unsigned char)b[0],OP_EQ,i);
tt_mem_op(b+1, OP_EQ, s, len);
}
@@ -366,79 +365,6 @@ test_buffer_copy(void *arg)
}
static void
-test_buffer_ext_or_cmd(void *arg)
-{
- ext_or_cmd_t *cmd = NULL;
- buf_t *buf = buf_new();
- char *tmp = NULL;
- (void) arg;
-
- /* Empty -- should give "not there. */
- tt_int_op(0, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd));
- tt_ptr_op(NULL, OP_EQ, cmd);
-
- /* Three bytes: shouldn't work. */
- write_to_buf("\x00\x20\x00", 3, buf);
- tt_int_op(0, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd));
- tt_ptr_op(NULL, OP_EQ, cmd);
- tt_int_op(3, OP_EQ, buf_datalen(buf));
-
- /* 0020 0000: That's a nil command. It should work. */
- write_to_buf("\x00", 1, buf);
- tt_int_op(1, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd));
- tt_ptr_op(NULL, OP_NE, cmd);
- tt_int_op(0x20, OP_EQ, cmd->cmd);
- tt_int_op(0, OP_EQ, cmd->len);
- tt_int_op(0, OP_EQ, buf_datalen(buf));
- ext_or_cmd_free(cmd);
- cmd = NULL;
-
- /* Now try a length-6 command with one byte missing. */
- write_to_buf("\x10\x21\x00\x06""abcde", 9, buf);
- tt_int_op(0, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd));
- tt_ptr_op(NULL, OP_EQ, cmd);
- write_to_buf("f", 1, buf);
- tt_int_op(1, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd));
- tt_ptr_op(NULL, OP_NE, cmd);
- tt_int_op(0x1021, OP_EQ, cmd->cmd);
- tt_int_op(6, OP_EQ, cmd->len);
- tt_mem_op("abcdef", OP_EQ, cmd->body, 6);
- tt_int_op(0, OP_EQ, buf_datalen(buf));
- ext_or_cmd_free(cmd);
- cmd = NULL;
-
- /* Now try a length-10 command with 4 extra bytes. */
- write_to_buf("\xff\xff\x00\x0aloremipsum\x10\x00\xff\xff", 18, buf);
- tt_int_op(1, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd));
- tt_ptr_op(NULL, OP_NE, cmd);
- tt_int_op(0xffff, OP_EQ, cmd->cmd);
- tt_int_op(10, OP_EQ, cmd->len);
- tt_mem_op("loremipsum", OP_EQ, cmd->body, 10);
- tt_int_op(4, OP_EQ, buf_datalen(buf));
- ext_or_cmd_free(cmd);
- cmd = NULL;
-
- /* Finally, let's try a maximum-length command. We already have the header
- * waiting. */
- tt_int_op(0, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd));
- tmp = tor_malloc_zero(65535);
- write_to_buf(tmp, 65535, buf);
- tt_int_op(1, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd));
- tt_ptr_op(NULL, OP_NE, cmd);
- tt_int_op(0x1000, OP_EQ, cmd->cmd);
- tt_int_op(0xffff, OP_EQ, cmd->len);
- tt_mem_op(tmp, OP_EQ, cmd->body, 65535);
- tt_int_op(0, OP_EQ, buf_datalen(buf));
- ext_or_cmd_free(cmd);
- cmd = NULL;
-
- done:
- ext_or_cmd_free(cmd);
- buf_free(buf);
- tor_free(tmp);
-}
-
-static void
test_buffer_allocation_tracking(void *arg)
{
char *junk = tor_malloc(16384);
@@ -458,36 +384,36 @@ test_buffer_allocation_tracking(void *arg)
tt_int_op(buf_allocation(buf1), OP_EQ, 0);
tt_int_op(buf_get_total_allocation(), OP_EQ, 0);
- write_to_buf(junk, 4000, buf1);
- write_to_buf(junk, 4000, buf1);
- write_to_buf(junk, 4000, buf1);
- write_to_buf(junk, 4000, buf1);
+ buf_add(buf1, junk, 4000);
+ buf_add(buf1, junk, 4000);
+ buf_add(buf1, junk, 4000);
+ buf_add(buf1, junk, 4000);
tt_int_op(buf_allocation(buf1), OP_EQ, 16384);
- fetch_from_buf(junk, 100, buf1);
+ buf_get_bytes(buf1, junk, 100);
tt_int_op(buf_allocation(buf1), OP_EQ, 16384); /* still 4 4k chunks */
tt_int_op(buf_get_total_allocation(), OP_EQ, 16384);
- fetch_from_buf(junk, 4096, buf1); /* drop a 1k chunk... */
+ buf_get_bytes(buf1, junk, 4096); /* drop a 1k chunk... */
tt_int_op(buf_allocation(buf1), OP_EQ, 3*4096); /* now 3 4k chunks */
tt_int_op(buf_get_total_allocation(), OP_EQ, 12288); /* that chunk was really
freed. */
- write_to_buf(junk, 4000, buf2);
+ buf_add(buf2, junk, 4000);
tt_int_op(buf_allocation(buf2), OP_EQ, 4096); /* another 4k chunk. */
/*
* We bounce back up to 16384 by allocating a new chunk.
*/
tt_int_op(buf_get_total_allocation(), OP_EQ, 16384);
- write_to_buf(junk, 4000, buf2);
+ buf_add(buf2, junk, 4000);
tt_int_op(buf_allocation(buf2), OP_EQ, 8192); /* another 4k chunk. */
tt_int_op(buf_get_total_allocation(),
OP_EQ, 5*4096); /* that chunk was new. */
/* Make a really huge buffer */
for (i = 0; i < 1000; ++i) {
- write_to_buf(junk, 4000, buf2);
+ buf_add(buf2, junk, 4000);
}
tt_int_op(buf_allocation(buf2), OP_GE, 4008000);
tt_int_op(buf_get_total_allocation(), OP_GE, 4008000);
@@ -530,7 +456,7 @@ test_buffer_time_tracking(void *arg)
tt_int_op(0, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_MSEC));
tt_int_op(0, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_MSEC+1000));
- write_to_buf("ABCDEFG", 7, buf);
+ buf_add(buf, "ABCDEFG", 7);
tt_int_op(1000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_MSEC+1000));
buf2 = buf_copy(buf);
@@ -541,7 +467,7 @@ test_buffer_time_tracking(void *arg)
/* Now add more bytes; enough to overflow the first chunk. */
monotime_coarse_set_mock_time_nsec(START_NSEC + 123 * (uint64_t)1000000);
for (i = 0; i < 600; ++i)
- write_to_buf("ABCDEFG", 7, buf);
+ buf_add(buf, "ABCDEFG", 7);
tt_int_op(4207, OP_EQ, buf_datalen(buf));
/* The oldest bytes are still in the front. */
@@ -549,12 +475,12 @@ test_buffer_time_tracking(void *arg)
/* Once those bytes are dropped, the chunk is still on the first
* timestamp. */
- fetch_from_buf(tmp, 100, buf);
+ buf_get_bytes(buf, tmp, 100);
tt_int_op(2000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_MSEC+2000));
/* But once we discard the whole first chunk, we get the data in the second
* chunk. */
- fetch_from_buf(tmp, 4000, buf);
+ buf_get_bytes(buf, tmp, 4000);
tt_int_op(107, OP_EQ, buf_datalen(buf));
tt_int_op(2000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_MSEC+2123));
@@ -562,12 +488,12 @@ test_buffer_time_tracking(void *arg)
its time gets updated */
monotime_coarse_set_mock_time_nsec(START_NSEC + 5617 * (uint64_t)1000000);
for (i = 0; i < 600; ++i)
- write_to_buf("ABCDEFG", 7, buf);
+ buf_add(buf, "ABCDEFG", 7);
tt_int_op(4307, OP_EQ, buf_datalen(buf));
tt_int_op(2000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_MSEC+2123));
- fetch_from_buf(tmp, 4000, buf);
- fetch_from_buf(tmp, 306, buf);
+ buf_get_bytes(buf, tmp, 4000);
+ buf_get_bytes(buf, tmp, 306);
tt_int_op(0, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_MSEC+5617));
tt_int_op(383, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_MSEC+6000));
@@ -578,120 +504,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);
- }
+ buf_add(buf, msg, 1);
+ 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;
+ buf_add(buf, msg, headerjunk-1);
+ 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(buf_add_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(buf_get_bytes(buf, contents, in_len), 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(buf_add_compress(buf, compress_state,
+ msg, 128, 0), OP_EQ, 0);
+ tt_int_op(buf_add_compress(buf, compress_state,
+ msg+128, 128, 0), OP_EQ, 0);
+ tt_int_op(buf_add_compress(buf, compress_state,
+ msg+256, 256, 0), OP_EQ, 0);
+ done = !finalize_with_nil;
+ tt_int_op(buf_add_compress(buf, compress_state,
+ "all done", 9, done), OP_EQ, 0);
+ if (finalize_with_nil) {
+ tt_int_op(buf_add_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(buf_get_bytes(buf, contents, in_len), OP_EQ, 0);
- tt_uint_op(in_len, OP_GT, headerjunk);
+ tt_int_op(0, OP_EQ, tor_uncompress(&expanded, &out_len,
+ contents, in_len,
+ method, 1,
+ LOG_WARN));
- 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(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];
@@ -732,11 +688,11 @@ test_buffers_tls_read_mocked(void *arg)
buf = buf_new();
next_reply_val[0] = 1024;
- tt_int_op(128, ==, read_to_buf_tls(NULL, 128, buf));
+ tt_int_op(128, OP_EQ, buf_read_from_tls(buf, NULL, 128));
next_reply_val[0] = 5000;
next_reply_val[1] = 5000;
- tt_int_op(6000, ==, read_to_buf_tls(NULL, 6000, buf));
+ tt_int_op(6000, OP_EQ, buf_read_from_tls(buf, NULL, 6000));
done:
UNMOCK(tor_tls_read);
@@ -750,36 +706,114 @@ test_buffers_chunk_size(void *arg)
(void)arg;
const int min = 256;
const int max = 65536;
- tt_uint_op(preferred_chunk_size(3), OP_EQ, min);
- tt_uint_op(preferred_chunk_size(25), OP_EQ, min);
- tt_uint_op(preferred_chunk_size(0), OP_EQ, min);
- tt_uint_op(preferred_chunk_size(256), OP_EQ, 512);
- tt_uint_op(preferred_chunk_size(65400), OP_EQ, max);
+ tt_uint_op(buf_preferred_chunk_size(3), OP_EQ, min);
+ tt_uint_op(buf_preferred_chunk_size(25), OP_EQ, min);
+ tt_uint_op(buf_preferred_chunk_size(0), OP_EQ, min);
+ tt_uint_op(buf_preferred_chunk_size(256), OP_EQ, 512);
+ tt_uint_op(buf_preferred_chunk_size(65400), OP_EQ, max);
/* Here, we're implicitly saying that the chunk header overhead is
* between 1 and 100 bytes. 24..48 would probably be more accurate. */
- tt_uint_op(preferred_chunk_size(65536), OP_GT, 65536);
- tt_uint_op(preferred_chunk_size(65536), OP_LT, 65536+100);
- tt_uint_op(preferred_chunk_size(165536), OP_GT, 165536);
- tt_uint_op(preferred_chunk_size(165536), OP_LT, 165536+100);
+ tt_uint_op(buf_preferred_chunk_size(65536), OP_GT, 65536);
+ tt_uint_op(buf_preferred_chunk_size(65536), OP_LT, 65536+100);
+ tt_uint_op(buf_preferred_chunk_size(165536), OP_GT, 165536);
+ tt_uint_op(buf_preferred_chunk_size(165536), OP_LT, 165536+100);
+ done:
+ ;
+}
+
+static void
+test_buffers_find_contentlen(void *arg)
+{
+ static const struct {
+ const char *headers;
+ int r;
+ int contentlen;
+ } results[] = {
+ { "Blah blah\r\nContent-Length: 1\r\n\r\n", 1, 1 },
+ { "Blah blah\r\n\r\n", 0, 0 }, /* no content-len */
+ { "Blah blah Content-Length: 1\r\n", 0, 0 }, /* no content-len. */
+ { "Blah blah\r\nContent-Length: 100000\r\n", 1, 100000},
+ { "Blah blah\r\nContent-Length: 1000000000000000000000000\r\n", -1, 0},
+ { "Blah blah\r\nContent-Length: 0\r\n", 1, 0},
+ { "Blah blah\r\nContent-Length: -1\r\n", -1, 0},
+ { "Blah blah\r\nContent-Length: 1x\r\n", -1, 0},
+ { "Blah blah\r\nContent-Length: 1 x\r\n", -1, 0},
+ { "Blah blah\r\nContent-Length: 1 \r\n", 1, 1},
+ { "Blah blah\r\nContent-Length: \r\n", -1, 0},
+ { "Blah blah\r\nContent-Length: ", -1, 0},
+ { "Blah blah\r\nContent-Length: 5050", -1, 0},
+ { NULL, 0, 0 }
+ };
+ int i;
+
+ (void)arg;
+
+ for (i = 0; results[i].headers; ++i) {
+ int r;
+ size_t sz;
+ size_t headerlen = strlen(results[i].headers);
+ char * tmp = tor_memdup(results[i].headers, headerlen);/* ensure no eos */
+ sz = 999; /* to ensure it gets set */
+ r = buf_http_find_content_length(tmp, headerlen, &sz);
+ tor_free(tmp);
+ log_debug(LD_DIR, "%d: %s", i, escaped(results[i].headers));
+ tt_int_op(r, OP_EQ, results[i].r);
+ tt_int_op(sz, OP_EQ, results[i].contentlen);
+ }
done:
;
}
+static void
+test_buffer_peek_startswith(void *arg)
+{
+ (void)arg;
+ buf_t *buf;
+ buf = buf_new();
+ tt_ptr_op(buf, OP_NE, NULL);
+
+ tt_assert(buf_peek_startswith(buf, ""));
+ tt_assert(! buf_peek_startswith(buf, "X"));
+
+ buf_add(buf, "Tor", 3);
+
+ tt_assert(buf_peek_startswith(buf, ""));
+ tt_assert(buf_peek_startswith(buf, "T"));
+ tt_assert(buf_peek_startswith(buf, "To"));
+ tt_assert(buf_peek_startswith(buf, "Tor"));
+ tt_assert(! buf_peek_startswith(buf, "Top"));
+ tt_assert(! buf_peek_startswith(buf, "For"));
+ tt_assert(! buf_peek_startswith(buf, "Tork"));
+ tt_assert(! buf_peek_startswith(buf, "Torpor"));
+
+ done:
+ buf_free(buf);
+}
+
struct testcase_t buffer_tests[] = {
{ "basic", test_buffers_basic, TT_FORK, NULL, NULL },
{ "copy", test_buffer_copy, TT_FORK, NULL, NULL },
{ "pullup", test_buffer_pullup, TT_FORK, NULL, NULL },
- { "ext_or_cmd", test_buffer_ext_or_cmd, TT_FORK, NULL, NULL },
+ { "startswith", test_buffer_peek_startswith, 0, NULL, NULL },
{ "allocation_tracking", test_buffer_allocation_tracking, TT_FORK,
NULL, NULL },
{ "time_tracking", test_buffer_time_tracking, TT_FORK, NULL, NULL },
- { "zlib", test_buffers_zlib, TT_FORK, NULL, NULL },
- { "zlib_fin_with_nil", test_buffers_zlib_fin_with_nil, TT_FORK, NULL, NULL },
- { "zlib_fin_at_chunk_end", test_buffers_zlib_fin_at_chunk_end, TT_FORK,
- NULL, NULL},
{ "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 f429f4291d..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"
@@ -11,6 +11,7 @@
#include "channel.h"
#include "connection_edge.h"
#include "connection_or.h"
+#include "config.h"
#include "onion.h"
#include "onion_tap.h"
#include "onion_fast.h"
@@ -698,6 +699,7 @@ test_cfmt_extend_cells(void *arg)
tt_int_op(61681, OP_EQ, ec.orport_ipv4.port);
tt_str_op("2002::f0:c51e", OP_EQ, fmt_addr(&ec.orport_ipv6.addr));
tt_int_op(4370, OP_EQ, ec.orport_ipv6.port);
+ tt_assert(ed25519_public_key_is_zero(&ec.ed_pubkey));
tt_mem_op(ec.node_id,OP_EQ, "anthropomorphization", 20);
tt_int_op(cc->cell_type, OP_EQ, CELL_CREATE2);
tt_int_op(cc->handshake_type, OP_EQ, 0x105);
@@ -717,6 +719,37 @@ test_cfmt_extend_cells(void *arg)
tt_mem_op(p2+1+8+22+4,OP_EQ, b, 99+20);
tt_int_op(0, OP_EQ, create_cell_format_relayed(&cell, cc));
+ /* Now let's add an ed25519 key to that extend2 cell. */
+ memcpy(ec.ed_pubkey.pubkey,
+ "brownshoesdontmakeit/brownshoesd", 32);
+
+ /* As before, since we aren't extending by ed25519. */
+ get_options_mutable()->ExtendByEd25519ID = 0;
+ tt_int_op(0, OP_EQ, extend_cell_format(&p2_cmd, &p2_len, p2, &ec));
+ tt_int_op(p2_len, OP_EQ, 89+99-34-20);
+ test_memeq_hex(p2,
+ "02000612F40001F0F1"
+ "0214616e7468726f706f6d6f727068697a6174696f6e"
+ "01050063");
+
+ /* Now try with the ed25519 ID. */
+ get_options_mutable()->ExtendByEd25519ID = 1;
+ tt_int_op(0, OP_EQ, extend_cell_format(&p2_cmd, &p2_len, p2, &ec));
+ tt_int_op(p2_len, OP_EQ, 89+99-34-20 + 34);
+ test_memeq_hex(p2,
+ "03000612F40001F0F1"
+ "0214616e7468726f706f6d6f727068697a6174696f6e"
+ // ed digest follows:
+ "0320" "62726f776e73686f6573646f6e746d616b656"
+ "9742f62726f776e73686f657364"
+ "01050063");
+ /* Can we parse that? Did the key come through right? */
+ memset(&ec, 0, sizeof(ec));
+ tt_int_op(0, OP_EQ, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
+ p2, p2_len));
+ tt_mem_op("brownshoesdontmakeit/brownshoesd", OP_EQ,
+ ec.ed_pubkey.pubkey, 32);
+
/* == Now try parsing some junk */
/* Try a too-long handshake */
@@ -1257,7 +1290,7 @@ struct testcase_t cell_format_tests[] = {
TEST(connected_cells, 0),
TEST(create_cells, 0),
TEST(created_cells, 0),
- TEST(extend_cells, 0),
+ TEST(extend_cells, TT_FORK),
TEST(extended_cells, 0),
TEST(resolved_cells, 0),
TEST(is_destroy, 0),
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 a9e0634d9e..023c2950c9 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_
@@ -86,7 +86,7 @@ channel_note_destroy_not_pending_mock(channel_t *ch,
static const char *
chan_test_describe_transport(channel_t *ch)
{
- tt_assert(ch != NULL);
+ tt_ptr_op(ch, OP_NE, NULL);
done:
return "Fake channel for unit tests";
@@ -100,7 +100,7 @@ chan_test_describe_transport(channel_t *ch)
static void
chan_test_channel_dump_statistics_mock(channel_t *chan, int severity)
{
- tt_assert(chan != NULL);
+ tt_ptr_op(chan, OP_NE, NULL);
(void)severity;
@@ -125,7 +125,7 @@ chan_test_channel_flush_from_first_active_circuit_mock(channel_t *chan,
int result = 0, c = 0;
packed_cell_t *cell = NULL;
- tt_assert(chan != NULL);
+ tt_ptr_op(chan, OP_NE, NULL);
if (test_target_cmux != NULL &&
test_target_cmux == chan->cmux) {
while (c <= max && test_cmux_cells > 0) {
@@ -154,7 +154,7 @@ chan_test_circuitmux_num_cells_mock(circuitmux_t *cmux)
{
unsigned int result = 0;
- tt_assert(cmux != NULL);
+ tt_ptr_op(cmux, OP_NE, NULL);
if (cmux != NULL) {
if (cmux == test_target_cmux) {
result = test_cmux_cells;
@@ -193,7 +193,7 @@ chan_test_cell_handler(channel_t *ch,
static void
chan_test_dumpstats(channel_t *ch, int severity)
{
- tt_assert(ch != NULL);
+ tt_ptr_op(ch, OP_NE, NULL);
(void)severity;
@@ -268,7 +268,7 @@ static const char *
chan_test_get_remote_descr(channel_t *ch, int flags)
{
tt_assert(ch);
- tt_int_op(flags & ~(GRD_FLAG_ORIGINAL | GRD_FLAG_ADDR_ONLY), ==, 0);
+ tt_int_op(flags & ~(GRD_FLAG_ORIGINAL | GRD_FLAG_ADDR_ONLY), OP_EQ, 0);
done:
return "Fake channel for unit tests; no real endpoint";
@@ -286,7 +286,7 @@ chan_test_get_overhead_estimate(channel_t *ch)
static int
chan_test_is_canonical(channel_t *ch, int req)
{
- tt_assert(ch != NULL);
+ tt_ptr_op(ch, OP_NE, NULL);
tt_assert(req == 0 || req == 1);
done:
@@ -380,7 +380,7 @@ chan_test_write_var_cell(channel_t *ch, var_cell_t *var_cell)
void
make_fake_cell(cell_t *c)
{
- tt_assert(c != NULL);
+ tt_ptr_op(c, OP_NE, NULL);
c->circ_id = 1;
c->command = CELL_RELAY;
@@ -397,7 +397,7 @@ make_fake_cell(cell_t *c)
void
make_fake_var_cell(var_cell_t *c)
{
- tt_assert(c != NULL);
+ tt_ptr_op(c, OP_NE, NULL);
c->circ_id = 1;
c->command = CELL_VERSIONS;
@@ -552,24 +552,24 @@ test_channel_dumpstats(void *arg)
channel_dumpstats(LOG_DEBUG);
/* Assert that we hit the mock */
- tt_int_op(dump_statistics_mock_matches, ==, 1);
+ tt_int_op(dump_statistics_mock_matches, OP_EQ, 1);
/* Close the channel */
channel_mark_for_close(ch);
- tt_int_op(ch->state, ==, CHANNEL_STATE_CLOSING);
+ tt_int_op(ch->state, OP_EQ, CHANNEL_STATE_CLOSING);
chan_test_finish_close(ch);
- tt_int_op(ch->state, ==, CHANNEL_STATE_CLOSED);
+ tt_int_op(ch->state, OP_EQ, CHANNEL_STATE_CLOSED);
/* Try again and hit the finished channel */
channel_dumpstats(LOG_DEBUG);
- tt_int_op(dump_statistics_mock_matches, ==, 2);
+ tt_int_op(dump_statistics_mock_matches, OP_EQ, 2);
channel_run_cleanup();
ch = NULL;
/* Now we should hit nothing */
channel_dumpstats(LOG_DEBUG);
- tt_int_op(dump_statistics_mock_matches, ==, 2);
+ tt_int_op(dump_statistics_mock_matches, OP_EQ, 2);
/* Unmock */
UNMOCK(channel_dump_statistics);
@@ -594,7 +594,7 @@ test_channel_dumpstats(void *arg)
old_count = test_cells_written;
channel_write_cell(ch, cell);
cell = NULL;
- tt_int_op(test_cells_written, ==, old_count + 1);
+ tt_int_op(test_cells_written, OP_EQ, old_count + 1);
tt_assert(ch->n_bytes_xmitted > 0);
tt_assert(ch->n_cells_xmitted > 0);
@@ -602,14 +602,15 @@ test_channel_dumpstats(void *arg)
channel_set_cell_handlers(ch,
chan_test_cell_handler,
chan_test_var_cell_handler);
- tt_ptr_op(channel_get_cell_handler(ch), ==, chan_test_cell_handler);
- tt_ptr_op(channel_get_var_cell_handler(ch), ==, chan_test_var_cell_handler);
+ tt_ptr_op(channel_get_cell_handler(ch), OP_EQ, chan_test_cell_handler);
+ tt_ptr_op(channel_get_var_cell_handler(ch), OP_EQ,
+ chan_test_var_cell_handler);
cell = tor_malloc_zero(sizeof(cell_t));
make_fake_cell(cell);
old_count = test_chan_fixed_cells_recved;
channel_queue_cell(ch, cell);
tor_free(cell);
- tt_int_op(test_chan_fixed_cells_recved, ==, old_count + 1);
+ tt_int_op(test_chan_fixed_cells_recved, OP_EQ, old_count + 1);
tt_assert(ch->n_bytes_recved > 0);
tt_assert(ch->n_cells_recved > 0);
@@ -619,13 +620,13 @@ test_channel_dumpstats(void *arg)
ch->is_canonical = chan_test_is_canonical;
old_count = test_dumpstats_calls;
channel_dump_statistics(ch, LOG_DEBUG);
- tt_int_op(test_dumpstats_calls, ==, old_count + 1);
+ tt_int_op(test_dumpstats_calls, OP_EQ, old_count + 1);
/* Close the channel */
channel_mark_for_close(ch);
- tt_int_op(ch->state, ==, CHANNEL_STATE_CLOSING);
+ tt_int_op(ch->state, OP_EQ, CHANNEL_STATE_CLOSING);
chan_test_finish_close(ch);
- tt_int_op(ch->state, ==, CHANNEL_STATE_CLOSED);
+ tt_int_op(ch->state, OP_EQ, CHANNEL_STATE_CLOSED);
channel_run_cleanup();
ch = NULL;
@@ -664,21 +665,21 @@ test_channel_flush(void *arg)
make_fake_cell(cell);
channel_write_cell(ch, cell);
/* It should be queued, so assert that we didn't write it */
- tt_int_op(test_cells_written, ==, init_count);
+ tt_int_op(test_cells_written, OP_EQ, init_count);
/* Queue a var cell */
v_cell = tor_malloc_zero(sizeof(var_cell_t) + CELL_PAYLOAD_SIZE);
make_fake_var_cell(v_cell);
channel_write_var_cell(ch, v_cell);
/* It should be queued, so assert that we didn't write it */
- tt_int_op(test_cells_written, ==, init_count);
+ tt_int_op(test_cells_written, OP_EQ, init_count);
/* Try a packed cell now */
p_cell = packed_cell_new();
tt_assert(p_cell);
channel_write_packed_cell(ch, p_cell);
/* It should be queued, so assert that we didn't write it */
- tt_int_op(test_cells_written, ==, init_count);
+ tt_int_op(test_cells_written, OP_EQ, init_count);
/* Now allow writes through again */
test_chan_accept_cells = 1;
@@ -687,7 +688,7 @@ test_channel_flush(void *arg)
channel_flush_cells(ch);
/* All three should have gone through */
- tt_int_op(test_cells_written, ==, init_count + 3);
+ tt_int_op(test_cells_written, OP_EQ, init_count + 3);
done:
tor_free(ch);
@@ -728,9 +729,9 @@ test_channel_flushmux(void *arg)
result = channel_flush_some_cells(ch, 1);
- tt_int_op(result, ==, 1);
- tt_int_op(test_cells_written, ==, old_count + 1);
- tt_int_op(test_cmux_cells, ==, 0);
+ tt_int_op(result, OP_EQ, 1);
+ tt_int_op(test_cells_written, OP_EQ, old_count + 1);
+ tt_int_op(test_cmux_cells, OP_EQ, 0);
/* Now try it without accepting to force them into the queue */
test_chan_accept_cells = 0;
@@ -740,19 +741,19 @@ test_channel_flushmux(void *arg)
result = channel_flush_some_cells(ch, 1);
/* We should not have actually flushed any */
- tt_int_op(result, ==, 0);
- tt_int_op(test_cells_written, ==, old_count + 1);
+ tt_int_op(result, OP_EQ, 0);
+ tt_int_op(test_cells_written, OP_EQ, old_count + 1);
/* But we should have gotten to the fake cellgen loop */
- tt_int_op(test_cmux_cells, ==, 0);
+ tt_int_op(test_cmux_cells, OP_EQ, 0);
/* ...and we should have a queued cell */
q_len_after = chan_cell_queue_len(&(ch->outgoing_queue));
- tt_int_op(q_len_after, ==, q_len_before + 1);
+ tt_int_op(q_len_after, OP_EQ, q_len_before + 1);
/* Now accept cells again and drain the queue */
test_chan_accept_cells = 1;
channel_flush_cells(ch);
- tt_int_op(test_cells_written, ==, old_count + 2);
- tt_int_op(chan_cell_queue_len(&(ch->outgoing_queue)), ==, 0);
+ tt_int_op(test_cells_written, OP_EQ, old_count + 2);
+ tt_int_op(chan_cell_queue_len(&(ch->outgoing_queue)), OP_EQ, 0);
test_target_cmux = NULL;
test_cmux_cells = 0;
@@ -803,16 +804,17 @@ test_channel_incoming(void *arg)
chan_test_cell_handler,
chan_test_var_cell_handler);
/* Test cell handler getters */
- tt_ptr_op(channel_get_cell_handler(ch), ==, chan_test_cell_handler);
- tt_ptr_op(channel_get_var_cell_handler(ch), ==, chan_test_var_cell_handler);
+ tt_ptr_op(channel_get_cell_handler(ch), OP_EQ, chan_test_cell_handler);
+ tt_ptr_op(channel_get_var_cell_handler(ch), OP_EQ,
+ chan_test_var_cell_handler);
/* Try to register it */
channel_register(ch);
tt_assert(ch->registered);
/* Open it */
- channel_change_state(ch, CHANNEL_STATE_OPEN);
- tt_int_op(ch->state, ==, CHANNEL_STATE_OPEN);
+ channel_change_state_open(ch);
+ tt_int_op(ch->state, OP_EQ, CHANNEL_STATE_OPEN);
/* Receive a fixed cell */
cell = tor_malloc_zero(sizeof(cell_t));
@@ -820,7 +822,7 @@ test_channel_incoming(void *arg)
old_count = test_chan_fixed_cells_recved;
channel_queue_cell(ch, cell);
tor_free(cell);
- tt_int_op(test_chan_fixed_cells_recved, ==, old_count + 1);
+ tt_int_op(test_chan_fixed_cells_recved, OP_EQ, old_count + 1);
/* Receive a variable-size cell */
var_cell = tor_malloc_zero(sizeof(var_cell_t) + CELL_PAYLOAD_SIZE);
@@ -828,13 +830,13 @@ test_channel_incoming(void *arg)
old_count = test_chan_var_cells_recved;
channel_queue_var_cell(ch, var_cell);
tor_free(cell);
- tt_int_op(test_chan_var_cells_recved, ==, old_count + 1);
+ tt_int_op(test_chan_var_cells_recved, OP_EQ, old_count + 1);
/* Close it */
channel_mark_for_close(ch);
- tt_int_op(ch->state, ==, CHANNEL_STATE_CLOSING);
+ tt_int_op(ch->state, OP_EQ, CHANNEL_STATE_CLOSING);
chan_test_finish_close(ch);
- tt_int_op(ch->state, ==, CHANNEL_STATE_CLOSED);
+ tt_int_op(ch->state, OP_EQ, CHANNEL_STATE_CLOSED);
channel_run_cleanup();
ch = NULL;
@@ -896,13 +898,13 @@ test_channel_lifecycle(void *arg)
make_fake_cell(cell);
old_count = test_cells_written;
channel_write_cell(ch1, cell);
- tt_int_op(old_count, ==, test_cells_written);
+ tt_int_op(old_count, OP_EQ, test_cells_written);
/* Move it to OPEN and flush */
- channel_change_state(ch1, CHANNEL_STATE_OPEN);
+ channel_change_state_open(ch1);
/* Queue should drain */
- tt_int_op(old_count + 1, ==, test_cells_written);
+ tt_int_op(old_count + 1, OP_EQ, test_cells_written);
/* Get another one */
ch2 = new_fake_channel();
@@ -915,41 +917,42 @@ test_channel_lifecycle(void *arg)
tt_assert(ch2->registered);
/* Check counters */
- tt_int_op(test_doesnt_want_writes_count, ==, init_doesnt_want_writes_count);
- tt_int_op(test_releases_count, ==, init_releases_count);
+ tt_int_op(test_doesnt_want_writes_count, OP_EQ,
+ init_doesnt_want_writes_count);
+ tt_int_op(test_releases_count, OP_EQ, init_releases_count);
/* Move ch1 to MAINT */
channel_change_state(ch1, CHANNEL_STATE_MAINT);
- tt_int_op(test_doesnt_want_writes_count, ==,
+ tt_int_op(test_doesnt_want_writes_count, OP_EQ,
init_doesnt_want_writes_count + 1);
- tt_int_op(test_releases_count, ==, init_releases_count);
+ tt_int_op(test_releases_count, OP_EQ, init_releases_count);
/* Move ch2 to OPEN */
- channel_change_state(ch2, CHANNEL_STATE_OPEN);
- tt_int_op(test_doesnt_want_writes_count, ==,
+ channel_change_state_open(ch2);
+ tt_int_op(test_doesnt_want_writes_count, OP_EQ,
init_doesnt_want_writes_count + 1);
- tt_int_op(test_releases_count, ==, init_releases_count);
+ tt_int_op(test_releases_count, OP_EQ, init_releases_count);
/* Move ch1 back to OPEN */
- channel_change_state(ch1, CHANNEL_STATE_OPEN);
- tt_int_op(test_doesnt_want_writes_count, ==,
+ channel_change_state_open(ch1);
+ tt_int_op(test_doesnt_want_writes_count, OP_EQ,
init_doesnt_want_writes_count + 1);
- tt_int_op(test_releases_count, ==, init_releases_count);
+ tt_int_op(test_releases_count, OP_EQ, init_releases_count);
/* Mark ch2 for close */
channel_mark_for_close(ch2);
- tt_int_op(ch2->state, ==, CHANNEL_STATE_CLOSING);
- tt_int_op(test_doesnt_want_writes_count, ==,
+ tt_int_op(ch2->state, OP_EQ, CHANNEL_STATE_CLOSING);
+ tt_int_op(test_doesnt_want_writes_count, OP_EQ,
init_doesnt_want_writes_count + 1);
- tt_int_op(test_releases_count, ==, init_releases_count + 1);
+ tt_int_op(test_releases_count, OP_EQ, init_releases_count + 1);
/* Shut down channels */
channel_free_all();
ch1 = ch2 = NULL;
- tt_int_op(test_doesnt_want_writes_count, ==,
+ tt_int_op(test_doesnt_want_writes_count, OP_EQ,
init_doesnt_want_writes_count + 1);
/* channel_free() calls scheduler_release_channel() */
- tt_int_op(test_releases_count, ==, init_releases_count + 4);
+ tt_int_op(test_releases_count, OP_EQ, init_releases_count + 4);
done:
free_fake_channel(ch1);
@@ -1001,11 +1004,11 @@ test_channel_lifecycle_2(void *arg)
/* Try to close it */
channel_mark_for_close(ch);
- tt_int_op(ch->state, ==, CHANNEL_STATE_CLOSING);
+ tt_int_op(ch->state, OP_EQ, CHANNEL_STATE_CLOSING);
/* Finish closing it */
chan_test_finish_close(ch);
- tt_int_op(ch->state, ==, CHANNEL_STATE_CLOSED);
+ tt_int_op(ch->state, OP_EQ, CHANNEL_STATE_CLOSED);
channel_run_cleanup();
ch = NULL;
@@ -1018,13 +1021,13 @@ test_channel_lifecycle_2(void *arg)
tt_assert(ch->registered);
/* Finish opening it */
- channel_change_state(ch, CHANNEL_STATE_OPEN);
+ channel_change_state_open(ch);
/* Error exit from lower layer */
chan_test_error(ch);
- tt_int_op(ch->state, ==, CHANNEL_STATE_CLOSING);
+ tt_int_op(ch->state, OP_EQ, CHANNEL_STATE_CLOSING);
chan_test_finish_close(ch);
- tt_int_op(ch->state, ==, CHANNEL_STATE_ERROR);
+ tt_int_op(ch->state, OP_EQ, CHANNEL_STATE_ERROR);
channel_run_cleanup();
ch = NULL;
@@ -1037,20 +1040,20 @@ test_channel_lifecycle_2(void *arg)
tt_assert(ch->registered);
/* Finish opening it */
- channel_change_state(ch, CHANNEL_STATE_OPEN);
- tt_int_op(ch->state, ==, CHANNEL_STATE_OPEN);
+ channel_change_state_open(ch);
+ tt_int_op(ch->state, OP_EQ, CHANNEL_STATE_OPEN);
/* Go to maintenance state */
channel_change_state(ch, CHANNEL_STATE_MAINT);
- tt_int_op(ch->state, ==, CHANNEL_STATE_MAINT);
+ tt_int_op(ch->state, OP_EQ, CHANNEL_STATE_MAINT);
/* Lower layer close */
channel_mark_for_close(ch);
- tt_int_op(ch->state, ==, CHANNEL_STATE_CLOSING);
+ tt_int_op(ch->state, OP_EQ, CHANNEL_STATE_CLOSING);
/* Finish */
chan_test_finish_close(ch);
- tt_int_op(ch->state, ==, CHANNEL_STATE_CLOSED);
+ tt_int_op(ch->state, OP_EQ, CHANNEL_STATE_CLOSED);
channel_run_cleanup();
ch = NULL;
@@ -1066,20 +1069,20 @@ test_channel_lifecycle_2(void *arg)
tt_assert(ch->registered);
/* Finish opening it */
- channel_change_state(ch, CHANNEL_STATE_OPEN);
- tt_int_op(ch->state, ==, CHANNEL_STATE_OPEN);
+ channel_change_state_open(ch);
+ tt_int_op(ch->state, OP_EQ, CHANNEL_STATE_OPEN);
/* Go to maintenance state */
channel_change_state(ch, CHANNEL_STATE_MAINT);
- tt_int_op(ch->state, ==, CHANNEL_STATE_MAINT);
+ tt_int_op(ch->state, OP_EQ, CHANNEL_STATE_MAINT);
/* Lower layer close */
channel_close_from_lower_layer(ch);
- tt_int_op(ch->state, ==, CHANNEL_STATE_CLOSING);
+ tt_int_op(ch->state, OP_EQ, CHANNEL_STATE_CLOSING);
/* Finish */
chan_test_finish_close(ch);
- tt_int_op(ch->state, ==, CHANNEL_STATE_CLOSED);
+ tt_int_op(ch->state, OP_EQ, CHANNEL_STATE_CLOSED);
channel_run_cleanup();
ch = NULL;
@@ -1092,20 +1095,20 @@ test_channel_lifecycle_2(void *arg)
tt_assert(ch->registered);
/* Finish opening it */
- channel_change_state(ch, CHANNEL_STATE_OPEN);
- tt_int_op(ch->state, ==, CHANNEL_STATE_OPEN);
+ channel_change_state_open(ch);
+ tt_int_op(ch->state, OP_EQ, CHANNEL_STATE_OPEN);
/* Go to maintenance state */
channel_change_state(ch, CHANNEL_STATE_MAINT);
- tt_int_op(ch->state, ==, CHANNEL_STATE_MAINT);
+ tt_int_op(ch->state, OP_EQ, CHANNEL_STATE_MAINT);
/* Lower layer close */
chan_test_error(ch);
- tt_int_op(ch->state, ==, CHANNEL_STATE_CLOSING);
+ tt_int_op(ch->state, OP_EQ, CHANNEL_STATE_CLOSING);
/* Finish */
chan_test_finish_close(ch);
- tt_int_op(ch->state, ==, CHANNEL_STATE_ERROR);
+ tt_int_op(ch->state, OP_EQ, CHANNEL_STATE_ERROR);
channel_run_cleanup();
ch = NULL;
@@ -1142,11 +1145,11 @@ test_channel_multi(void *arg)
/* Initial queue size update */
channel_update_xmit_queue_size(ch1);
- tt_u64_op(ch1->bytes_queued_for_xmit, ==, 0);
+ tt_u64_op(ch1->bytes_queued_for_xmit, OP_EQ, 0);
channel_update_xmit_queue_size(ch2);
- tt_u64_op(ch2->bytes_queued_for_xmit, ==, 0);
+ tt_u64_op(ch2->bytes_queued_for_xmit, OP_EQ, 0);
global_queue_estimate = channel_get_global_queue_estimate();
- tt_u64_op(global_queue_estimate, ==, 0);
+ tt_u64_op(global_queue_estimate, OP_EQ, 0);
/* Queue some cells, check queue estimates */
cell = tor_malloc_zero(sizeof(cell_t));
@@ -1159,10 +1162,10 @@ test_channel_multi(void *arg)
channel_update_xmit_queue_size(ch1);
channel_update_xmit_queue_size(ch2);
- tt_u64_op(ch1->bytes_queued_for_xmit, ==, 0);
- tt_u64_op(ch2->bytes_queued_for_xmit, ==, 0);
+ tt_u64_op(ch1->bytes_queued_for_xmit, OP_EQ, 0);
+ tt_u64_op(ch2->bytes_queued_for_xmit, OP_EQ, 0);
global_queue_estimate = channel_get_global_queue_estimate();
- tt_u64_op(global_queue_estimate, ==, 0);
+ tt_u64_op(global_queue_estimate, OP_EQ, 0);
/* Stop accepting cells at lower layer */
test_chan_accept_cells = 0;
@@ -1173,18 +1176,18 @@ test_channel_multi(void *arg)
channel_write_cell(ch1, cell);
channel_update_xmit_queue_size(ch1);
- tt_u64_op(ch1->bytes_queued_for_xmit, ==, 512);
+ tt_u64_op(ch1->bytes_queued_for_xmit, OP_EQ, 512);
global_queue_estimate = channel_get_global_queue_estimate();
- tt_u64_op(global_queue_estimate, ==, 512);
+ tt_u64_op(global_queue_estimate, OP_EQ, 512);
cell = tor_malloc_zero(sizeof(cell_t));
make_fake_cell(cell);
channel_write_cell(ch2, cell);
channel_update_xmit_queue_size(ch2);
- tt_u64_op(ch2->bytes_queued_for_xmit, ==, 512);
+ tt_u64_op(ch2->bytes_queued_for_xmit, OP_EQ, 512);
global_queue_estimate = channel_get_global_queue_estimate();
- tt_u64_op(global_queue_estimate, ==, 1024);
+ tt_u64_op(global_queue_estimate, OP_EQ, 1024);
/* Allow cells through again */
test_chan_accept_cells = 1;
@@ -1195,10 +1198,10 @@ test_channel_multi(void *arg)
/* Update and check queue sizes */
channel_update_xmit_queue_size(ch1);
channel_update_xmit_queue_size(ch2);
- tt_u64_op(ch1->bytes_queued_for_xmit, ==, 512);
- tt_u64_op(ch2->bytes_queued_for_xmit, ==, 0);
+ tt_u64_op(ch1->bytes_queued_for_xmit, OP_EQ, 512);
+ tt_u64_op(ch2->bytes_queued_for_xmit, OP_EQ, 0);
global_queue_estimate = channel_get_global_queue_estimate();
- tt_u64_op(global_queue_estimate, ==, 512);
+ tt_u64_op(global_queue_estimate, OP_EQ, 512);
/* Flush chan 1 */
channel_flush_cells(ch1);
@@ -1206,10 +1209,10 @@ test_channel_multi(void *arg)
/* Update and check queue sizes */
channel_update_xmit_queue_size(ch1);
channel_update_xmit_queue_size(ch2);
- tt_u64_op(ch1->bytes_queued_for_xmit, ==, 0);
- tt_u64_op(ch2->bytes_queued_for_xmit, ==, 0);
+ tt_u64_op(ch1->bytes_queued_for_xmit, OP_EQ, 0);
+ tt_u64_op(ch2->bytes_queued_for_xmit, OP_EQ, 0);
global_queue_estimate = channel_get_global_queue_estimate();
- tt_u64_op(global_queue_estimate, ==, 0);
+ tt_u64_op(global_queue_estimate, OP_EQ, 0);
/* Now block again */
test_chan_accept_cells = 0;
@@ -1227,10 +1230,10 @@ test_channel_multi(void *arg)
/* Check the estimates */
channel_update_xmit_queue_size(ch1);
channel_update_xmit_queue_size(ch2);
- tt_u64_op(ch1->bytes_queued_for_xmit, ==, 512);
- tt_u64_op(ch2->bytes_queued_for_xmit, ==, 512);
+ tt_u64_op(ch1->bytes_queued_for_xmit, OP_EQ, 512);
+ tt_u64_op(ch2->bytes_queued_for_xmit, OP_EQ, 512);
global_queue_estimate = channel_get_global_queue_estimate();
- tt_u64_op(global_queue_estimate, ==, 1024);
+ tt_u64_op(global_queue_estimate, OP_EQ, 1024);
/* Now close channel 2; it should be subtracted from the global queue */
MOCK(scheduler_release_channel, scheduler_release_channel_mock);
@@ -1238,7 +1241,7 @@ test_channel_multi(void *arg)
UNMOCK(scheduler_release_channel);
global_queue_estimate = channel_get_global_queue_estimate();
- tt_u64_op(global_queue_estimate, ==, 512);
+ tt_u64_op(global_queue_estimate, OP_EQ, 512);
/*
* Since the fake channels aren't registered, channel_free_all() can't
@@ -1249,7 +1252,7 @@ test_channel_multi(void *arg)
UNMOCK(scheduler_release_channel);
global_queue_estimate = channel_get_global_queue_estimate();
- tt_u64_op(global_queue_estimate, ==, 0);
+ tt_u64_op(global_queue_estimate, OP_EQ, 0);
/* Now free everything */
MOCK(scheduler_release_channel, scheduler_release_channel_mock);
@@ -1297,7 +1300,7 @@ test_channel_queue_impossible(void *arg)
old_count = test_cells_written;
/* Assert that the queue is initially empty */
- tt_int_op(chan_cell_queue_len(&(ch->outgoing_queue)), ==, 0);
+ tt_int_op(chan_cell_queue_len(&(ch->outgoing_queue)), OP_EQ, 0);
/* Get a fresh cell and write it to the channel*/
cell = tor_malloc_zero(sizeof(cell_t));
@@ -1306,11 +1309,11 @@ test_channel_queue_impossible(void *arg)
channel_write_cell(ch, cell);
/* Now it should be queued */
- tt_int_op(chan_cell_queue_len(&(ch->outgoing_queue)), ==, 1);
+ tt_int_op(chan_cell_queue_len(&(ch->outgoing_queue)), OP_EQ, 1);
q = TOR_SIMPLEQ_FIRST(&(ch->outgoing_queue));
tt_assert(q);
if (q) {
- tt_int_op(q->type, ==, CELL_QUEUE_FIXED);
+ tt_int_op(q->type, OP_EQ, CELL_QUEUE_FIXED);
tt_assert((uintptr_t)q->u.fixed.cell == cellintptr);
}
/* Do perverse things to it */
@@ -1322,9 +1325,9 @@ test_channel_queue_impossible(void *arg)
* gets thrown away properly.
*/
test_chan_accept_cells = 1;
- channel_change_state(ch, CHANNEL_STATE_OPEN);
+ channel_change_state_open(ch);
tt_assert(test_cells_written == old_count);
- tt_int_op(chan_cell_queue_len(&(ch->outgoing_queue)), ==, 0);
+ tt_int_op(chan_cell_queue_len(&(ch->outgoing_queue)), OP_EQ, 0);
/* Same thing but for a var_cell */
@@ -1336,11 +1339,11 @@ test_channel_queue_impossible(void *arg)
channel_write_var_cell(ch, var_cell);
/* Check that it's queued */
- tt_int_op(chan_cell_queue_len(&(ch->outgoing_queue)), ==, 1);
+ tt_int_op(chan_cell_queue_len(&(ch->outgoing_queue)), OP_EQ, 1);
q = TOR_SIMPLEQ_FIRST(&(ch->outgoing_queue));
tt_assert(q);
if (q) {
- tt_int_op(q->type, ==, CELL_QUEUE_VAR);
+ tt_int_op(q->type, OP_EQ, CELL_QUEUE_VAR);
tt_assert((uintptr_t)q->u.var.var_cell == cellintptr);
}
@@ -1350,9 +1353,9 @@ test_channel_queue_impossible(void *arg)
/* Let it drain and check that the bad entry is discarded */
test_chan_accept_cells = 1;
- channel_change_state(ch, CHANNEL_STATE_OPEN);
+ channel_change_state_open(ch);
tt_assert(test_cells_written == old_count);
- tt_int_op(chan_cell_queue_len(&(ch->outgoing_queue)), ==, 0);
+ tt_int_op(chan_cell_queue_len(&(ch->outgoing_queue)), OP_EQ, 0);
/* Same thing with a packed_cell */
@@ -1364,11 +1367,11 @@ test_channel_queue_impossible(void *arg)
channel_write_packed_cell(ch, packed_cell);
/* Check that it's queued */
- tt_int_op(chan_cell_queue_len(&(ch->outgoing_queue)), ==, 1);
+ tt_int_op(chan_cell_queue_len(&(ch->outgoing_queue)), OP_EQ, 1);
q = TOR_SIMPLEQ_FIRST(&(ch->outgoing_queue));
tt_assert(q);
if (q) {
- tt_int_op(q->type, ==, CELL_QUEUE_PACKED);
+ tt_int_op(q->type, OP_EQ, CELL_QUEUE_PACKED);
tt_assert((uintptr_t)q->u.packed.packed_cell == cellintptr);
}
@@ -1378,9 +1381,9 @@ test_channel_queue_impossible(void *arg)
/* Let it drain and check that the bad entry is discarded */
test_chan_accept_cells = 1;
- channel_change_state(ch, CHANNEL_STATE_OPEN);
+ channel_change_state_open(ch);
tt_assert(test_cells_written == old_count);
- tt_int_op(chan_cell_queue_len(&(ch->outgoing_queue)), ==, 0);
+ tt_int_op(chan_cell_queue_len(&(ch->outgoing_queue)), OP_EQ, 0);
/* Unknown cell type case */
test_chan_accept_cells = 0;
@@ -1391,11 +1394,11 @@ test_channel_queue_impossible(void *arg)
channel_write_cell(ch, cell);
/* Check that it's queued */
- tt_int_op(chan_cell_queue_len(&(ch->outgoing_queue)), ==, 1);
+ tt_int_op(chan_cell_queue_len(&(ch->outgoing_queue)), OP_EQ, 1);
q = TOR_SIMPLEQ_FIRST(&(ch->outgoing_queue));
tt_assert(q);
if (q) {
- tt_int_op(q->type, ==, CELL_QUEUE_FIXED);
+ tt_int_op(q->type, OP_EQ, CELL_QUEUE_FIXED);
tt_assert((uintptr_t)q->u.fixed.cell == cellintptr);
}
/* Clobber it, including the queue entry type */
@@ -1405,9 +1408,13 @@ test_channel_queue_impossible(void *arg)
/* Let it drain and check that the bad entry is discarded */
test_chan_accept_cells = 1;
- channel_change_state(ch, CHANNEL_STATE_OPEN);
+ tor_capture_bugs_(1);
+ channel_change_state_open(ch);
tt_assert(test_cells_written == old_count);
- tt_int_op(chan_cell_queue_len(&(ch->outgoing_queue)), ==, 0);
+ tt_int_op(chan_cell_queue_len(&(ch->outgoing_queue)), OP_EQ, 0);
+
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1);
+ tor_end_capture_bugs_();
done:
free_fake_channel(ch);
@@ -1451,16 +1458,16 @@ test_channel_queue_incoming(void *arg)
ch->cmux = circuitmux_alloc();
/* Test cell handler getters */
- tt_ptr_op(channel_get_cell_handler(ch), ==, NULL);
- tt_ptr_op(channel_get_var_cell_handler(ch), ==, NULL);
+ tt_ptr_op(channel_get_cell_handler(ch), OP_EQ, NULL);
+ tt_ptr_op(channel_get_var_cell_handler(ch), OP_EQ, NULL);
/* Try to register it */
channel_register(ch);
tt_assert(ch->registered);
/* Open it */
- channel_change_state(ch, CHANNEL_STATE_OPEN);
- tt_int_op(ch->state, ==, CHANNEL_STATE_OPEN);
+ channel_change_state_open(ch);
+ tt_int_op(ch->state, OP_EQ, CHANNEL_STATE_OPEN);
/* Assert that the incoming queue is empty */
tt_assert(TOR_SIMPLEQ_EMPTY(&(ch->incoming_queue)));
@@ -1471,7 +1478,7 @@ test_channel_queue_incoming(void *arg)
channel_queue_cell(ch, cell);
/* Assert that the incoming queue has one entry */
- tt_int_op(chan_cell_queue_len(&(ch->incoming_queue)), ==, 1);
+ tt_int_op(chan_cell_queue_len(&(ch->incoming_queue)), OP_EQ, 1);
/* Queue an incoming var cell */
var_cell = tor_malloc_zero(sizeof(var_cell_t) + CELL_PAYLOAD_SIZE);
@@ -1479,7 +1486,7 @@ test_channel_queue_incoming(void *arg)
channel_queue_var_cell(ch, var_cell);
/* Assert that the incoming queue has two entries */
- tt_int_op(chan_cell_queue_len(&(ch->incoming_queue)), ==, 2);
+ tt_int_op(chan_cell_queue_len(&(ch->incoming_queue)), OP_EQ, 2);
/*
* Install cell handlers; this will drain the queue, so save the old
@@ -1490,12 +1497,13 @@ test_channel_queue_incoming(void *arg)
channel_set_cell_handlers(ch,
chan_test_cell_handler,
chan_test_var_cell_handler);
- tt_ptr_op(channel_get_cell_handler(ch), ==, chan_test_cell_handler);
- tt_ptr_op(channel_get_var_cell_handler(ch), ==, chan_test_var_cell_handler);
+ tt_ptr_op(channel_get_cell_handler(ch), OP_EQ, chan_test_cell_handler);
+ tt_ptr_op(channel_get_var_cell_handler(ch), OP_EQ,
+ chan_test_var_cell_handler);
/* Assert cells were received */
- tt_int_op(test_chan_fixed_cells_recved, ==, old_fixed_count + 1);
- tt_int_op(test_chan_var_cells_recved, ==, old_var_count + 1);
+ tt_int_op(test_chan_fixed_cells_recved, OP_EQ, old_fixed_count + 1);
+ tt_int_op(test_chan_var_cells_recved, OP_EQ, old_var_count + 1);
/*
* Assert that the pointers are different from the cells we allocated;
@@ -1504,17 +1512,17 @@ test_channel_queue_incoming(void *arg)
* delivery. These pointers will have already been freed by the time
* we get here, so don't dereference them.
*/
- tt_ptr_op(test_chan_last_seen_fixed_cell_ptr, !=, cell);
- tt_ptr_op(test_chan_last_seen_var_cell_ptr, !=, var_cell);
+ tt_ptr_op(test_chan_last_seen_fixed_cell_ptr, OP_NE, cell);
+ tt_ptr_op(test_chan_last_seen_var_cell_ptr, OP_NE, var_cell);
/* Assert queue is now empty */
tt_assert(TOR_SIMPLEQ_EMPTY(&(ch->incoming_queue)));
/* Close it; this contains an assertion that the incoming queue is empty */
channel_mark_for_close(ch);
- tt_int_op(ch->state, ==, CHANNEL_STATE_CLOSING);
+ tt_int_op(ch->state, OP_EQ, CHANNEL_STATE_CLOSING);
chan_test_finish_close(ch);
- tt_int_op(ch->state, ==, CHANNEL_STATE_CLOSED);
+ tt_int_op(ch->state, OP_EQ, CHANNEL_STATE_CLOSED);
channel_run_cleanup();
ch = NULL;
@@ -1544,14 +1552,14 @@ test_channel_queue_size(void *arg)
/* Initial queue size update */
channel_update_xmit_queue_size(ch);
- tt_u64_op(ch->bytes_queued_for_xmit, ==, 0);
+ tt_u64_op(ch->bytes_queued_for_xmit, OP_EQ, 0);
global_queue_estimate = channel_get_global_queue_estimate();
- tt_u64_op(global_queue_estimate, ==, 0);
+ tt_u64_op(global_queue_estimate, OP_EQ, 0);
/* Test the call-through to our fake lower layer */
n = channel_num_cells_writeable(ch);
/* chan_test_num_cells_writeable() always returns 32 */
- tt_int_op(n, ==, 32);
+ tt_int_op(n, OP_EQ, 32);
/*
* Now we queue some cells and check that channel_num_cells_writeable()
@@ -1570,72 +1578,73 @@ test_channel_queue_size(void *arg)
old_count = test_cells_written;
channel_write_cell(ch, cell);
/* Assert that it got queued, not written through, correctly */
- tt_int_op(test_cells_written, ==, old_count);
+ tt_int_op(test_cells_written, OP_EQ, old_count);
/* Now check chan_test_num_cells_writeable() again */
n = channel_num_cells_writeable(ch);
- tt_int_op(n, ==, 0); /* Should return 0 since we're in CHANNEL_STATE_MAINT */
+ /* Should return 0 since we're in CHANNEL_STATE_MAINT */
+ tt_int_op(n, OP_EQ, 0);
/* Update queue size estimates */
channel_update_xmit_queue_size(ch);
/* One cell, times an overhead factor of 1.0 */
- tt_u64_op(ch->bytes_queued_for_xmit, ==, 512);
+ tt_u64_op(ch->bytes_queued_for_xmit, OP_EQ, 512);
/* Try a different overhead factor */
test_overhead_estimate = 0.5;
/* This one should be ignored since it's below 1.0 */
channel_update_xmit_queue_size(ch);
- tt_u64_op(ch->bytes_queued_for_xmit, ==, 512);
+ tt_u64_op(ch->bytes_queued_for_xmit, OP_EQ, 512);
/* Now try a larger one */
test_overhead_estimate = 2.0;
channel_update_xmit_queue_size(ch);
- tt_u64_op(ch->bytes_queued_for_xmit, ==, 1024);
+ tt_u64_op(ch->bytes_queued_for_xmit, OP_EQ, 1024);
/* Go back to 1.0 */
test_overhead_estimate = 1.0;
channel_update_xmit_queue_size(ch);
- tt_u64_op(ch->bytes_queued_for_xmit, ==, 512);
+ tt_u64_op(ch->bytes_queued_for_xmit, OP_EQ, 512);
/* Check the global estimate too */
global_queue_estimate = channel_get_global_queue_estimate();
- tt_u64_op(global_queue_estimate, ==, 512);
+ tt_u64_op(global_queue_estimate, OP_EQ, 512);
/* Go to open */
old_count = test_cells_written;
- channel_change_state(ch, CHANNEL_STATE_OPEN);
+ channel_change_state_open(ch);
/*
* It should try to write, but we aren't accepting cells right now, so
* it'll requeue
*/
- tt_int_op(test_cells_written, ==, old_count);
+ tt_int_op(test_cells_written, OP_EQ, old_count);
/* Check the queue size again */
channel_update_xmit_queue_size(ch);
- tt_u64_op(ch->bytes_queued_for_xmit, ==, 512);
+ tt_u64_op(ch->bytes_queued_for_xmit, OP_EQ, 512);
global_queue_estimate = channel_get_global_queue_estimate();
- tt_u64_op(global_queue_estimate, ==, 512);
+ tt_u64_op(global_queue_estimate, OP_EQ, 512);
/*
* Now the cell is in the queue, and we're open, so we should get 31
* writeable cells.
*/
n = channel_num_cells_writeable(ch);
- tt_int_op(n, ==, 31);
+ tt_int_op(n, OP_EQ, 31);
/* Accept cells again */
test_chan_accept_cells = 1;
/* ...and re-process the queue */
old_count = test_cells_written;
channel_flush_cells(ch);
- tt_int_op(test_cells_written, ==, old_count + 1);
+ tt_int_op(test_cells_written, OP_EQ, old_count + 1);
/* Should have 32 writeable now */
n = channel_num_cells_writeable(ch);
- tt_int_op(n, ==, 32);
+ tt_int_op(n, OP_EQ, 32);
/* Should have queue size estimate of zero */
channel_update_xmit_queue_size(ch);
- tt_u64_op(ch->bytes_queued_for_xmit, ==, 0);
+ tt_u64_op(ch->bytes_queued_for_xmit, OP_EQ, 0);
global_queue_estimate = channel_get_global_queue_estimate();
- tt_u64_op(global_queue_estimate, ==, 0);
+ tt_u64_op(global_queue_estimate, OP_EQ, 0);
/* Okay, now we're done with this one */
MOCK(scheduler_release_channel, scheduler_release_channel_mock);
@@ -1702,7 +1711,7 @@ test_channel_write(void *arg)
* gets drained from the queue.
*/
test_chan_accept_cells = 1;
- channel_change_state(ch, CHANNEL_STATE_OPEN);
+ channel_change_state_open(ch);
tt_assert(test_cells_written == old_count + 1);
/*
@@ -1764,6 +1773,112 @@ test_channel_write(void *arg)
return;
}
+static void
+test_channel_id_map(void *arg)
+{
+ (void)arg;
+#define N_CHAN 6
+ char rsa_id[N_CHAN][DIGEST_LEN];
+ ed25519_public_key_t *ed_id[N_CHAN];
+ channel_t *chan[N_CHAN];
+ int i;
+ ed25519_public_key_t ed_zero;
+ memset(&ed_zero, 0, sizeof(ed_zero));
+
+ tt_int_op(DIGEST_LEN, OP_EQ, sizeof(rsa_id[0])); // Do I remember C?
+
+ for (i = 0; i < N_CHAN; ++i) {
+ crypto_rand(rsa_id[i], DIGEST_LEN);
+ ed_id[i] = tor_malloc_zero(sizeof(*ed_id[i]));
+ crypto_rand((char*)ed_id[i]->pubkey, sizeof(ed_id[i]->pubkey));
+ }
+
+ /* For channel 3, have no Ed identity. */
+ tor_free(ed_id[3]);
+
+ /* Channel 2 and 4 have same ROSA identity */
+ memcpy(rsa_id[4], rsa_id[2], DIGEST_LEN);
+
+ /* Channel 2 and 4 and 5 have same RSA identity */
+ memcpy(rsa_id[4], rsa_id[2], DIGEST_LEN);
+ memcpy(rsa_id[5], rsa_id[2], DIGEST_LEN);
+
+ /* Channels 2 and 5 have same Ed25519 identity */
+ memcpy(ed_id[5], ed_id[2], sizeof(*ed_id[2]));
+
+ for (i = 0; i < N_CHAN; ++i) {
+ chan[i] = new_fake_channel();
+ channel_register(chan[i]);
+ channel_set_identity_digest(chan[i], rsa_id[i], ed_id[i]);
+ }
+
+ /* Lookup by RSA id only */
+ tt_ptr_op(chan[0], OP_EQ,
+ channel_find_by_remote_identity(rsa_id[0], NULL));
+ tt_ptr_op(chan[1], OP_EQ,
+ channel_find_by_remote_identity(rsa_id[1], NULL));
+ tt_ptr_op(chan[3], OP_EQ,
+ channel_find_by_remote_identity(rsa_id[3], NULL));
+ channel_t *ch;
+ ch = channel_find_by_remote_identity(rsa_id[2], NULL);
+ tt_assert(ch == chan[2] || ch == chan[4] || ch == chan[5]);
+ ch = channel_next_with_rsa_identity(ch);
+ tt_assert(ch == chan[2] || ch == chan[4] || ch == chan[5]);
+ ch = channel_next_with_rsa_identity(ch);
+ tt_assert(ch == chan[2] || ch == chan[4] || ch == chan[5]);
+ ch = channel_next_with_rsa_identity(ch);
+ tt_ptr_op(ch, OP_EQ, NULL);
+
+ /* As above, but with zero Ed25519 ID (meaning "any ID") */
+ tt_ptr_op(chan[0], OP_EQ,
+ channel_find_by_remote_identity(rsa_id[0], &ed_zero));
+ tt_ptr_op(chan[1], OP_EQ,
+ channel_find_by_remote_identity(rsa_id[1], &ed_zero));
+ tt_ptr_op(chan[3], OP_EQ,
+ channel_find_by_remote_identity(rsa_id[3], &ed_zero));
+ ch = channel_find_by_remote_identity(rsa_id[2], &ed_zero);
+ tt_assert(ch == chan[2] || ch == chan[4] || ch == chan[5]);
+ ch = channel_next_with_rsa_identity(ch);
+ tt_assert(ch == chan[2] || ch == chan[4] || ch == chan[5]);
+ ch = channel_next_with_rsa_identity(ch);
+ tt_assert(ch == chan[2] || ch == chan[4] || ch == chan[5]);
+ ch = channel_next_with_rsa_identity(ch);
+ tt_ptr_op(ch, OP_EQ, NULL);
+
+ /* Lookup nonexistent RSA identity */
+ tt_ptr_op(NULL, OP_EQ,
+ channel_find_by_remote_identity("!!!!!!!!!!!!!!!!!!!!", NULL));
+
+ /* Look up by full identity pair */
+ tt_ptr_op(chan[0], OP_EQ,
+ channel_find_by_remote_identity(rsa_id[0], ed_id[0]));
+ tt_ptr_op(chan[1], OP_EQ,
+ channel_find_by_remote_identity(rsa_id[1], ed_id[1]));
+ tt_ptr_op(chan[3], OP_EQ,
+ channel_find_by_remote_identity(rsa_id[3], ed_id[3] /*NULL*/));
+ tt_ptr_op(chan[4], OP_EQ,
+ channel_find_by_remote_identity(rsa_id[4], ed_id[4]));
+ ch = channel_find_by_remote_identity(rsa_id[2], ed_id[2]);
+ tt_assert(ch == chan[2] || ch == chan[5]);
+
+ /* Look up RSA identity with wrong ed25519 identity */
+ tt_ptr_op(NULL, OP_EQ,
+ channel_find_by_remote_identity(rsa_id[4], ed_id[0]));
+ tt_ptr_op(NULL, OP_EQ,
+ channel_find_by_remote_identity(rsa_id[2], ed_id[1]));
+ tt_ptr_op(NULL, OP_EQ,
+ channel_find_by_remote_identity(rsa_id[3], ed_id[1]));
+
+ done:
+ for (i = 0; i < N_CHAN; ++i) {
+ channel_clear_identity_digest(chan[i]);
+ channel_unregister(chan[i]);
+ free_fake_channel(chan[i]);
+ tor_free(ed_id[i]);
+ }
+#undef N_CHAN
+}
+
struct testcase_t channel_tests[] = {
{ "dumpstats", test_channel_dumpstats, TT_FORK, NULL, NULL },
{ "flush", test_channel_flush, TT_FORK, NULL, NULL },
@@ -1776,6 +1891,7 @@ struct testcase_t channel_tests[] = {
{ "queue_incoming", test_channel_queue_incoming, TT_FORK, NULL, NULL },
{ "queue_size", test_channel_queue_size, TT_FORK, NULL, NULL },
{ "write", test_channel_write, TT_FORK, NULL, NULL },
+ { "id_map", test_channel_id_map, TT_FORK, NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_channelpadding.c b/src/test/test_channelpadding.c
new file mode 100644
index 0000000000..391ead3c72
--- /dev/null
+++ b/src/test/test_channelpadding.c
@@ -0,0 +1,1133 @@
+#define TOR_CHANNEL_INTERNAL_
+#define MAIN_PRIVATE
+#define NETWORKSTATUS_PRIVATE
+#define TOR_TIMERS_PRIVATE
+#include "or.h"
+#include "test.h"
+#include "testsupport.h"
+#include "connection.h"
+#include "connection_or.h"
+#include "channel.h"
+#include "channeltls.h"
+#include "channelpadding.h"
+#include "compat_libevent.h"
+#include "config.h"
+#include <event2/event.h>
+#include "compat_time.h"
+#include "main.h"
+#include "networkstatus.h"
+#include "log_test_helpers.h"
+
+int channelpadding_get_netflow_inactive_timeout_ms(channel_t *chan);
+int64_t channelpadding_compute_time_until_pad_for_netflow(channel_t *chan);
+int channelpadding_send_disable_command(channel_t*);
+int channelpadding_find_timerslot(channel_t *chan);
+
+void test_channelpadding_timers(void *arg);
+void test_channelpadding_consensus(void *arg);
+void test_channelpadding_negotiation(void *arg);
+void test_channelpadding_decide_to_pad_channel(void *arg);
+void test_channelpadding_killonehop(void *arg);
+
+void dummy_nop_timer(void);
+
+#define NSEC_PER_MSEC (1000*1000)
+
+/* Thing to cast to fake tor_tls_t * to appease assert_connection_ok() */
+static int fake_tortls = 0; /* Bleh... */
+
+static int dont_stop_libevent = 0;
+
+// From test_channel.c
+channel_t * new_fake_channel(void);
+void free_fake_channel(channel_t*);
+
+static int
+mock_channel_has_queued_writes(channel_t *chan)
+{
+ (void)chan;
+ return 0;
+}
+
+static int tried_to_write_cell = 0;
+
+static channel_t *relay1_relay2;
+static channel_t *relay2_relay1;
+static channel_t *relay3_client;
+static channel_t *client_relay3;
+
+static int
+mock_channel_write_cell_relay2(channel_t *chan, cell_t *cell)
+{
+ (void)chan;
+ tried_to_write_cell++;
+ channel_tls_handle_cell(cell, ((channel_tls_t*)relay1_relay2)->conn);
+ event_base_loopbreak(tor_libevent_get_base());
+ return 0;
+}
+
+static int
+mock_channel_write_cell_relay1(channel_t *chan, cell_t *cell)
+{
+ (void)chan;
+ tried_to_write_cell++;
+ channel_tls_handle_cell(cell, ((channel_tls_t*)relay2_relay1)->conn);
+ event_base_loopbreak(tor_libevent_get_base());
+ return 0;
+}
+
+static int
+mock_channel_write_cell_relay3(channel_t *chan, cell_t *cell)
+{
+ (void)chan;
+ tried_to_write_cell++;
+ channel_tls_handle_cell(cell, ((channel_tls_t*)client_relay3)->conn);
+ event_base_loopbreak(tor_libevent_get_base());
+ return 0;
+}
+
+static int
+mock_channel_write_cell_client(channel_t *chan, cell_t *cell)
+{
+ (void)chan;
+ tried_to_write_cell++;
+ channel_tls_handle_cell(cell, ((channel_tls_t*)relay3_client)->conn);
+ event_base_loopbreak(tor_libevent_get_base());
+ return 0;
+}
+
+static int
+mock_channel_write_cell(channel_t *chan, cell_t *cell)
+{
+ tried_to_write_cell++;
+ channel_tls_handle_cell(cell, ((channel_tls_t*)chan)->conn);
+ if (!dont_stop_libevent)
+ event_base_loopbreak(tor_libevent_get_base());
+ return 0;
+}
+
+static void
+setup_fake_connection_for_channel(channel_tls_t *chan)
+{
+ or_connection_t *conn = (or_connection_t*)connection_new(CONN_TYPE_OR,
+ AF_INET);
+
+ conn->base_.conn_array_index = smartlist_len(connection_array);
+ smartlist_add(connection_array, conn);
+
+ conn->chan = chan;
+ chan->conn = conn;
+
+ conn->base_.magic = OR_CONNECTION_MAGIC;
+ conn->base_.state = OR_CONN_STATE_OPEN;
+ conn->base_.type = CONN_TYPE_OR;
+ conn->base_.socket_family = AF_INET;
+ conn->base_.address = tor_strdup("<fake>");
+
+ conn->base_.port = 4242;
+
+ conn->tls = (tor_tls_t *)((void *)(&fake_tortls));
+
+ conn->link_proto = MIN_LINK_PROTO_FOR_CHANNEL_PADDING;
+
+ connection_or_set_canonical(conn, 1);
+}
+
+static channel_tls_t *
+new_fake_channeltls(uint8_t id)
+{
+ channel_tls_t *chan = tor_realloc(new_fake_channel(), sizeof(channel_tls_t));
+ chan->base_.magic = TLS_CHAN_MAGIC;
+ setup_fake_connection_for_channel(chan);
+ chan->base_.channel_usage = CHANNEL_USED_FOR_FULL_CIRCS;
+ chan->base_.has_queued_writes = mock_channel_has_queued_writes;
+ chan->base_.write_cell = mock_channel_write_cell;
+ chan->base_.padding_enabled = 1;
+
+ chan->base_.identity_digest[0] = id;
+ channel_register(&chan->base_);
+
+ return chan;
+}
+
+static void
+free_fake_channeltls(channel_tls_t *chan)
+{
+ channel_unregister(&chan->base_);
+
+ tor_free(((channel_tls_t*)chan)->conn->base_.address);
+ buf_free(((channel_tls_t*)chan)->conn->base_.inbuf);
+ buf_free(((channel_tls_t*)chan)->conn->base_.outbuf);
+ tor_free(((channel_tls_t*)chan)->conn);
+
+ timer_free(chan->base_.padding_timer);
+ channel_handle_free(chan->base_.timer_handle);
+ channel_handles_clear(&chan->base_);
+
+ free_fake_channel(&chan->base_);
+
+ return;
+}
+
+static void
+setup_mock_consensus(void)
+{
+ current_md_consensus = current_ns_consensus
+ = tor_malloc_zero(sizeof(networkstatus_t));
+ current_md_consensus->net_params = smartlist_new();
+ current_md_consensus->routerstatus_list = smartlist_new();
+ channelpadding_new_consensus_params(current_md_consensus);
+}
+
+static void
+free_mock_consensus(void)
+{
+ SMARTLIST_FOREACH(current_md_consensus->routerstatus_list, void *, r,
+ tor_free(r));
+ smartlist_free(current_md_consensus->routerstatus_list);
+ smartlist_free(current_ns_consensus->net_params);
+ tor_free(current_ns_consensus);
+}
+
+static void
+setup_mock_network(void)
+{
+ routerstatus_t *relay;
+ if (!connection_array)
+ connection_array = smartlist_new();
+
+ relay1_relay2 = (channel_t*)new_fake_channeltls(2);
+ relay1_relay2->write_cell = mock_channel_write_cell_relay1;
+ channel_timestamp_active(relay1_relay2);
+ relay = tor_malloc_zero(sizeof(routerstatus_t));
+ relay->identity_digest[0] = 1;
+ smartlist_add(current_md_consensus->routerstatus_list, relay);
+
+ relay2_relay1 = (channel_t*)new_fake_channeltls(1);
+ relay2_relay1->write_cell = mock_channel_write_cell_relay2;
+ channel_timestamp_active(relay2_relay1);
+ relay = tor_malloc_zero(sizeof(routerstatus_t));
+ relay->identity_digest[0] = 2;
+ smartlist_add(current_md_consensus->routerstatus_list, relay);
+
+ relay3_client = (channel_t*)new_fake_channeltls(0);
+ relay3_client->write_cell = mock_channel_write_cell_relay3;
+ relay3_client->is_client = 1;
+ channel_timestamp_active(relay3_client);
+ relay = tor_malloc_zero(sizeof(routerstatus_t));
+ relay->identity_digest[0] = 3;
+ smartlist_add(current_md_consensus->routerstatus_list, relay);
+
+ client_relay3 = (channel_t*)new_fake_channeltls(3);
+ client_relay3->write_cell = mock_channel_write_cell_client;
+ channel_timestamp_active(client_relay3);
+
+ channel_do_open_actions(relay1_relay2);
+ channel_do_open_actions(relay2_relay1);
+ channel_do_open_actions(relay3_client);
+ channel_do_open_actions(client_relay3);
+}
+
+static void
+free_mock_network(void)
+{
+ free_fake_channeltls((channel_tls_t*)relay1_relay2);
+ free_fake_channeltls((channel_tls_t*)relay2_relay1);
+ free_fake_channeltls((channel_tls_t*)relay3_client);
+ free_fake_channeltls((channel_tls_t*)client_relay3);
+
+ smartlist_free(connection_array);
+}
+
+static void
+dummy_timer_cb(tor_timer_t *t, void *arg, const monotime_t *now_mono)
+{
+ (void)t; (void)arg; (void)now_mono;
+ event_base_loopbreak(tor_libevent_get_base());
+ return;
+}
+
+// This hack adds a dummy timer so that the libevent base loop
+// actually returns when we don't expect any timers to fire. Otherwise,
+// the global_timer_event gets scheduled an hour from now, and the
+// base loop never returns.
+void
+dummy_nop_timer(void)
+{
+ tor_timer_t *dummy_timer = timer_new(dummy_timer_cb, NULL);
+ struct timeval timeout;
+ timeout.tv_sec = 1;
+ timeout.tv_usec = 0;
+
+ timer_schedule(dummy_timer, &timeout);
+
+ event_base_loop(tor_libevent_get_base(), 0);
+ timer_free(dummy_timer);
+}
+
+#define CHANNELPADDING_MAX_TIMERS 25
+#define CHANNELS_TO_TEST (CHANNELPADDING_MAX_TIMERS*4)
+/**
+ * Tests to ensure that we handle more than the max number of pending
+ * timers properly.
+ */
+void
+test_channelpadding_timers(void *arg)
+{
+ channelpadding_decision_t decision;
+ channel_t *chans[CHANNELS_TO_TEST];
+ int64_t new_time;
+ (void)arg;
+
+ tor_libevent_postfork();
+
+ if (!connection_array)
+ connection_array = smartlist_new();
+
+ monotime_init();
+ monotime_enable_test_mocking();
+ monotime_set_mock_time_nsec(1);
+ monotime_coarse_set_mock_time_nsec(1);
+
+ timers_initialize();
+ channelpadding_new_consensus_params(NULL);
+
+ for (int i = 0; i < CHANNELS_TO_TEST; i++) {
+ chans[i] = (channel_t*)new_fake_channeltls(0);
+ channel_timestamp_active(chans[i]);
+ }
+
+ for (int j = 0; j < 2; j++) {
+ tried_to_write_cell = 0;
+ int i = 0;
+
+ /* This loop fills our timerslot array with timers of increasing time
+ * until they fire */
+ for (; i < CHANNELPADDING_MAX_TIMERS; i++) {
+ chans[i]->next_padding_time_ms = monotime_coarse_absolute_msec()
+ + 10 + i*4;
+ decision = channelpadding_decide_to_pad_channel(chans[i]);
+ tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED);
+ tt_assert(chans[i]->pending_padding_callback);
+ tt_int_op(tried_to_write_cell, OP_EQ, 0);
+ }
+
+ /* This loop should add timers to the first position in the timerslot
+ * array, since its timeout is before all other timers. */
+ for (; i < CHANNELS_TO_TEST/3; i++) {
+ chans[i]->next_padding_time_ms = monotime_coarse_absolute_msec() + 1;
+ decision = channelpadding_decide_to_pad_channel(chans[i]);
+ tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED);
+ tt_assert(chans[i]->pending_padding_callback);
+ tt_int_op(tried_to_write_cell, OP_EQ, 0);
+ }
+
+ /* This loop should add timers to our existing lists in a weak
+ * pseudorandom pattern. It ensures that the lists can grow with multiple
+ * timers in them. */
+ for (; i < CHANNELS_TO_TEST/2; i++) {
+ chans[i]->next_padding_time_ms = monotime_coarse_absolute_msec() + 10 +
+ i*3 % CHANNELPADDING_MAX_TIMERS;
+ decision = channelpadding_decide_to_pad_channel(chans[i]);
+ tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED);
+ tt_assert(chans[i]->pending_padding_callback);
+ tt_int_op(tried_to_write_cell, OP_EQ, 0);
+ }
+
+ /* This loop should add timers to the last position in the timerslot
+ * array, since its timeout is after all other timers. */
+ for (; i < CHANNELS_TO_TEST; i++) {
+ chans[i]->next_padding_time_ms = monotime_coarse_absolute_msec() + 500 +
+ i % CHANNELPADDING_MAX_TIMERS;
+ decision = channelpadding_decide_to_pad_channel(chans[i]);
+ tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED);
+ tt_assert(chans[i]->pending_padding_callback);
+ tt_int_op(tried_to_write_cell, OP_EQ, 0);
+ }
+
+ // Wait for the timers and then kill the event loop.
+ new_time = (monotime_coarse_absolute_msec()+1001)*NSEC_PER_MSEC;
+ monotime_coarse_set_mock_time_nsec(new_time);
+ monotime_set_mock_time_nsec(new_time);
+ timers_run_pending();
+
+ tt_int_op(tried_to_write_cell, OP_EQ, CHANNELS_TO_TEST);
+
+ // Test that we have no pending callbacks and all empty slots now
+ for (i = 0; i < CHANNELS_TO_TEST; i++) {
+ tt_assert(!chans[i]->pending_padding_callback);
+ }
+ }
+
+ done:
+ for (int i = 0; i < CHANNELS_TO_TEST; i++) {
+ free_fake_channeltls((channel_tls_t*)chans[i]);
+ }
+ smartlist_free(connection_array);
+
+ timers_shutdown();
+ monotime_disable_test_mocking();
+ channel_free_all();
+
+ return;
+}
+
+void
+test_channelpadding_killonehop(void *arg)
+{
+ channelpadding_decision_t decision;
+ int64_t new_time;
+ (void)arg;
+ tor_libevent_postfork();
+
+ routerstatus_t *relay = tor_malloc_zero(sizeof(routerstatus_t));
+ monotime_init();
+ monotime_enable_test_mocking();
+ monotime_set_mock_time_nsec(1);
+ monotime_coarse_set_mock_time_nsec(1);
+
+ timers_initialize();
+ setup_mock_consensus();
+ setup_mock_network();
+
+ /* Do we disable padding if tor2webmode or rsos are enabled, and
+ * the consensus says don't pad? */
+
+ /* Ensure we can kill tor2web and rsos padding if we want. */
+ // First, test that padding works if either is enabled
+ smartlist_clear(current_md_consensus->net_params);
+ channelpadding_new_consensus_params(current_md_consensus);
+
+ tried_to_write_cell = 0;
+ get_options_mutable()->Tor2webMode = 1;
+ client_relay3->next_padding_time_ms = monotime_coarse_absolute_msec() + 100;
+ decision = channelpadding_decide_to_pad_channel(client_relay3);
+ tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED);
+ tt_assert(client_relay3->pending_padding_callback);
+ tt_int_op(tried_to_write_cell, OP_EQ, 0);
+
+ decision = channelpadding_decide_to_pad_channel(client_relay3);
+ tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_ALREADY_SCHEDULED);
+
+ // Wait for the timer
+ new_time = (monotime_coarse_absolute_msec()+101)*NSEC_PER_MSEC;
+ monotime_coarse_set_mock_time_nsec(new_time);
+ monotime_set_mock_time_nsec(new_time);
+ timers_run_pending();
+ tt_int_op(tried_to_write_cell, OP_EQ, 1);
+ tt_assert(!client_relay3->pending_padding_callback);
+
+ // Then test disabling each via consensus param
+ smartlist_add(current_md_consensus->net_params,
+ (void*)"nf_pad_tor2web=0");
+ channelpadding_new_consensus_params(current_md_consensus);
+
+ // Before the client tries to pad, the relay will still pad:
+ tried_to_write_cell = 0;
+ relay3_client->next_padding_time_ms = monotime_coarse_absolute_msec() + 100;
+ get_options_mutable()->ORPort_set = 1;
+ get_options_mutable()->Tor2webMode = 0;
+ decision = channelpadding_decide_to_pad_channel(relay3_client);
+ tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED);
+ tt_assert(relay3_client->pending_padding_callback);
+
+ // Wait for the timer
+ new_time = (monotime_coarse_absolute_msec()+101)*NSEC_PER_MSEC;
+ monotime_coarse_set_mock_time_nsec(new_time);
+ monotime_set_mock_time_nsec(new_time);
+ timers_run_pending();
+ tt_int_op(tried_to_write_cell, OP_EQ, 1);
+ tt_assert(!client_relay3->pending_padding_callback);
+
+ // Test client side (it should stop immediately, but send a negotiate)
+ tried_to_write_cell = 0;
+ tt_assert(relay3_client->padding_enabled);
+ tt_assert(client_relay3->padding_enabled);
+ get_options_mutable()->Tor2webMode = 1;
+ /* For the relay to recieve the negotiate: */
+ get_options_mutable()->ORPort_set = 1;
+ decision = channelpadding_decide_to_pad_channel(client_relay3);
+ tt_int_op(decision, OP_EQ, CHANNELPADDING_WONTPAD);
+ tt_int_op(tried_to_write_cell, OP_EQ, 1);
+ tt_assert(!client_relay3->pending_padding_callback);
+ tt_assert(!relay3_client->padding_enabled);
+
+ // Test relay side (it should have gotten the negotiation to disable)
+ get_options_mutable()->ORPort_set = 1;
+ get_options_mutable()->Tor2webMode = 0;
+ tt_int_op(channelpadding_decide_to_pad_channel(relay3_client), OP_EQ,
+ CHANNELPADDING_WONTPAD);
+ tt_assert(!relay3_client->padding_enabled);
+
+ /* Repeat for SOS */
+ // First, test that padding works if either is enabled
+ smartlist_clear(current_md_consensus->net_params);
+ channelpadding_new_consensus_params(current_md_consensus);
+
+ relay3_client->padding_enabled = 1;
+ client_relay3->padding_enabled = 1;
+
+ tried_to_write_cell = 0;
+ get_options_mutable()->ORPort_set = 0;
+ get_options_mutable()->HiddenServiceSingleHopMode = 1;
+ get_options_mutable()->HiddenServiceNonAnonymousMode = 1;
+ client_relay3->next_padding_time_ms = monotime_coarse_absolute_msec() + 100;
+ decision = channelpadding_decide_to_pad_channel(client_relay3);
+ tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED);
+ tt_assert(client_relay3->pending_padding_callback);
+ tt_int_op(tried_to_write_cell, OP_EQ, 0);
+
+ decision = channelpadding_decide_to_pad_channel(client_relay3);
+ tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_ALREADY_SCHEDULED);
+
+ // Wait for the timer
+ new_time = (monotime_coarse_absolute_msec()+101)*NSEC_PER_MSEC;
+ monotime_coarse_set_mock_time_nsec(new_time);
+ monotime_set_mock_time_nsec(new_time);
+ timers_run_pending();
+ tt_int_op(tried_to_write_cell, OP_EQ, 1);
+ tt_assert(!client_relay3->pending_padding_callback);
+
+ // Then test disabling each via consensus param
+ smartlist_add(current_md_consensus->net_params,
+ (void*)"nf_pad_single_onion=0");
+ channelpadding_new_consensus_params(current_md_consensus);
+
+ // Before the client tries to pad, the relay will still pad:
+ tried_to_write_cell = 0;
+ relay3_client->next_padding_time_ms = monotime_coarse_absolute_msec() + 100;
+ get_options_mutable()->ORPort_set = 1;
+ get_options_mutable()->HiddenServiceSingleHopMode = 0;
+ get_options_mutable()->HiddenServiceNonAnonymousMode = 0;
+ decision = channelpadding_decide_to_pad_channel(relay3_client);
+ tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED);
+ tt_assert(relay3_client->pending_padding_callback);
+
+ // Wait for the timer
+ new_time = (monotime_coarse_absolute_msec()+101)*NSEC_PER_MSEC;
+ monotime_coarse_set_mock_time_nsec(new_time);
+ monotime_set_mock_time_nsec(new_time);
+ timers_run_pending();
+ tt_int_op(tried_to_write_cell, OP_EQ, 1);
+ tt_assert(!client_relay3->pending_padding_callback);
+
+ // Test client side (it should stop immediately)
+ get_options_mutable()->HiddenServiceSingleHopMode = 1;
+ get_options_mutable()->HiddenServiceNonAnonymousMode = 1;
+ /* For the relay to recieve the negotiate: */
+ get_options_mutable()->ORPort_set = 1;
+ decision = channelpadding_decide_to_pad_channel(client_relay3);
+ tt_int_op(decision, OP_EQ, CHANNELPADDING_WONTPAD);
+ tt_assert(!client_relay3->pending_padding_callback);
+
+ // Test relay side (it should have gotten the negotiation to disable)
+ get_options_mutable()->ORPort_set = 1;
+ get_options_mutable()->HiddenServiceSingleHopMode = 0;
+ get_options_mutable()->HiddenServiceNonAnonymousMode = 0;
+ tt_int_op(channelpadding_decide_to_pad_channel(relay3_client), OP_EQ,
+ CHANNELPADDING_WONTPAD);
+ tt_assert(!relay3_client->padding_enabled);
+
+ done:
+ free_mock_consensus();
+ free_mock_network();
+ tor_free(relay);
+
+ timers_shutdown();
+ monotime_disable_test_mocking();
+ channel_free_all();
+}
+
+void
+test_channelpadding_consensus(void *arg)
+{
+ channelpadding_decision_t decision;
+ or_options_t *options = get_options_mutable();
+ int64_t val;
+ int64_t new_time;
+ (void)arg;
+
+ tor_libevent_postfork();
+
+ /*
+ * Params tested:
+ * nf_pad_before_usage
+ * nf_pad_relays
+ * nf_ito_low
+ * nf_ito_high
+ *
+ * Plan:
+ * 1. Padding can be completely disabled via consensus
+ * 2. Negotiation can't re-enable consensus-disabled padding
+ * 3. Negotiation can't increase padding from relays beyond
+ * consensus defaults
+ * 4. Relay-to-relay padding can be enabled/disabled in consensus
+ * 5. Can enable/disable padding before actually using a connection
+ * 6. Can we control circ and TLS conn lifetime from the consensus?
+ */
+ channel_t *chan;
+ routerstatus_t *relay = tor_malloc_zero(sizeof(routerstatus_t));
+ monotime_enable_test_mocking();
+ monotime_set_mock_time_nsec(1);
+ monotime_coarse_set_mock_time_nsec(1);
+ timers_initialize();
+
+ if (!connection_array)
+ connection_array = smartlist_new();
+ chan = (channel_t*)new_fake_channeltls(0);
+ channel_timestamp_active(chan);
+
+ setup_mock_consensus();
+
+ get_options_mutable()->ORPort_set = 1;
+
+ /* Test 1: Padding can be completely disabled via consensus */
+ tried_to_write_cell = 0;
+ chan->next_padding_time_ms = monotime_coarse_absolute_msec() + 100;
+ decision = channelpadding_decide_to_pad_channel(chan);
+ tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED);
+ tt_assert(chan->pending_padding_callback);
+ tt_int_op(tried_to_write_cell, OP_EQ, 0);
+
+ decision = channelpadding_decide_to_pad_channel(chan);
+ tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_ALREADY_SCHEDULED);
+
+ // Wait for the timer
+ new_time = (monotime_coarse_absolute_msec()+101)*NSEC_PER_MSEC;
+ monotime_coarse_set_mock_time_nsec(new_time);
+ monotime_set_mock_time_nsec(new_time);
+ timers_run_pending();
+ tt_int_op(tried_to_write_cell, OP_EQ, 1);
+ tt_assert(!chan->pending_padding_callback);
+
+ smartlist_add(current_md_consensus->net_params,
+ (void*)"nf_ito_low=0");
+ smartlist_add(current_md_consensus->net_params,
+ (void*)"nf_ito_high=0");
+ get_options_mutable()->ConnectionPadding = 1;
+ channelpadding_new_consensus_params(current_md_consensus);
+
+ decision = channelpadding_decide_to_pad_channel(chan);
+ tt_int_op(decision, OP_EQ, CHANNELPADDING_WONTPAD);
+ tt_assert(!chan->pending_padding_callback);
+ val = channelpadding_get_netflow_inactive_timeout_ms(chan);
+ tt_i64_op(val, OP_EQ, 0);
+ val = channelpadding_compute_time_until_pad_for_netflow(chan);
+ tt_i64_op(val, OP_EQ, -2);
+
+ /* Test 2: Negotiation can't re-enable consensus-disabled padding */
+ channelpadding_send_enable_command(chan, 100, 200);
+ tried_to_write_cell = 0;
+ decision = channelpadding_decide_to_pad_channel(chan);
+ tt_int_op(decision, OP_EQ, CHANNELPADDING_WONTPAD);
+ tt_assert(!chan->pending_padding_callback);
+ val = channelpadding_get_netflow_inactive_timeout_ms(chan);
+ tt_i64_op(val, OP_EQ, 0);
+ val = channelpadding_compute_time_until_pad_for_netflow(chan);
+ tt_i64_op(val, OP_EQ, -2);
+ tt_assert(!chan->next_padding_time_ms);
+
+ smartlist_clear(current_md_consensus->net_params);
+
+ /* Test 3: Negotiation can't increase padding from relays beyond consensus
+ * values */
+ smartlist_add(current_md_consensus->net_params,
+ (void*)"nf_ito_low=100");
+ smartlist_add(current_md_consensus->net_params,
+ (void*)"nf_ito_high=200");
+ channelpadding_new_consensus_params(current_md_consensus);
+
+ tried_to_write_cell = 0;
+ chan->next_padding_time_ms = monotime_coarse_absolute_msec() + 100;
+ decision = channelpadding_decide_to_pad_channel(chan);
+ tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED);
+ tt_assert(chan->pending_padding_callback);
+ tt_int_op(tried_to_write_cell, OP_EQ, 0);
+ val = channelpadding_get_netflow_inactive_timeout_ms(chan);
+ tt_i64_op(val, OP_GE, 100);
+ tt_i64_op(val, OP_LE, 200);
+ val = channelpadding_compute_time_until_pad_for_netflow(chan);
+ tt_i64_op(val, OP_LE, 200);
+
+ // Wait for the timer
+ new_time = (monotime_coarse_absolute_msec()+201)*NSEC_PER_MSEC;
+ monotime_set_mock_time_nsec(new_time);
+ monotime_coarse_set_mock_time_nsec(new_time);
+ timers_run_pending();
+ tt_int_op(tried_to_write_cell, OP_EQ, 1);
+ tt_assert(!chan->pending_padding_callback);
+
+ smartlist_clear(current_md_consensus->net_params);
+ smartlist_add(current_md_consensus->net_params,
+ (void*)"nf_ito_low=1500");
+ smartlist_add(current_md_consensus->net_params,
+ (void*)"nf_ito_high=4500");
+ channelpadding_new_consensus_params(current_md_consensus);
+
+ channelpadding_send_enable_command(chan, 100, 200);
+ tried_to_write_cell = 0;
+ decision = channelpadding_decide_to_pad_channel(chan);
+ tt_int_op(decision, OP_EQ, CHANNELPADDING_PADLATER);
+ tt_assert(!chan->pending_padding_callback);
+ val = channelpadding_get_netflow_inactive_timeout_ms(chan);
+ tt_i64_op(val, OP_GE, 1500);
+ tt_i64_op(val, OP_LE, 4500);
+ val = channelpadding_compute_time_until_pad_for_netflow(chan);
+ tt_i64_op(val, OP_LE, 4500);
+
+ /* Test 4: Relay-to-relay padding can be enabled/disabled in consensus */
+ /* Make this channel a relay's channel */
+ memcpy(relay->identity_digest,
+ ((channel_tls_t *)chan)->conn->identity_digest, DIGEST_LEN);
+ smartlist_add(current_md_consensus->routerstatus_list, relay);
+ relay = NULL; /* Prevent double-free */
+
+ tried_to_write_cell = 0;
+ decision = channelpadding_decide_to_pad_channel(chan);
+ tt_int_op(decision, OP_EQ, CHANNELPADDING_WONTPAD);
+ tt_assert(!chan->pending_padding_callback);
+
+ smartlist_add(current_md_consensus->net_params,
+ (void*)"nf_pad_relays=1");
+ channelpadding_new_consensus_params(current_md_consensus);
+
+ decision = channelpadding_decide_to_pad_channel(chan);
+ tt_int_op(decision, OP_EQ, CHANNELPADDING_PADLATER);
+ tt_assert(!chan->pending_padding_callback);
+ val = channelpadding_get_netflow_inactive_timeout_ms(chan);
+ tt_i64_op(val, OP_GE, 1500);
+ tt_i64_op(val, OP_LE, 4500);
+ val = channelpadding_compute_time_until_pad_for_netflow(chan);
+ tt_i64_op(val, OP_LE, 4500);
+
+ /* Test 5: If we disable padding before channel usage, does that work? */
+ smartlist_add(current_md_consensus->net_params,
+ (void*)"nf_pad_before_usage=0");
+ channelpadding_new_consensus_params(current_md_consensus);
+ tried_to_write_cell = 0;
+ decision = channelpadding_decide_to_pad_channel(chan);
+ tt_int_op(decision, OP_EQ, CHANNELPADDING_WONTPAD);
+ tt_assert(!chan->pending_padding_callback);
+
+ /* Test 6: Can we control circ and TLS conn lifetime from the consensus? */
+ val = channelpadding_get_channel_idle_timeout(NULL, 0);
+ tt_i64_op(val, OP_GE, 180);
+ tt_i64_op(val, OP_LE, 180+90);
+ val = channelpadding_get_channel_idle_timeout(chan, 0);
+ tt_i64_op(val, OP_GE, 180);
+ tt_i64_op(val, OP_LE, 180+90);
+ options->ReducedConnectionPadding = 1;
+ val = channelpadding_get_channel_idle_timeout(chan, 0);
+ tt_i64_op(val, OP_GE, 180/2);
+ tt_i64_op(val, OP_LE, (180+90)/2);
+
+ options->ReducedConnectionPadding = 0;
+ options->ORPort_set = 1;
+ smartlist_add(current_md_consensus->net_params,
+ (void*)"nf_conntimeout_relays=600");
+ channelpadding_new_consensus_params(current_md_consensus);
+ val = channelpadding_get_channel_idle_timeout(chan, 1);
+ tt_i64_op(val, OP_GE, 450);
+ tt_i64_op(val, OP_LE, 750);
+
+ val = channelpadding_get_circuits_available_timeout();
+ tt_i64_op(val, OP_GE, 30*60);
+ tt_i64_op(val, OP_LE, 30*60*2);
+
+ options->ReducedConnectionPadding = 1;
+ smartlist_add(current_md_consensus->net_params,
+ (void*)"nf_conntimeout_clients=600");
+ channelpadding_new_consensus_params(current_md_consensus);
+ val = channelpadding_get_circuits_available_timeout();
+ tt_i64_op(val, OP_GE, 600/2);
+ tt_i64_op(val, OP_LE, 600*2/2);
+
+ options->ReducedConnectionPadding = 0;
+ options->CircuitsAvailableTimeout = 24*60*60;
+ val = channelpadding_get_circuits_available_timeout();
+ tt_i64_op(val, OP_GE, 24*60*60);
+ tt_i64_op(val, OP_LE, 24*60*60*2);
+
+ done:
+ tor_free(relay);
+
+ free_mock_consensus();
+ free_fake_channeltls((channel_tls_t*)chan);
+ smartlist_free(connection_array);
+
+ timers_shutdown();
+ monotime_disable_test_mocking();
+ channel_free_all();
+
+ return;
+}
+
+void
+test_channelpadding_negotiation(void *arg)
+{
+ channelpadding_negotiate_t disable;
+ cell_t cell;
+ channelpadding_decision_t decision;
+ int val;
+ (void)arg;
+
+ /* Plan:
+ * 1. Clients reject negotiation, relays accept it.
+ * * Bridges accept negotiation from their clients,
+ * but not from relays.
+ * 2. Torrc options can override client-side negotiation
+ * 3. Test a version issue in channelpadidng cell
+ * 4. Test channelpadding_reduced_padding
+ */
+ monotime_init();
+ monotime_enable_test_mocking();
+ monotime_set_mock_time_nsec(1);
+ monotime_coarse_set_mock_time_nsec(1);
+ timers_initialize();
+ setup_mock_consensus();
+ setup_mock_network();
+
+ /* Test case #1: Do the right things ignore negotiation? */
+ /* relay-to-client case: */
+ channelpadding_send_disable_command(relay3_client);
+ tt_assert(client_relay3->padding_enabled);
+
+ /* client-to-relay case: */
+ get_options_mutable()->ORPort_set = 1;
+ channelpadding_disable_padding_on_channel(client_relay3);
+ tt_int_op(channelpadding_decide_to_pad_channel(relay3_client), OP_EQ,
+ CHANNELPADDING_WONTPAD);
+ tt_assert(!relay3_client->padding_enabled);
+ relay3_client->padding_enabled = 1;
+ client_relay3->padding_enabled = 1;
+
+ /* Bridge case from relay */
+ get_options_mutable()->BridgeRelay = 1;
+ channelpadding_disable_padding_on_channel(relay2_relay1);
+ tt_assert(relay1_relay2->padding_enabled);
+
+ /* Bridge case from client */
+ channelpadding_disable_padding_on_channel(client_relay3);
+ tt_assert(!relay3_client->padding_enabled);
+ tt_int_op(channelpadding_decide_to_pad_channel(relay3_client), OP_EQ,
+ CHANNELPADDING_WONTPAD);
+ relay3_client->padding_enabled = 1;
+ client_relay3->padding_enabled = 1;
+ get_options_mutable()->BridgeRelay = 0;
+ get_options_mutable()->ORPort_set = 0;
+
+ /* Test case #2: Torrc options */
+ /* ConnectionPadding auto; Relay doesn't suport us */
+ ((channel_tls_t*)relay3_client)->conn->link_proto = 4;
+ relay3_client->padding_enabled = 0;
+ tried_to_write_cell = 0;
+ decision = channelpadding_decide_to_pad_channel(relay3_client);
+ tt_int_op(decision, OP_EQ, CHANNELPADDING_WONTPAD);
+ tt_assert(!relay3_client->pending_padding_callback);
+ tt_int_op(tried_to_write_cell, OP_EQ, 0);
+ ((channel_tls_t*)relay3_client)->conn->link_proto = 5;
+ relay3_client->padding_enabled = 1;
+
+ /* ConnectionPadding 1; Relay doesn't suport us */
+ get_options_mutable()->ConnectionPadding = 1;
+ tried_to_write_cell = 0;
+ decision = channelpadding_decide_to_pad_channel(client_relay3);
+ tt_int_op(decision, OP_EQ, CHANNELPADDING_PADLATER);
+ tt_assert(!client_relay3->pending_padding_callback);
+ tt_int_op(tried_to_write_cell, OP_EQ, 0);
+ get_options_mutable()->ConnectionPadding = 0;
+
+ /* Test case #3: Test a version issue in channelpadding cell */
+ get_options_mutable()->ORPort_set = 1;
+ client_relay3->padding_enabled = 1;
+ relay3_client->padding_enabled = 1;
+ memset(&cell, 0, sizeof(cell_t));
+ memset(&disable, 0, sizeof(channelpadding_negotiate_t));
+ cell.command = CELL_PADDING_NEGOTIATE;
+
+ channelpadding_negotiate_set_command(&disable, CHANNELPADDING_COMMAND_STOP);
+ disable.version = 1;
+ channelpadding_negotiate_encode(cell.payload, CELL_PAYLOAD_SIZE, &disable);
+ client_relay3->write_cell(client_relay3, &cell);
+ tt_assert(relay3_client->padding_enabled);
+ tt_int_op(channelpadding_update_padding_for_channel(client_relay3, &disable),
+ OP_EQ, -1);
+ tt_assert(client_relay3->padding_enabled);
+
+ disable.version = 0;
+ channelpadding_negotiate_encode(cell.payload, CELL_PAYLOAD_SIZE, &disable);
+ client_relay3->write_cell(client_relay3, &cell);
+ tt_assert(!relay3_client->padding_enabled);
+
+ /* Test case 4: Reducing padding actually reduces it */
+ relay3_client->padding_enabled = 1;
+ client_relay3->padding_enabled = 1;
+
+ decision = channelpadding_decide_to_pad_channel(relay3_client);
+ tt_int_op(decision, OP_EQ, CHANNELPADDING_PADLATER);
+
+ channelpadding_reduce_padding_on_channel(client_relay3);
+
+ tried_to_write_cell = 0;
+ decision = channelpadding_decide_to_pad_channel(relay3_client);
+ tt_int_op(decision, OP_EQ, CHANNELPADDING_WONTPAD);
+
+ get_options_mutable()->ORPort_set = 0;
+ decision = channelpadding_decide_to_pad_channel(client_relay3);
+ tt_int_op(decision, OP_EQ, CHANNELPADDING_PADLATER);
+
+ tt_assert(!client_relay3->pending_padding_callback);
+ val = channelpadding_get_netflow_inactive_timeout_ms(client_relay3);
+ tt_int_op(val, OP_GE, 9000);
+ tt_int_op(val, OP_LE, 14000);
+ int64_t val64 =
+ channelpadding_compute_time_until_pad_for_netflow(client_relay3);
+ tt_i64_op(val64, OP_LE, 14000);
+
+ done:
+ free_mock_network();
+ free_mock_consensus();
+
+ timers_shutdown();
+ monotime_disable_test_mocking();
+ channel_free_all();
+
+ return;
+}
+
+void
+test_channelpadding_decide_to_pad_channel(void *arg)
+{
+ channelpadding_decision_t decision;
+ /**
+ * Test case plan:
+ *
+ * 1. Channel that has "sent a packet" before the timeout.
+ * + We should decide to pad later
+ * 2. Channel that has not "sent a packet" before the timeout:
+ * 2a. Not within 1.1s of the timeout.
+ * + We should decide to pad later
+ * 2b. Within 1.1s of the timemout.
+ * + We should schedule padding
+ * + We should get feedback that we wrote a cell
+ * 2c. Within 0.1s of the timeout.
+ * + We should schedule padding
+ * + We should get feedback that we wrote a cell
+ * 2d. Channel that asks to pad while timeout is scheduled
+ * + We should schedule padding
+ * + We should get feedback that we wrote a cell
+ * 2e. 0s of the timeout
+ * + We should send padding immediately
+ * + We should get feedback that we wrote a cell
+ * 2f. <0s of the timeout
+ * + We should send padding immediately
+ * + We should get feedback that we wrote a cell
+ * 3. Channel that sends a packet while timeout is scheduled
+ * + We should not get feedback that we wrote a cell
+ * 4. Channel that closes while timeout is scheduled
+ * + We should not get feedback that we wrote a cell
+ * 5. Make sure the channel still would work if repaired
+ * + We should be able to schedule padding and resend
+ * 6. Channel is not used for full circuits
+ * 7. Channel that disappears while timeout is scheduled
+ * + We should not send padding
+ */
+ channel_t *chan;
+ int64_t new_time;
+ if (!connection_array)
+ connection_array = smartlist_new();
+ (void)arg;
+
+ tor_libevent_postfork();
+
+ monotime_init();
+ monotime_enable_test_mocking();
+ monotime_set_mock_time_nsec(1);
+ monotime_coarse_set_mock_time_nsec(1);
+ timers_initialize();
+ setup_full_capture_of_logs(LOG_WARN);
+ channelpadding_new_consensus_params(NULL);
+
+ chan = (channel_t*)new_fake_channeltls(0);
+ channel_timestamp_active(chan);
+
+ /* Test case #1: Channel that has "sent a packet" before the timeout. */
+ tried_to_write_cell = 0;
+ decision = channelpadding_decide_to_pad_channel(chan);
+ tt_int_op(decision, OP_EQ, CHANNELPADDING_PADLATER);
+ tt_assert(!chan->pending_padding_callback);
+ tt_int_op(tried_to_write_cell, OP_EQ, 0);
+
+ /* Test case #2a: > 1.1s until timeout */
+ tried_to_write_cell = 0;
+ chan->next_padding_time_ms = monotime_coarse_absolute_msec() + 1200;
+ decision = channelpadding_decide_to_pad_channel(chan);
+ tt_int_op(decision, OP_EQ, CHANNELPADDING_PADLATER);
+ tt_assert(!chan->pending_padding_callback);
+ tt_int_op(tried_to_write_cell, OP_EQ, 0);
+
+ /* Test case #2b: >= 1.0s until timeout */
+ tried_to_write_cell = 0;
+ chan->next_padding_time_ms = monotime_coarse_absolute_msec() + 1000;
+ decision = channelpadding_decide_to_pad_channel(chan);
+ tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED);
+ tt_assert(chan->pending_padding_callback);
+ tt_int_op(tried_to_write_cell, OP_EQ, 0);
+
+ // Wait for the timer from case #2b
+ new_time = (monotime_coarse_absolute_msec() + 1000)*NSEC_PER_MSEC;
+ monotime_set_mock_time_nsec(new_time);
+ monotime_coarse_set_mock_time_nsec(new_time);
+ timers_run_pending();
+ tt_int_op(tried_to_write_cell, OP_EQ, 1);
+ tt_assert(!chan->pending_padding_callback);
+
+ /* Test case #2c: > 0.1s until timeout */
+ tried_to_write_cell = 0;
+ chan->next_padding_time_ms = monotime_coarse_absolute_msec() + 100;
+ decision = channelpadding_decide_to_pad_channel(chan);
+ tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED);
+ tt_assert(chan->pending_padding_callback);
+ tt_int_op(tried_to_write_cell, OP_EQ, 0);
+
+ /* Test case #2d: Channel that asks to pad while timeout is scheduled */
+ decision = channelpadding_decide_to_pad_channel(chan);
+ tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_ALREADY_SCHEDULED);
+
+ // Wait for the timer
+ new_time = (monotime_coarse_absolute_msec()+101)*NSEC_PER_MSEC;
+ monotime_coarse_set_mock_time_nsec(new_time);
+ monotime_set_mock_time_nsec(new_time);
+ timers_run_pending();
+ tt_int_op(tried_to_write_cell, OP_EQ, 1);
+ tt_assert(!chan->pending_padding_callback);
+
+ /* Test case #2e: 0s until timeout */
+ tried_to_write_cell = 0;
+ chan->next_padding_time_ms = monotime_coarse_absolute_msec();
+ decision = channelpadding_decide_to_pad_channel(chan);
+ tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SENT);
+ tt_int_op(tried_to_write_cell, OP_EQ, 1);
+ tt_assert(!chan->pending_padding_callback);
+
+ /* Test case #2f: <0s until timeout */
+ tried_to_write_cell = 0;
+ chan->next_padding_time_ms = monotime_coarse_absolute_msec() - 100;
+ decision = channelpadding_decide_to_pad_channel(chan);
+ tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SENT);
+ tt_int_op(tried_to_write_cell, OP_EQ, 1);
+ tt_assert(!chan->pending_padding_callback);
+
+ /* Test case #3: Channel that sends a packet while timeout is scheduled */
+ tried_to_write_cell = 0;
+ chan->next_padding_time_ms = monotime_coarse_absolute_msec() + 100;
+ decision = channelpadding_decide_to_pad_channel(chan);
+ tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED);
+ tt_int_op(tried_to_write_cell, OP_EQ, 0);
+ tt_assert(chan->pending_padding_callback);
+
+ // Pretend the channel sent a packet
+ channel_timestamp_active(chan);
+
+ // We don't expect any timer callbacks here. Make a dummy one to be sure.
+ // Wait for the timer
+ new_time = (monotime_coarse_absolute_msec()+101)*NSEC_PER_MSEC;
+ monotime_coarse_set_mock_time_nsec(new_time);
+ monotime_set_mock_time_nsec(new_time);
+ timers_run_pending();
+
+ tt_int_op(tried_to_write_cell, OP_EQ, 0);
+ tt_assert(!chan->pending_padding_callback);
+
+ /* Test case #4: Channel that closes while a timeout is scheduled */
+ tried_to_write_cell = 0;
+ chan->next_padding_time_ms = monotime_coarse_absolute_msec() + 100;
+ decision = channelpadding_decide_to_pad_channel(chan);
+ tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED);
+ tt_int_op(tried_to_write_cell, OP_EQ, 0);
+ tt_assert(chan->pending_padding_callback);
+
+ // Pretend the channel is temporarily down
+ chan->state = CHANNEL_STATE_MAINT;
+
+ // We don't expect any timer callbacks here. Make a dummy one to be sure.
+ new_time = (monotime_coarse_absolute_msec()+101)*NSEC_PER_MSEC;
+ monotime_coarse_set_mock_time_nsec(new_time);
+ monotime_set_mock_time_nsec(new_time);
+ timers_run_pending();
+
+ tt_int_op(tried_to_write_cell, OP_EQ, 0);
+ tt_assert(!chan->pending_padding_callback);
+ chan->state = CHANNEL_STATE_OPEN;
+
+ /* Test case #5: Make sure previous test case didn't break everything */
+ tried_to_write_cell = 0;
+ chan->next_padding_time_ms = monotime_coarse_absolute_msec() + 100;
+ decision = channelpadding_decide_to_pad_channel(chan);
+ tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED);
+ tt_assert(chan->pending_padding_callback);
+ tt_int_op(tried_to_write_cell, OP_EQ, 0);
+
+ // Wait for the timer
+ new_time = (monotime_coarse_absolute_msec()+101)*NSEC_PER_MSEC;
+ monotime_coarse_set_mock_time_nsec(new_time);
+ monotime_set_mock_time_nsec(new_time);
+ timers_run_pending();
+
+ tt_int_op(tried_to_write_cell, OP_EQ, 1);
+ tt_assert(!chan->pending_padding_callback);
+
+ /* Test case #6. Channel is not used for full circuits */
+ chan->channel_usage = CHANNEL_USED_NOT_USED_FOR_FULL_CIRCS;
+ decision = channelpadding_decide_to_pad_channel(chan);
+ tt_int_op(decision, OP_EQ, CHANNELPADDING_WONTPAD);
+ tt_assert(!chan->pending_padding_callback);
+ chan->channel_usage = CHANNEL_USED_FOR_FULL_CIRCS;
+
+ /* Test case #7. Channel is closed while timeout is scheduled.
+ *
+ * NOTE: This test deliberately breaks the channel callback mechanism.
+ * It must be last.
+ */
+ tried_to_write_cell = 0;
+ chan->next_padding_time_ms = monotime_coarse_absolute_msec() + 100;
+ decision = channelpadding_decide_to_pad_channel(chan);
+ tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED);
+ tt_int_op(tried_to_write_cell, OP_EQ, 0);
+ tt_assert(chan->pending_padding_callback);
+
+ // Close the connection while the timer is scheduled
+ free_fake_channeltls((channel_tls_t*)chan);
+
+ // We don't expect any timer callbacks here. Make a dummy one to be sure.
+ new_time = (monotime_coarse_absolute_msec()+101)*NSEC_PER_MSEC;
+ monotime_coarse_set_mock_time_nsec(new_time);
+ monotime_set_mock_time_nsec(new_time);
+ timers_run_pending();
+
+ tt_int_op(tried_to_write_cell, OP_EQ, 0);
+
+ done:
+ smartlist_free(connection_array);
+
+ teardown_capture_of_logs();
+ monotime_disable_test_mocking();
+ timers_shutdown();
+ channel_free_all();
+
+ return;
+}
+
+#define TEST_CHANNELPADDING(name, flags) \
+ { #name, test_##name, (flags), NULL, NULL }
+
+struct testcase_t channelpadding_tests[] = {
+ //TEST_CHANNELPADDING(channelpadding_decide_to_pad_channel, 0),
+ TEST_CHANNELPADDING(channelpadding_decide_to_pad_channel, TT_FORK),
+ TEST_CHANNELPADDING(channelpadding_negotiation, TT_FORK),
+ TEST_CHANNELPADDING(channelpadding_consensus, TT_FORK),
+ TEST_CHANNELPADDING(channelpadding_killonehop, TT_FORK),
+ TEST_CHANNELPADDING(channelpadding_timers, TT_FORK),
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_channeltls.c b/src/test/test_channeltls.c
index 08442e01b6..94f1893cae 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"
@@ -32,6 +32,7 @@ static or_connection_t * tlschan_connection_or_connect_mock(
const tor_addr_t *addr,
uint16_t port,
const char *digest,
+ const ed25519_public_key_t *ed_id,
channel_tls_t *tlschan);
static int tlschan_is_local_addr_mock(const tor_addr_t *addr);
@@ -70,8 +71,8 @@ test_channeltls_create(void *arg)
MOCK(connection_or_connect, tlschan_connection_or_connect_mock);
/* Try connecting */
- ch = channel_tls_connect(&test_addr, 567, test_digest);
- tt_assert(ch != NULL);
+ ch = channel_tls_connect(&test_addr, 567, test_digest, NULL);
+ tt_ptr_op(ch, OP_NE, NULL);
done:
if (ch) {
@@ -119,8 +120,8 @@ test_channeltls_num_bytes_queued(void *arg)
MOCK(connection_or_connect, tlschan_connection_or_connect_mock);
/* Try connecting */
- ch = channel_tls_connect(&test_addr, 567, test_digest);
- tt_assert(ch != NULL);
+ ch = channel_tls_connect(&test_addr, 567, test_digest, NULL);
+ tt_ptr_op(ch, OP_NE, NULL);
/*
* Next, we have to test ch->num_bytes_queued, which is
@@ -131,7 +132,7 @@ test_channeltls_num_bytes_queued(void *arg)
tt_assert(ch->num_bytes_queued != NULL);
tlschan = BASE_CHAN_TO_TLS(ch);
- tt_assert(tlschan != NULL);
+ tt_ptr_op(tlschan, OP_NE, NULL);
if (TO_CONN(tlschan->conn)->outbuf == NULL) {
/* We need an outbuf to make sure buf_datalen() gets called */
fake_outbuf = 1;
@@ -141,7 +142,7 @@ test_channeltls_num_bytes_queued(void *arg)
tlschan_buf_datalen_mock_size = 1024;
MOCK(buf_datalen, tlschan_buf_datalen_mock);
len = ch->num_bytes_queued(ch);
- tt_int_op(len, ==, tlschan_buf_datalen_mock_size);
+ tt_int_op(len, OP_EQ, tlschan_buf_datalen_mock_size);
/*
* We also cover num_cells_writeable here; since wide_circ_ids = 0 on
* the fake tlschans, cell_network_size returns 512, and so with
@@ -150,7 +151,7 @@ test_channeltls_num_bytes_queued(void *arg)
* - 2 cells.
*/
n = ch->num_cells_writeable(ch);
- tt_int_op(n, ==, CEIL_DIV(OR_CONN_HIGHWATER, 512) - 2);
+ tt_int_op(n, OP_EQ, CEIL_DIV(OR_CONN_HIGHWATER, 512) - 2);
UNMOCK(buf_datalen);
tlschan_buf_datalen_mock_target = NULL;
tlschan_buf_datalen_mock_size = 0;
@@ -204,12 +205,12 @@ test_channeltls_overhead_estimate(void *arg)
MOCK(connection_or_connect, tlschan_connection_or_connect_mock);
/* Try connecting */
- ch = channel_tls_connect(&test_addr, 567, test_digest);
- tt_assert(ch != NULL);
+ ch = channel_tls_connect(&test_addr, 567, test_digest, NULL);
+ tt_ptr_op(ch, OP_NE, NULL);
/* First case: silly low ratios should get clamped to 1.0 */
tlschan = BASE_CHAN_TO_TLS(ch);
- tt_assert(tlschan != NULL);
+ tt_ptr_op(tlschan, OP_NE, NULL);
tlschan->conn->bytes_xmitted = 128;
tlschan->conn->bytes_xmitted_by_tls = 64;
r = ch->get_overhead_estimate(ch);
@@ -266,14 +267,16 @@ static or_connection_t *
tlschan_connection_or_connect_mock(const tor_addr_t *addr,
uint16_t port,
const char *digest,
+ const ed25519_public_key_t *ed_id,
channel_tls_t *tlschan)
{
or_connection_t *result = NULL;
+ (void) ed_id; // XXXX Not yet used.
- tt_assert(addr != NULL);
- tt_assert(port != 0);
- tt_assert(digest != NULL);
- tt_assert(tlschan != NULL);
+ tt_ptr_op(addr, OP_NE, NULL);
+ tt_uint_op(port, OP_NE, 0);
+ tt_ptr_op(digest, OP_NE, NULL);
+ tt_ptr_op(tlschan, OP_NE, NULL);
/* Make a fake orconn */
result = tor_malloc_zero(sizeof(*result));
@@ -298,11 +301,11 @@ tlschan_fake_close_method(channel_t *chan)
{
channel_tls_t *tlschan = NULL;
- tt_assert(chan != NULL);
- tt_int_op(chan->magic, ==, TLS_CHAN_MAGIC);
+ tt_ptr_op(chan, OP_NE, NULL);
+ tt_int_op(chan->magic, OP_EQ, TLS_CHAN_MAGIC);
tlschan = BASE_CHAN_TO_TLS(chan);
- tt_assert(tlschan != NULL);
+ tt_ptr_op(tlschan, OP_NE, NULL);
/* Just free the fake orconn */
tor_free(tlschan->conn->base_.address);
@@ -317,7 +320,7 @@ tlschan_fake_close_method(channel_t *chan)
static int
tlschan_is_local_addr_mock(const tor_addr_t *addr)
{
- tt_assert(addr != NULL);
+ tt_ptr_op(addr, OP_NE, NULL);
done:
return tlschan_local;
diff --git a/src/test/test_checkdir.c b/src/test/test_checkdir.c
index fbb33f87f6..bf6a8376b3 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"
@@ -20,7 +20,7 @@
#define umask(mask) ((void)0)
#else
#define tt_int_op_nowin(a,op,b) tt_int_op((a),op,(b))
-#endif
+#endif /* defined(_WIN32) */
/** Run unit tests for private dir permission enforcement logic. */
static void
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 e996c42115..f622704ec5 100644
--- a/src/test/test_circuitlist.c
+++ b/src/test/test_circuitlist.c
@@ -1,13 +1,15 @@
-/* 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_
#define CIRCUITBUILD_PRIVATE
#define CIRCUITLIST_PRIVATE
+#define HS_CIRCUITMAP_PRIVATE
#include "or.h"
#include "channel.h"
#include "circuitbuild.h"
#include "circuitlist.h"
+#include "hs_circuitmap.h"
#include "test.h"
#include "log_test_helpers.h"
@@ -178,6 +180,7 @@ static void
test_rend_token_maps(void *arg)
{
or_circuit_t *c1, *c2, *c3, *c4;
+ origin_circuit_t *c5;
const uint8_t tok1[REND_TOKEN_LEN] = "The cat can't tell y";
const uint8_t tok2[REND_TOKEN_LEN] = "ou its name, and it ";
const uint8_t tok3[REND_TOKEN_LEN] = "doesn't really care.";
@@ -185,10 +188,14 @@ test_rend_token_maps(void *arg)
(void)arg;
(void)tok1; //xxxx
+
+ hs_circuitmap_init();
+
c1 = or_circuit_new(0, NULL);
c2 = or_circuit_new(0, NULL);
c3 = or_circuit_new(0, NULL);
c4 = or_circuit_new(0, NULL);
+ c5 = origin_circuit_new();
/* Make sure we really filled up the tok* variables */
tt_int_op(tok1[REND_TOKEN_LEN-1], OP_EQ, 'y');
@@ -196,68 +203,75 @@ 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, circuit_get_rendezvous(tok1));
- tt_ptr_op(NULL, OP_EQ, circuit_get_intro_point(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));
- circuit_set_rendezvous_cookie(c1, tok1);
- circuit_set_intro_point_digest(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, circuit_get_rendezvous(tok3));
- tt_ptr_op(NULL, OP_EQ, circuit_get_intro_point(tok3));
- tt_ptr_op(NULL, OP_EQ, circuit_get_rendezvous(tok2));
- tt_ptr_op(NULL, OP_EQ, circuit_get_intro_point(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, circuit_get_rendezvous(tok1));
- tt_ptr_op(NULL, OP_EQ, circuit_get_intro_point(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, circuit_get_rendezvous(tok1));
- tt_ptr_op(c2, OP_EQ, circuit_get_intro_point(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;
- circuit_set_rendezvous_cookie(c3, tok2);
- tt_ptr_op(c2, OP_EQ, circuit_get_intro_point(tok2));
- tt_ptr_op(c3, OP_EQ, circuit_get_rendezvous(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, circuit_get_rendezvous(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, circuit_get_intro_point(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, circuit_get_rendezvous(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;
- circuit_set_intro_point_digest(c3, tok3);
+ hs_circuitmap_register_intro_circ_v2_relay_side(c3, tok3);
- tt_ptr_op(NULL, OP_EQ, circuit_get_rendezvous(tok2));
- tt_ptr_op(c3, OP_EQ, circuit_get_intro_point(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;
- circuit_set_intro_point_digest(c4, tok3);
+ hs_circuitmap_register_intro_circ_v2_relay_side(c4, tok3);
- tt_ptr_op(c4, OP_EQ, circuit_get_intro_point(tok3));
+ tt_ptr_op(c4, OP_EQ, hs_circuitmap_get_intro_circ_v2_relay_side(tok3));
- tt_ptr_op(c3->rendinfo, OP_EQ, NULL);
- tt_ptr_op(c4->rendinfo, OP_NE, NULL);
- tt_mem_op(c4->rendinfo, 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. */
- circuit_set_intro_point_digest(c4, NULL);
- tt_ptr_op(c4->rendinfo, OP_EQ, NULL);
- tt_ptr_op(NULL, OP_EQ, circuit_get_intro_point(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));
+
+ /* Now let's do a check for the client-side rend circuitmap */
+ c5->base_.purpose = CIRCUIT_PURPOSE_C_ESTABLISH_REND;
+ hs_circuitmap_register_rend_circ_client_side(c5, tok1);
+
+ tt_ptr_op(c5, OP_EQ, hs_circuitmap_get_rend_circ_client_side(tok1));
+ tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ_client_side(tok2));
done:
if (c1)
@@ -268,6 +282,8 @@ test_rend_token_maps(void *arg)
circuit_free(TO_CIRCUIT(c3));
if (c4)
circuit_free(TO_CIRCUIT(c4));
+ if (c5)
+ circuit_free(TO_CIRCUIT(c5));
}
static void
@@ -365,10 +381,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 1ffa17247d..854f725054 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_
@@ -49,8 +49,8 @@ test_cmux_destroy_cell_queue(void *arg)
ch->wide_circ_ids = 1;
circ = circuitmux_get_first_active_circuit(cmux, &cq);
- tt_assert(!circ);
- tt_assert(!cq);
+ tt_ptr_op(circ, OP_EQ, NULL);
+ tt_ptr_op(cq, OP_EQ, NULL);
circuitmux_append_destroy_cell(ch, cmux, 100, 10);
circuitmux_append_destroy_cell(ch, cmux, 190, 6);
@@ -59,7 +59,7 @@ test_cmux_destroy_cell_queue(void *arg)
tt_int_op(circuitmux_num_cells(cmux), OP_EQ, 3);
circ = circuitmux_get_first_active_circuit(cmux, &cq);
- tt_assert(!circ);
+ tt_ptr_op(circ, OP_EQ, NULL);
tt_assert(cq);
tt_int_op(cq->n, OP_EQ, 3);
diff --git a/src/test/test_circuituse.c b/src/test/test_circuituse.c
new file mode 100644
index 0000000000..df1b43807f
--- /dev/null
+++ b/src/test/test_circuituse.c
@@ -0,0 +1,307 @@
+/* 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 */
+
+#define CIRCUITLIST_PRIVATE
+
+#include "or.h"
+#include "test.h"
+#include "test_helpers.h"
+#include "config.h"
+#include "circuitlist.h"
+#include "circuituse.h"
+#include "circuitbuild.h"
+#include "nodelist.h"
+
+static void
+test_circuit_is_available_for_use_ret_false_when_marked_for_close(void *arg)
+{
+ (void)arg;
+
+ circuit_t *circ = tor_malloc(sizeof(circuit_t));
+ circ->marked_for_close = 1;
+
+ tt_int_op(0, OP_EQ, circuit_is_available_for_use(circ));
+
+ done:
+ tor_free(circ);
+}
+
+static void
+test_circuit_is_available_for_use_ret_false_when_timestamp_dirty(void *arg)
+{
+ (void)arg;
+
+ circuit_t *circ = tor_malloc(sizeof(circuit_t));
+ circ->timestamp_dirty = 1;
+
+ tt_int_op(0, OP_EQ, circuit_is_available_for_use(circ));
+
+ done:
+ tor_free(circ);
+}
+
+static void
+test_circuit_is_available_for_use_ret_false_for_non_general_purpose(void *arg)
+{
+ (void)arg;
+
+ circuit_t *circ = tor_malloc(sizeof(circuit_t));
+ circ->purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING;
+
+ tt_int_op(0, OP_EQ, circuit_is_available_for_use(circ));
+
+ done:
+ tor_free(circ);
+}
+
+static void
+test_circuit_is_available_for_use_ret_false_for_non_general_origin(void *arg)
+{
+ (void)arg;
+
+ circuit_t *circ = tor_malloc(sizeof(circuit_t));
+ circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT;
+
+ tt_int_op(0, OP_EQ, circuit_is_available_for_use(circ));
+
+ done:
+ tor_free(circ);
+}
+
+static void
+test_circuit_is_available_for_use_ret_false_for_non_origin_purpose(void *arg)
+{
+ (void)arg;
+
+ circuit_t *circ = tor_malloc(sizeof(circuit_t));
+ circ->purpose = CIRCUIT_PURPOSE_OR;
+
+ tt_int_op(0, OP_EQ, circuit_is_available_for_use(circ));
+
+ done:
+ tor_free(circ);
+}
+
+static void
+test_circuit_is_available_for_use_ret_false_unusable_for_new_conns(void *arg)
+{
+ (void)arg;
+
+ circuit_t *circ = dummy_origin_circuit_new(30);
+ mark_circuit_unusable_for_new_conns(TO_ORIGIN_CIRCUIT(circ));
+
+ tt_int_op(0, OP_EQ, circuit_is_available_for_use(circ));
+
+ done:
+ circuit_free(circ);
+}
+
+static void
+test_circuit_is_available_for_use_returns_false_for_onehop_tunnel(void *arg)
+{
+ (void)arg;
+
+ circuit_t *circ = dummy_origin_circuit_new(30);
+ origin_circuit_t *oc = TO_ORIGIN_CIRCUIT(circ);
+ oc->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
+ oc->build_state->onehop_tunnel = 1;
+
+ tt_int_op(0, OP_EQ, circuit_is_available_for_use(circ));
+
+ done:
+ circuit_free(circ);
+}
+
+static void
+test_circuit_is_available_for_use_returns_true_for_clean_circuit(void *arg)
+{
+ (void)arg;
+
+ circuit_t *circ = dummy_origin_circuit_new(30);
+ origin_circuit_t *oc = TO_ORIGIN_CIRCUIT(circ);
+ oc->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
+ oc->build_state->onehop_tunnel = 0;
+
+ tt_int_op(1, OP_EQ, circuit_is_available_for_use(circ));
+
+ done:
+ circuit_free(circ);
+}
+
+static int
+mock_circuit_all_predicted_ports_handled(time_t now,
+ int *need_uptime,
+ int *need_capacity)
+{
+ (void)now;
+
+ if (need_uptime && need_capacity)
+ return 0;
+ return 1;
+}
+
+static consensus_path_type_t
+mock_router_have_unknown_consensus_path(void)
+{
+ return CONSENSUS_PATH_UNKNOWN;
+}
+
+static consensus_path_type_t
+mock_router_have_exit_consensus_path(void)
+{
+ return CONSENSUS_PATH_EXIT;
+}
+
+static void
+test_needs_exit_circuits_ret_false_for_predicted_ports_and_path(void *arg)
+{
+ (void)arg;
+
+ MOCK(circuit_all_predicted_ports_handled,
+ mock_circuit_all_predicted_ports_handled);
+ int needs_uptime = 1;
+ int needs_capacity = 0;
+
+ time_t now = time(NULL);
+ tt_int_op(0, OP_EQ,
+ needs_exit_circuits(now, &needs_uptime, &needs_capacity));
+
+ done:
+ UNMOCK(circuit_all_predicted_ports_handled);
+}
+
+static void
+test_needs_exit_circuits_ret_false_for_non_exit_consensus_path(void *arg)
+{
+ (void)arg;
+
+ MOCK(circuit_all_predicted_ports_handled,
+ mock_circuit_all_predicted_ports_handled);
+ int needs_uptime = 1;
+ int needs_capacity = 1;
+ MOCK(router_have_consensus_path, mock_router_have_unknown_consensus_path);
+
+ time_t now = time(NULL);
+ tt_int_op(0, OP_EQ,
+ needs_exit_circuits(now, &needs_uptime, &needs_capacity));
+
+ done:
+ UNMOCK(circuit_all_predicted_ports_handled);
+ UNMOCK(router_have_consensus_path);
+}
+
+static void
+test_needs_exit_circuits_ret_true_for_predicted_ports_and_path(void *arg)
+{
+ (void)arg;
+
+ MOCK(circuit_all_predicted_ports_handled,
+ mock_circuit_all_predicted_ports_handled);
+ int needs_uptime = 1;
+ int needs_capacity = 1;
+ MOCK(router_have_consensus_path, mock_router_have_exit_consensus_path);
+
+ time_t now = time(NULL);
+ tt_int_op(1, OP_EQ,
+ needs_exit_circuits(now, &needs_uptime, &needs_capacity));
+
+ done:
+ UNMOCK(circuit_all_predicted_ports_handled);
+ UNMOCK(router_have_consensus_path);
+}
+
+static void
+test_needs_circuits_for_build_ret_false_consensus_path_unknown(void *arg)
+{
+ (void)arg;
+ MOCK(router_have_consensus_path, mock_router_have_unknown_consensus_path);
+ tt_int_op(0, OP_EQ, needs_circuits_for_build(0));
+ done: ;
+}
+
+static void
+test_needs_circuits_for_build_ret_false_if_num_less_than_max(void *arg)
+{
+ (void)arg;
+ MOCK(router_have_consensus_path, mock_router_have_exit_consensus_path);
+ tt_int_op(0, OP_EQ, needs_circuits_for_build(13));
+ done:
+ UNMOCK(router_have_consensus_path);
+}
+
+static void
+test_needs_circuits_for_build_returns_true_when_more_are_needed(void *arg)
+{
+ (void)arg;
+ MOCK(router_have_consensus_path, mock_router_have_exit_consensus_path);
+ tt_int_op(1, OP_EQ, needs_circuits_for_build(0));
+ done:
+ UNMOCK(router_have_consensus_path);
+}
+
+struct testcase_t circuituse_tests[] = {
+ { "marked",
+ test_circuit_is_available_for_use_ret_false_when_marked_for_close,
+ TT_FORK, NULL, NULL
+ },
+ { "timestamp",
+ test_circuit_is_available_for_use_ret_false_when_timestamp_dirty,
+ TT_FORK, NULL, NULL
+ },
+ { "non_general",
+ test_circuit_is_available_for_use_ret_false_for_non_general_purpose,
+ TT_FORK, NULL, NULL
+ },
+ { "non_general",
+ test_circuit_is_available_for_use_ret_false_for_non_general_origin,
+ TT_FORK, NULL, NULL
+ },
+ { "origin",
+ test_circuit_is_available_for_use_ret_false_for_non_origin_purpose,
+ TT_FORK, NULL, NULL
+ },
+ { "clean",
+ test_circuit_is_available_for_use_ret_false_unusable_for_new_conns,
+ TT_FORK, NULL, NULL
+ },
+ { "onehop",
+ test_circuit_is_available_for_use_returns_false_for_onehop_tunnel,
+ TT_FORK, NULL, NULL
+ },
+ { "clean_circ",
+ test_circuit_is_available_for_use_returns_true_for_clean_circuit,
+ TT_FORK, NULL, NULL
+ },
+ { "exit_f",
+ test_needs_exit_circuits_ret_false_for_predicted_ports_and_path,
+ TT_FORK, NULL, NULL
+ },
+ { "exit_t",
+ test_needs_exit_circuits_ret_true_for_predicted_ports_and_path,
+ TT_FORK, NULL, NULL
+ },
+ { "non_exit",
+ test_needs_exit_circuits_ret_false_for_non_exit_consensus_path,
+ TT_FORK, NULL, NULL
+ },
+ { "true",
+ test_needs_exit_circuits_ret_true_for_predicted_ports_and_path,
+ TT_FORK, NULL, NULL
+ },
+ { "consensus_path_unknown",
+ test_needs_circuits_for_build_ret_false_consensus_path_unknown,
+ TT_FORK, NULL, NULL
+ },
+ { "less_than_max",
+ test_needs_circuits_for_build_ret_false_if_num_less_than_max,
+ TT_FORK, NULL, NULL
+ },
+ { "more_needed",
+ test_needs_circuits_for_build_returns_true_when_more_are_needed,
+ TT_FORK, NULL, NULL
+ },
+ END_OF_TESTCASES
+};
+
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 89f9b3e2aa..e7380c1d14 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"
@@ -11,6 +11,7 @@
#include "or.h"
#include "address.h"
#include "addressmap.h"
+#include "bridges.h"
#include "circuitmux_ewma.h"
#include "circuitbuild.h"
#include "config.h"
@@ -45,6 +46,8 @@
#include "transports.h"
#include "util.h"
+#include "test_helpers.h"
+
static void
test_config_addressmap(void *arg)
{
@@ -276,7 +279,7 @@ test_config_check_or_create_data_subdir(void *arg)
tt_assert(!is_private_dir(subpath));
tt_assert(!check_or_create_data_subdir(subdir));
tt_assert(is_private_dir(subpath));
-#endif
+#endif /* !defined (_WIN32) */
done:
rmdir(subpath);
@@ -365,12 +368,12 @@ good_bridge_line_test(const char *string, const char *test_addrport,
/* If we were asked to validate a digest, but we did not get a
digest after parsing, we failed. */
if (test_digest && tor_digest_is_zero(bridge_line->digest))
- tt_assert(0);
+ tt_abort();
/* If we were not asked to validate a digest, and we got a digest
after parsing, we failed again. */
if (!test_digest && !tor_digest_is_zero(bridge_line->digest))
- tt_assert(0);
+ tt_abort();
/* If we were asked to validate a digest, and we got a digest after
parsing, make sure it's correct. */
@@ -384,17 +387,17 @@ good_bridge_line_test(const char *string, const char *test_addrport,
/* If we were asked to validate a transport name, make sure tha it
matches with the transport name that was parsed. */
if (test_transport && !bridge_line->transport_name)
- tt_assert(0);
+ tt_abort();
if (!test_transport && bridge_line->transport_name)
- tt_assert(0);
+ tt_abort();
if (test_transport)
tt_str_op(test_transport,OP_EQ, bridge_line->transport_name);
/* Validate the SOCKS argument smartlist. */
if (test_socks_args && !bridge_line->socks_args)
- tt_assert(0);
+ tt_abort();
if (!test_socks_args && bridge_line->socks_args)
- tt_assert(0);
+ tt_abort();
if (test_socks_args)
tt_assert(smartlist_strings_eq(test_socks_args,
bridge_line->socks_args));
@@ -412,7 +415,7 @@ bad_bridge_line_test(const char *string)
bridge_line_t *bridge_line = parse_bridge_line(string);
if (bridge_line)
TT_FAIL(("%s was supposed to fail, but it didn't.", string));
- tt_assert(!bridge_line);
+ tt_ptr_op(bridge_line, OP_EQ, NULL);
done:
bridge_line_free(bridge_line);
@@ -520,18 +523,18 @@ test_config_parse_transport_options_line(void *arg)
{ /* too small line */
options_sl = get_options_from_transport_options_line("valley", NULL);
- tt_assert(!options_sl);
+ tt_ptr_op(options_sl, OP_EQ, NULL);
}
{ /* no k=v values */
options_sl = get_options_from_transport_options_line("hit it!", NULL);
- tt_assert(!options_sl);
+ tt_ptr_op(options_sl, OP_EQ, NULL);
}
{ /* correct line, but wrong transport specified */
options_sl =
get_options_from_transport_options_line("trebuchet k=v", "rook");
- tt_assert(!options_sl);
+ tt_ptr_op(options_sl, OP_EQ, NULL);
}
{ /* correct -- no transport specified */
@@ -655,84 +658,85 @@ test_config_parse_transport_plugin_line(void *arg)
/* Bad transport lines - too short */
r = parse_transport_line(options, "bad", 1, 0);
- tt_assert(r < 0);
+ tt_int_op(r, OP_LT, 0);
r = parse_transport_line(options, "bad", 1, 1);
- tt_assert(r < 0);
+ tt_int_op(r, OP_LT, 0);
r = parse_transport_line(options, "bad bad", 1, 0);
- tt_assert(r < 0);
+ tt_int_op(r, OP_LT, 0);
r = parse_transport_line(options, "bad bad", 1, 1);
- tt_assert(r < 0);
+ tt_int_op(r, OP_LT, 0);
/* Test transport list parsing */
r = parse_transport_line(options,
"transport_1 exec /usr/bin/fake-transport", 1, 0);
- tt_assert(r == 0);
+ tt_int_op(r, OP_EQ, 0);
r = parse_transport_line(options,
"transport_1 exec /usr/bin/fake-transport", 1, 1);
- tt_assert(r == 0);
+ tt_int_op(r, OP_EQ, 0);
r = parse_transport_line(options,
"transport_1,transport_2 exec /usr/bin/fake-transport", 1, 0);
- tt_assert(r == 0);
+ tt_int_op(r, OP_EQ, 0);
r = parse_transport_line(options,
"transport_1,transport_2 exec /usr/bin/fake-transport", 1, 1);
- tt_assert(r == 0);
+ tt_int_op(r, OP_EQ, 0);
/* Bad transport identifiers */
r = parse_transport_line(options,
"transport_* exec /usr/bin/fake-transport", 1, 0);
- tt_assert(r < 0);
+ tt_int_op(r, OP_LT, 0);
r = parse_transport_line(options,
"transport_* exec /usr/bin/fake-transport", 1, 1);
- tt_assert(r < 0);
+ tt_int_op(r, OP_LT, 0);
/* Check SOCKS cases for client transport */
r = parse_transport_line(options,
"transport_1 socks4 1.2.3.4:567", 1, 0);
- tt_assert(r == 0);
+ tt_int_op(r, OP_EQ, 0);
r = parse_transport_line(options,
"transport_1 socks5 1.2.3.4:567", 1, 0);
- tt_assert(r == 0);
+ tt_int_op(r, OP_EQ, 0);
/* Proxy case for server transport */
r = parse_transport_line(options,
"transport_1 proxy 1.2.3.4:567", 1, 1);
- tt_assert(r == 0);
+ tt_int_op(r, OP_EQ, 0);
/* Multiple-transport error exit */
r = parse_transport_line(options,
"transport_1,transport_2 socks5 1.2.3.4:567", 1, 0);
- tt_assert(r < 0);
+ tt_int_op(r, OP_LT, 0);
r = parse_transport_line(options,
"transport_1,transport_2 proxy 1.2.3.4:567", 1, 1);
+ tt_int_op(r, OP_LT, 0);
/* No port error exit */
r = parse_transport_line(options,
"transport_1 socks5 1.2.3.4", 1, 0);
- tt_assert(r < 0);
+ tt_int_op(r, OP_LT, 0);
r = parse_transport_line(options,
"transport_1 proxy 1.2.3.4", 1, 1);
- tt_assert(r < 0);
+ tt_int_op(r, OP_LT, 0);
/* Unparsable address error exit */
r = parse_transport_line(options,
"transport_1 socks5 1.2.3:6x7", 1, 0);
- tt_assert(r < 0);
+ tt_int_op(r, OP_LT, 0);
r = parse_transport_line(options,
"transport_1 proxy 1.2.3:6x7", 1, 1);
- tt_assert(r < 0);
+ tt_int_op(r, OP_LT, 0);
/* "Strange {Client|Server}TransportPlugin field" error exit */
r = parse_transport_line(options,
"transport_1 foo bar", 1, 0);
- tt_assert(r < 0);
+ tt_int_op(r, OP_LT, 0);
r = parse_transport_line(options,
"transport_1 foo bar", 1, 1);
- tt_assert(r < 0);
+ tt_int_op(r, OP_LT, 0);
/* No sandbox mode error exit */
tmp = options->Sandbox;
options->Sandbox = 1;
r = parse_transport_line(options,
"transport_1 exec /usr/bin/fake-transport", 1, 0);
- tt_assert(r < 0);
+ tt_int_op(r, OP_LT, 0);
r = parse_transport_line(options,
"transport_1 exec /usr/bin/fake-transport", 1, 1);
- tt_assert(r < 0);
+ tt_int_op(r, OP_LT, 0);
options->Sandbox = tmp;
/*
@@ -744,7 +748,7 @@ test_config_parse_transport_plugin_line(void *arg)
pt_kickstart_proxy_mock_call_count;
r = parse_transport_line(options,
"transport_1 exec /usr/bin/fake-transport", 0, 1);
- tt_assert(r == 0);
+ tt_int_op(r, OP_EQ, 0);
tt_assert(pt_kickstart_proxy_mock_call_count ==
old_pt_kickstart_proxy_mock_call_count + 1);
UNMOCK(pt_kickstart_proxy);
@@ -752,7 +756,7 @@ test_config_parse_transport_plugin_line(void *arg)
/* This one hits a log line in the !validate_only case only */
r = parse_transport_line(options,
"transport_1 proxy 1.2.3.4:567", 0, 1);
- tt_assert(r == 0);
+ tt_int_op(r, OP_EQ, 0);
/* Check mocked client transport cases */
MOCK(pt_kickstart_proxy, pt_kickstart_proxy_mock);
@@ -770,7 +774,7 @@ test_config_parse_transport_plugin_line(void *arg)
r = parse_transport_line(options,
"transport_1 exec /usr/bin/fake-transport", 0, 0);
/* Should have succeeded */
- tt_assert(r == 0);
+ tt_int_op(r, OP_EQ, 0);
/* transport_is_needed() should have been called */
tt_assert(transport_is_needed_mock_call_count ==
old_transport_is_needed_mock_call_count + 1);
@@ -794,7 +798,7 @@ test_config_parse_transport_plugin_line(void *arg)
r = parse_transport_line(options,
"transport_1 exec /usr/bin/fake-transport", 0, 0);
/* Should have succeeded */
- tt_assert(r == 0);
+ tt_int_op(r, OP_EQ, 0);
/*
* transport_is_needed() and pt_kickstart_proxy() should have been
* called.
@@ -818,7 +822,7 @@ test_config_parse_transport_plugin_line(void *arg)
r = parse_transport_line(options,
"transport_1 socks5 1.2.3.4:567", 0, 0);
/* Should have succeeded */
- tt_assert(r == 0);
+ tt_int_op(r, OP_EQ, 0);
/*
* transport_is_needed() and transport_add_from_config() should have
* been called.
@@ -851,9 +855,23 @@ static void
test_config_fix_my_family(void *arg)
{
char *err = NULL;
- const char *family = "$1111111111111111111111111111111111111111, "
- "1111111111111111111111111111111111111112, "
- "$1111111111111111111111111111111111111113";
+ config_line_t *family = tor_malloc_zero(sizeof(config_line_t));
+ family->key = tor_strdup("MyFamily");
+ family->value = tor_strdup("$1111111111111111111111111111111111111111, "
+ "1111111111111111111111111111111111111112, "
+ "$1111111111111111111111111111111111111113");
+
+ config_line_t *family2 = tor_malloc_zero(sizeof(config_line_t));
+ family2->key = tor_strdup("MyFamily");
+ family2->value = tor_strdup("1111111111111111111111111111111111111114");
+
+ config_line_t *family3 = tor_malloc_zero(sizeof(config_line_t));
+ family3->key = tor_strdup("MyFamily");
+ family3->value = tor_strdup("$1111111111111111111111111111111111111115");
+
+ family->next = family2;
+ family2->next = family3;
+ family3->next = NULL;
or_options_t* options = options_new();
or_options_t* defaults = options_new();
@@ -861,7 +879,7 @@ test_config_fix_my_family(void *arg)
options_init(options);
options_init(defaults);
- options->MyFamily = tor_strdup(family);
+ options->MyFamily_lines = family;
options_validate(NULL, options, defaults, 0, &err) ;
@@ -869,18 +887,23 @@ test_config_fix_my_family(void *arg)
TT_FAIL(("options_validate failed: %s", err));
}
- tt_str_op(options->MyFamily,OP_EQ,
- "$1111111111111111111111111111111111111111, "
- "$1111111111111111111111111111111111111112, "
- "$1111111111111111111111111111111111111113");
-
- done:
- if (err != NULL) {
- tor_free(err);
- }
+ const char *valid[] = { "$1111111111111111111111111111111111111111",
+ "$1111111111111111111111111111111111111112",
+ "$1111111111111111111111111111111111111113",
+ "$1111111111111111111111111111111111111114",
+ "$1111111111111111111111111111111111111115" };
+ int ret_size = 0;
+ config_line_t *ret;
+ for (ret = options->MyFamily; ret && ret_size < 5; ret = ret->next) {
+ tt_str_op(ret->value, OP_EQ, valid[ret_size]);
+ ret_size++;
+ }
+ tt_int_op(ret_size, OP_EQ, 5);
- or_options_free(options);
- or_options_free(defaults);
+ done:
+ tor_free(err);
+ or_options_free(options);
+ or_options_free(defaults);
}
static int n_hostname_01010101 = 0;
@@ -1117,7 +1140,7 @@ test_config_resolve_my_address(void *arg)
&method_used,&hostname_out);
tt_want(retval == 0);
- tt_want_str_op(method_used,==,"CONFIGURED");
+ tt_want_str_op(method_used,OP_EQ,"CONFIGURED");
tt_want(hostname_out == NULL);
tt_assert(resolved_addr == 0x80348069);
@@ -1142,8 +1165,8 @@ test_config_resolve_my_address(void *arg)
tt_want(retval == 0);
tt_want(n_hostname_01010101 == prev_n_hostname_01010101 + 1);
- tt_want_str_op(method_used,==,"RESOLVED");
- tt_want_str_op(hostname_out,==,"www.torproject.org");
+ tt_want_str_op(method_used,OP_EQ,"RESOLVED");
+ tt_want_str_op(hostname_out,OP_EQ,"www.torproject.org");
tt_assert(resolved_addr == 0x01010101);
UNMOCK(tor_lookup_hostname);
@@ -1174,8 +1197,8 @@ test_config_resolve_my_address(void *arg)
tt_want(retval == 0);
tt_want(n_gethostname_replacement == prev_n_gethostname_replacement + 1);
tt_want(n_hostname_01010101 == prev_n_hostname_01010101 + 1);
- tt_want_str_op(method_used,==,"GETHOSTNAME");
- tt_want_str_op(hostname_out,==,"onionrouter!");
+ tt_want_str_op(method_used,OP_EQ,"GETHOSTNAME");
+ tt_want_str_op(hostname_out,OP_EQ,"onionrouter!");
tt_assert(resolved_addr == 0x01010101);
UNMOCK(tor_gethostname);
@@ -1197,7 +1220,7 @@ test_config_resolve_my_address(void *arg)
&method_used,&hostname_out);
tt_want(resolved_addr == 0);
- tt_assert(retval == -1);
+ tt_int_op(retval, OP_EQ, -1);
tor_free(options->Address);
tor_free(hostname_out);
@@ -1219,7 +1242,7 @@ test_config_resolve_my_address(void *arg)
&method_used,&hostname_out);
tt_want(n_hostname_failure == prev_n_hostname_failure + 1);
- tt_assert(retval == -1);
+ tt_int_op(retval, OP_EQ, -1);
UNMOCK(tor_lookup_hostname);
@@ -1240,7 +1263,7 @@ test_config_resolve_my_address(void *arg)
&method_used,&hostname_out);
tt_want(n_gethostname_failure == prev_n_gethostname_failure + 1);
- tt_assert(retval == -1);
+ tt_int_op(retval, OP_EQ, -1);
UNMOCK(tor_gethostname);
tor_free(hostname_out);
@@ -1263,11 +1286,11 @@ test_config_resolve_my_address(void *arg)
&method_used,&hostname_out);
tt_want(retval == 0);
- tt_want_int_op(n_gethostname_replacement, ==,
+ tt_want_int_op(n_gethostname_replacement, OP_EQ,
prev_n_gethostname_replacement + 1);
- tt_want_int_op(n_get_interface_address, ==,
+ tt_want_int_op(n_get_interface_address, OP_EQ,
prev_n_get_interface_address + 1);
- tt_want_str_op(method_used,==,"INTERFACE");
+ tt_want_str_op(method_used,OP_EQ,"INTERFACE");
tt_want(hostname_out == NULL);
tt_assert(resolved_addr == 0x08080808);
@@ -1293,7 +1316,7 @@ test_config_resolve_my_address(void *arg)
prev_n_get_interface_address_failure + 1);
tt_want(n_gethostname_replacement ==
prev_n_gethostname_replacement + 1);
- tt_assert(retval == -1);
+ tt_int_op(retval, OP_EQ, -1);
UNMOCK(get_interface_address);
tor_free(hostname_out);
@@ -1323,7 +1346,7 @@ test_config_resolve_my_address(void *arg)
tt_want(n_hostname_failure == prev_n_hostname_failure + 1);
tt_want(n_gethostname_replacement == prev_n_gethostname_replacement + 1);
tt_want(retval == 0);
- tt_want_str_op(method_used,==,"INTERFACE");
+ tt_want_str_op(method_used,OP_EQ,"INTERFACE");
tt_assert(resolved_addr == 0x09090909);
UNMOCK(tor_lookup_hostname);
@@ -1353,7 +1376,7 @@ test_config_resolve_my_address(void *arg)
&method_used,&hostname_out);
tt_want(n_hostname_failure == prev_n_hostname_failure + 1);
- tt_assert(retval == -1);
+ tt_int_op(retval, OP_EQ, -1);
UNMOCK(tor_gethostname);
UNMOCK(tor_lookup_hostname);
@@ -1397,9 +1420,9 @@ test_config_resolve_my_address(void *arg)
tt_want(n_hostname_localhost == prev_n_hostname_localhost + 1);
tt_want(n_get_interface_address6 == prev_n_get_interface_address6 + 1);
- tt_str_op(method_used,==,"INTERFACE");
- tt_assert(!hostname_out);
- tt_assert(retval == 0);
+ tt_str_op(method_used,OP_EQ,"INTERFACE");
+ tt_ptr_op(hostname_out, OP_EQ, NULL);
+ tt_int_op(retval, OP_EQ, 0);
/*
* CASE 11b:
@@ -1424,7 +1447,7 @@ test_config_resolve_my_address(void *arg)
tt_want(n_get_interface_address6_failure ==
prev_n_get_interface_address6_failure + 1);
- tt_assert(retval == -1);
+ tt_int_op(retval, OP_EQ, -1);
UNMOCK(tor_gethostname);
UNMOCK(tor_lookup_hostname);
@@ -1453,7 +1476,7 @@ test_config_resolve_my_address(void *arg)
&method_used,&hostname_out);
tt_want(n_gethostname_localhost == prev_n_gethostname_localhost + 1);
- tt_assert(retval == -1);
+ tt_int_op(retval, OP_EQ, -1);
UNMOCK(tor_gethostname);
@@ -1488,18 +1511,18 @@ test_config_adding_trusted_dir_server(void *arg)
NULL, V3_DIRINFO, 1.0);
tt_assert(ds);
dir_server_add(ds);
- tt_assert(get_n_authorities(V3_DIRINFO) == 1);
- tt_assert(smartlist_len(router_get_fallback_dir_servers()) == 1);
+ tt_int_op(get_n_authorities(V3_DIRINFO), OP_EQ, 1);
+ tt_int_op(smartlist_len(router_get_fallback_dir_servers()), OP_EQ, 1);
/* create a trusted ds with an IPv6 address and port */
rv = tor_addr_port_parse(LOG_WARN, "[::1]:9061", &ipv6.addr, &ipv6.port, -1);
- tt_assert(rv == 0);
+ tt_int_op(rv, OP_EQ, 0);
ds = trusted_dir_server_new("ds", "127.0.0.1", 9059, 9060, &ipv6, digest,
NULL, V3_DIRINFO, 1.0);
tt_assert(ds);
dir_server_add(ds);
- tt_assert(get_n_authorities(V3_DIRINFO) == 2);
- tt_assert(smartlist_len(router_get_fallback_dir_servers()) == 2);
+ tt_int_op(get_n_authorities(V3_DIRINFO), OP_EQ, 2);
+ tt_int_op(smartlist_len(router_get_fallback_dir_servers()), OP_EQ, 2);
done:
clear_dir_servers();
@@ -1521,21 +1544,21 @@ test_config_adding_fallback_dir_server(void *arg)
routerlist_free_all();
rv = tor_addr_parse(&ipv4, "127.0.0.1");
- tt_assert(rv == AF_INET);
+ tt_int_op(rv, OP_EQ, AF_INET);
/* create a trusted ds without an IPv6 address and port */
ds = fallback_dir_server_new(&ipv4, 9059, 9060, NULL, digest, 1.0);
tt_assert(ds);
dir_server_add(ds);
- tt_assert(smartlist_len(router_get_fallback_dir_servers()) == 1);
+ tt_int_op(smartlist_len(router_get_fallback_dir_servers()), OP_EQ, 1);
/* create a trusted ds with an IPv6 address and port */
rv = tor_addr_port_parse(LOG_WARN, "[::1]:9061", &ipv6.addr, &ipv6.port, -1);
- tt_assert(rv == 0);
+ tt_int_op(rv, OP_EQ, 0);
ds = fallback_dir_server_new(&ipv4, 9059, 9060, &ipv6, digest, 1.0);
tt_assert(ds);
dir_server_add(ds);
- tt_assert(smartlist_len(router_get_fallback_dir_servers()) == 2);
+ tt_int_op(smartlist_len(router_get_fallback_dir_servers()), OP_EQ, 2);
done:
clear_dir_servers();
@@ -1566,14 +1589,14 @@ test_config_parsing_trusted_dir_server(void *arg)
rv = parse_dir_authority_line(TEST_DIR_AUTH_LINE_START
TEST_DIR_AUTH_LINE_END,
V3_DIRINFO, 1);
- tt_assert(rv == 0);
+ tt_int_op(rv, OP_EQ, 0);
/* parse a trusted dir server with an IPv6 address and port */
rv = parse_dir_authority_line(TEST_DIR_AUTH_LINE_START
TEST_DIR_AUTH_IPV6_FLAG
TEST_DIR_AUTH_LINE_END,
V3_DIRINFO, 1);
- tt_assert(rv == 0);
+ tt_int_op(rv, OP_EQ, 0);
/* Since we are only validating, there is no cleanup. */
done:
@@ -1601,13 +1624,13 @@ test_config_parsing_fallback_dir_server(void *arg)
/* parse a trusted dir server without an IPv6 address and port */
rv = parse_dir_fallback_line(TEST_DIR_FALLBACK_LINE, 1);
- tt_assert(rv == 0);
+ tt_int_op(rv, OP_EQ, 0);
/* parse a trusted dir server with an IPv6 address and port */
rv = parse_dir_fallback_line(TEST_DIR_FALLBACK_LINE
TEST_DIR_FALLBACK_IPV6_FLAG,
1);
- tt_assert(rv == 0);
+ tt_int_op(rv, OP_EQ, 0);
/* Since we are only validating, there is no cleanup. */
done:
@@ -1627,8 +1650,8 @@ test_config_adding_default_trusted_dir_servers(void *arg)
/* Assume we only have one bridge authority */
add_default_trusted_dir_authorities(BRIDGE_DIRINFO);
- tt_assert(get_n_authorities(BRIDGE_DIRINFO) == 1);
- tt_assert(smartlist_len(router_get_fallback_dir_servers()) == 1);
+ tt_int_op(get_n_authorities(BRIDGE_DIRINFO), OP_EQ, 1);
+ tt_int_op(smartlist_len(router_get_fallback_dir_servers()), OP_EQ, 1);
/* Assume we have eight V3 authorities */
add_default_trusted_dir_authorities(V3_DIRINFO);
@@ -1816,7 +1839,7 @@ test_config_adding_dir_servers(void *arg)
/* check outcome */
/* we must have added the default fallback dirs */
- tt_assert(n_add_default_fallback_dir_servers_known_default == 1);
+ tt_int_op(n_add_default_fallback_dir_servers_known_default, OP_EQ, 1);
/* we have more fallbacks than just the authorities */
tt_assert(networkstatus_consensus_can_use_extra_fallbacks(options) == 1);
@@ -1835,7 +1858,7 @@ test_config_adding_dir_servers(void *arg)
1 : 0)
);
/* If we have no default bridge authority, something has gone wrong */
- tt_assert(n_default_alt_bridge_authority >= 1);
+ tt_int_op(n_default_alt_bridge_authority, OP_GE, 1);
/* Count v3 Authorities */
SMARTLIST_FOREACH(fallback_servers,
@@ -1847,7 +1870,7 @@ test_config_adding_dir_servers(void *arg)
1 : 0)
);
/* If we have no default authorities, something has gone really wrong */
- tt_assert(n_default_alt_dir_authority >= 1);
+ tt_int_op(n_default_alt_dir_authority, OP_GE, 1);
/* Calculate Fallback Directory Count */
n_default_fallback_dir = (smartlist_len(fallback_servers) -
@@ -1857,7 +1880,7 @@ test_config_adding_dir_servers(void *arg)
* or some authorities aren't being added as fallback directories.
* (networkstatus_consensus_can_use_extra_fallbacks depends on all
* authorities being fallback directories.) */
- tt_assert(n_default_fallback_dir >= 0);
+ tt_int_op(n_default_fallback_dir, OP_GE, 0);
}
}
@@ -1898,7 +1921,7 @@ test_config_adding_dir_servers(void *arg)
/* check outcome */
/* we must not have added the default fallback dirs */
- tt_assert(n_add_default_fallback_dir_servers_known_default == 0);
+ tt_int_op(n_add_default_fallback_dir_servers_known_default, OP_EQ, 0);
/* we have more fallbacks than just the authorities */
tt_assert(networkstatus_consensus_can_use_extra_fallbacks(options) == 1);
@@ -1907,7 +1930,7 @@ test_config_adding_dir_servers(void *arg)
/* trusted_dir_servers */
const smartlist_t *dir_servers = router_get_trusted_dir_servers();
/* D0, (No B1), (No A2) */
- tt_assert(smartlist_len(dir_servers) == 1);
+ tt_int_op(smartlist_len(dir_servers), OP_EQ, 1);
/* DirAuthority - D0 - dir_port: 60090 */
int found_D0 = 0;
@@ -1919,7 +1942,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60090 ?
1 : 0)
);
- tt_assert(found_D0 == 1);
+ tt_int_op(found_D0, OP_EQ, 1);
/* (No AlternateBridgeAuthority) - B1 - dir_port: 60091 */
int found_B1 = 0;
@@ -1931,7 +1954,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60091 ?
1 : 0)
);
- tt_assert(found_B1 == 0);
+ tt_int_op(found_B1, OP_EQ, 0);
/* (No AlternateDirAuthority) - A2 - dir_port: 60092 */
int found_A2 = 0;
@@ -1943,14 +1966,14 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60092 ?
1 : 0)
);
- tt_assert(found_A2 == 0);
+ tt_int_op(found_A2, OP_EQ, 0);
}
{
/* fallback_dir_servers */
const smartlist_t *fallback_servers = router_get_fallback_dir_servers();
/* D0, (No B1), (No A2), Custom Fallback */
- tt_assert(smartlist_len(fallback_servers) == 2);
+ tt_int_op(smartlist_len(fallback_servers), OP_EQ, 2);
/* DirAuthority - D0 - dir_port: 60090 */
int found_D0 = 0;
@@ -1962,7 +1985,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60090 ?
1 : 0)
);
- tt_assert(found_D0 == 1);
+ tt_int_op(found_D0, OP_EQ, 1);
/* (No AlternateBridgeAuthority) - B1 - dir_port: 60091 */
int found_B1 = 0;
@@ -1974,7 +1997,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60091 ?
1 : 0)
);
- tt_assert(found_B1 == 0);
+ tt_int_op(found_B1, OP_EQ, 0);
/* (No AlternateDirAuthority) - A2 - dir_port: 60092 */
int found_A2 = 0;
@@ -1986,7 +2009,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60092 ?
1 : 0)
);
- tt_assert(found_A2 == 0);
+ tt_int_op(found_A2, OP_EQ, 0);
/* Custom FallbackDir - No Nickname - dir_port: 60093 */
int found_non_default_fallback = 0;
@@ -1998,7 +2021,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60093 ?
1 : 0)
);
- tt_assert(found_non_default_fallback == 1);
+ tt_int_op(found_non_default_fallback, OP_EQ, 1);
/* (No Default FallbackDir) - No Nickname - dir_port: 60099 */
int found_default_fallback = 0;
@@ -2010,7 +2033,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60099 ?
1 : 0)
);
- tt_assert(found_default_fallback == 0);
+ tt_int_op(found_default_fallback, OP_EQ, 0);
}
}
@@ -2039,7 +2062,7 @@ test_config_adding_dir_servers(void *arg)
/* check outcome */
/* we must not have added the default fallback dirs */
- tt_assert(n_add_default_fallback_dir_servers_known_default == 0);
+ tt_int_op(n_add_default_fallback_dir_servers_known_default, OP_EQ, 0);
/* we just have the authorities */
tt_assert(networkstatus_consensus_can_use_extra_fallbacks(options) == 0);
@@ -2048,7 +2071,7 @@ test_config_adding_dir_servers(void *arg)
/* trusted_dir_servers */
const smartlist_t *dir_servers = router_get_trusted_dir_servers();
/* D0, (No B1), (No A2) */
- tt_assert(smartlist_len(dir_servers) == 1);
+ tt_int_op(smartlist_len(dir_servers), OP_EQ, 1);
/* DirAuthority - D0 - dir_port: 60090 */
int found_D0 = 0;
@@ -2060,7 +2083,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60090 ?
1 : 0)
);
- tt_assert(found_D0 == 1);
+ tt_int_op(found_D0, OP_EQ, 1);
/* (No AlternateBridgeAuthority) - B1 - dir_port: 60091 */
int found_B1 = 0;
@@ -2072,7 +2095,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60091 ?
1 : 0)
);
- tt_assert(found_B1 == 0);
+ tt_int_op(found_B1, OP_EQ, 0);
/* (No AlternateDirAuthority) - A2 - dir_port: 60092 */
int found_A2 = 0;
@@ -2084,14 +2107,14 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60092 ?
1 : 0)
);
- tt_assert(found_A2 == 0);
+ tt_int_op(found_A2, OP_EQ, 0);
}
{
/* fallback_dir_servers */
const smartlist_t *fallback_servers = router_get_fallback_dir_servers();
/* D0, (No B1), (No A2), (No Fallback) */
- tt_assert(smartlist_len(fallback_servers) == 1);
+ tt_int_op(smartlist_len(fallback_servers), OP_EQ, 1);
/* DirAuthority - D0 - dir_port: 60090 */
int found_D0 = 0;
@@ -2103,7 +2126,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60090 ?
1 : 0)
);
- tt_assert(found_D0 == 1);
+ tt_int_op(found_D0, OP_EQ, 1);
/* (No AlternateBridgeAuthority) - B1 - dir_port: 60091 */
int found_B1 = 0;
@@ -2115,7 +2138,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60091 ?
1 : 0)
);
- tt_assert(found_B1 == 0);
+ tt_int_op(found_B1, OP_EQ, 0);
/* (No AlternateDirAuthority) - A2 - dir_port: 60092 */
int found_A2 = 0;
@@ -2127,7 +2150,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60092 ?
1 : 0)
);
- tt_assert(found_A2 == 0);
+ tt_int_op(found_A2, OP_EQ, 0);
/* (No Custom FallbackDir) - No Nickname - dir_port: 60093 */
int found_non_default_fallback = 0;
@@ -2139,7 +2162,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60093 ?
1 : 0)
);
- tt_assert(found_non_default_fallback == 0);
+ tt_int_op(found_non_default_fallback, OP_EQ, 0);
/* (No Default FallbackDir) - No Nickname - dir_port: 60099 */
int found_default_fallback = 0;
@@ -2151,7 +2174,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60099 ?
1 : 0)
);
- tt_assert(found_default_fallback == 0);
+ tt_int_op(found_default_fallback, OP_EQ, 0);
}
}
@@ -2180,7 +2203,7 @@ test_config_adding_dir_servers(void *arg)
/* check outcome */
/* we must not have added the default fallback dirs */
- tt_assert(n_add_default_fallback_dir_servers_known_default == 0);
+ tt_int_op(n_add_default_fallback_dir_servers_known_default, OP_EQ, 0);
/* we have more fallbacks than just the authorities */
tt_assert(networkstatus_consensus_can_use_extra_fallbacks(options) == 1);
@@ -2189,7 +2212,7 @@ test_config_adding_dir_servers(void *arg)
/* trusted_dir_servers */
const smartlist_t *dir_servers = router_get_trusted_dir_servers();
/* (No D0), B1, A2 */
- tt_assert(smartlist_len(dir_servers) == 2);
+ tt_int_op(smartlist_len(dir_servers), OP_EQ, 2);
/* (No DirAuthority) - D0 - dir_port: 60090 */
int found_D0 = 0;
@@ -2201,7 +2224,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60090 ?
1 : 0)
);
- tt_assert(found_D0 == 0);
+ tt_int_op(found_D0, OP_EQ, 0);
/* AlternateBridgeAuthority - B1 - dir_port: 60091 */
int found_B1 = 0;
@@ -2213,7 +2236,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60091 ?
1 : 0)
);
- tt_assert(found_B1 == 1);
+ tt_int_op(found_B1, OP_EQ, 1);
/* AlternateDirAuthority - A2 - dir_port: 60092 */
int found_A2 = 0;
@@ -2225,14 +2248,14 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60092 ?
1 : 0)
);
- tt_assert(found_A2 == 1);
+ tt_int_op(found_A2, OP_EQ, 1);
}
{
/* fallback_dir_servers */
const smartlist_t *fallback_servers = router_get_fallback_dir_servers();
/* (No D0), B1, A2, Custom Fallback */
- tt_assert(smartlist_len(fallback_servers) == 3);
+ tt_int_op(smartlist_len(fallback_servers), OP_EQ, 3);
/* (No DirAuthority) - D0 - dir_port: 60090 */
int found_D0 = 0;
@@ -2244,7 +2267,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60090 ?
1 : 0)
);
- tt_assert(found_D0 == 0);
+ tt_int_op(found_D0, OP_EQ, 0);
/* AlternateBridgeAuthority - B1 - dir_port: 60091 */
int found_B1 = 0;
@@ -2256,7 +2279,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60091 ?
1 : 0)
);
- tt_assert(found_B1 == 1);
+ tt_int_op(found_B1, OP_EQ, 1);
/* AlternateDirAuthority - A2 - dir_port: 60092 */
int found_A2 = 0;
@@ -2268,7 +2291,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60092 ?
1 : 0)
);
- tt_assert(found_A2 == 1);
+ tt_int_op(found_A2, OP_EQ, 1);
/* Custom FallbackDir - No Nickname - dir_port: 60093 */
int found_non_default_fallback = 0;
@@ -2280,7 +2303,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60093 ?
1 : 0)
);
- tt_assert(found_non_default_fallback == 1);
+ tt_int_op(found_non_default_fallback, OP_EQ, 1);
/* (No Default FallbackDir) - No Nickname - dir_port: 60099 */
int found_default_fallback = 0;
@@ -2292,7 +2315,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60099 ?
1 : 0)
);
- tt_assert(found_default_fallback == 0);
+ tt_int_op(found_default_fallback, OP_EQ, 0);
}
}
@@ -2322,7 +2345,7 @@ test_config_adding_dir_servers(void *arg)
/* check outcome */
/* we must not have added the default fallback dirs */
- tt_assert(n_add_default_fallback_dir_servers_known_default == 0);
+ tt_int_op(n_add_default_fallback_dir_servers_known_default, OP_EQ, 0);
/* we have more fallbacks than just the authorities */
tt_assert(networkstatus_consensus_can_use_extra_fallbacks(options) == 0);
@@ -2331,7 +2354,7 @@ test_config_adding_dir_servers(void *arg)
/* trusted_dir_servers */
const smartlist_t *dir_servers = router_get_trusted_dir_servers();
/* (No D0), B1, A2 */
- tt_assert(smartlist_len(dir_servers) == 2);
+ tt_int_op(smartlist_len(dir_servers), OP_EQ, 2);
/* (No DirAuthority) - D0 - dir_port: 60090 */
int found_D0 = 0;
@@ -2343,7 +2366,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60090 ?
1 : 0)
);
- tt_assert(found_D0 == 0);
+ tt_int_op(found_D0, OP_EQ, 0);
/* AlternateBridgeAuthority - B1 - dir_port: 60091 */
int found_B1 = 0;
@@ -2355,7 +2378,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60091 ?
1 : 0)
);
- tt_assert(found_B1 == 1);
+ tt_int_op(found_B1, OP_EQ, 1);
/* AlternateDirAuthority - A2 - dir_port: 60092 */
int found_A2 = 0;
@@ -2367,14 +2390,14 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60092 ?
1 : 0)
);
- tt_assert(found_A2 == 1);
+ tt_int_op(found_A2, OP_EQ, 1);
}
{
/* fallback_dir_servers */
const smartlist_t *fallback_servers = router_get_fallback_dir_servers();
/* (No D0), B1, A2, (No Fallback) */
- tt_assert(smartlist_len(fallback_servers) == 2);
+ tt_int_op(smartlist_len(fallback_servers), OP_EQ, 2);
/* (No DirAuthority) - D0 - dir_port: 60090 */
int found_D0 = 0;
@@ -2386,7 +2409,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60090 ?
1 : 0)
);
- tt_assert(found_D0 == 0);
+ tt_int_op(found_D0, OP_EQ, 0);
/* AlternateBridgeAuthority - B1 - dir_port: 60091 */
int found_B1 = 0;
@@ -2398,7 +2421,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60091 ?
1 : 0)
);
- tt_assert(found_B1 == 1);
+ tt_int_op(found_B1, OP_EQ, 1);
/* AlternateDirAuthority - A2 - dir_port: 60092 */
int found_A2 = 0;
@@ -2410,7 +2433,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60092 ?
1 : 0)
);
- tt_assert(found_A2 == 1);
+ tt_int_op(found_A2, OP_EQ, 1);
/* (No Custom FallbackDir) - No Nickname - dir_port: 60093 */
int found_non_default_fallback = 0;
@@ -2422,7 +2445,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60093 ?
1 : 0)
);
- tt_assert(found_non_default_fallback == 0);
+ tt_int_op(found_non_default_fallback, OP_EQ, 0);
/* (No Default FallbackDir) - No Nickname - dir_port: 60099 */
int found_default_fallback = 0;
@@ -2434,7 +2457,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60099 ?
1 : 0)
);
- tt_assert(found_default_fallback == 0);
+ tt_int_op(found_default_fallback, OP_EQ, 0);
}
}
@@ -2474,7 +2497,7 @@ test_config_adding_dir_servers(void *arg)
/* check outcome */
/* we must not have added the default fallback dirs */
- tt_assert(n_add_default_fallback_dir_servers_known_default == 0);
+ tt_int_op(n_add_default_fallback_dir_servers_known_default, OP_EQ, 0);
/* we have more fallbacks than just the authorities */
tt_assert(networkstatus_consensus_can_use_extra_fallbacks(options) == 1);
@@ -2495,7 +2518,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60090 ?
1 : 0)
);
- tt_assert(found_D0 == 0);
+ tt_int_op(found_D0, OP_EQ, 0);
/* AlternateBridgeAuthority - B1 - dir_port: 60091 */
int found_B1 = 0;
@@ -2507,7 +2530,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60091 ?
1 : 0)
);
- tt_assert(found_B1 == 1);
+ tt_int_op(found_B1, OP_EQ, 1);
/* (No AlternateDirAuthority) - A2 - dir_port: 60092 */
int found_A2 = 0;
@@ -2519,7 +2542,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60092 ?
1 : 0)
);
- tt_assert(found_A2 == 0);
+ tt_int_op(found_A2, OP_EQ, 0);
/* There's no easy way of checking that we have included all the
* default v3 non-Bridge directory authorities, so let's assume that
@@ -2545,7 +2568,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60090 ?
1 : 0)
);
- tt_assert(found_D0 == 0);
+ tt_int_op(found_D0, OP_EQ, 0);
/* AlternateBridgeAuthority - B1 - dir_port: 60091 */
int found_B1 = 0;
@@ -2557,7 +2580,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60091 ?
1 : 0)
);
- tt_assert(found_B1 == 1);
+ tt_int_op(found_B1, OP_EQ, 1);
/* (No AlternateDirAuthority) - A2 - dir_port: 60092 */
int found_A2 = 0;
@@ -2569,7 +2592,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60092 ?
1 : 0)
);
- tt_assert(found_A2 == 0);
+ tt_int_op(found_A2, OP_EQ, 0);
/* Custom FallbackDir - No Nickname - dir_port: 60093 */
int found_non_default_fallback = 0;
@@ -2581,7 +2604,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60093 ?
1 : 0)
);
- tt_assert(found_non_default_fallback == 1);
+ tt_int_op(found_non_default_fallback, OP_EQ, 1);
/* (No Default FallbackDir) - No Nickname - dir_port: 60099 */
int found_default_fallback = 0;
@@ -2593,7 +2616,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60099 ?
1 : 0)
);
- tt_assert(found_default_fallback == 0);
+ tt_int_op(found_default_fallback, OP_EQ, 0);
/* There's no easy way of checking that we have included all the
* default v3 non-Bridge directory authorities, so let's assume that
@@ -2628,7 +2651,7 @@ test_config_adding_dir_servers(void *arg)
/* check outcome */
/* we must have added the default fallback dirs */
- tt_assert(n_add_default_fallback_dir_servers_known_default == 1);
+ tt_int_op(n_add_default_fallback_dir_servers_known_default, OP_EQ, 1);
/* we have more fallbacks than just the authorities */
tt_assert(networkstatus_consensus_can_use_extra_fallbacks(options) == 1);
@@ -2649,7 +2672,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60090 ?
1 : 0)
);
- tt_assert(found_D0 == 0);
+ tt_int_op(found_D0, OP_EQ, 0);
/* AlternateBridgeAuthority - B1 - dir_port: 60091 */
int found_B1 = 0;
@@ -2661,7 +2684,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60091 ?
1 : 0)
);
- tt_assert(found_B1 == 1);
+ tt_int_op(found_B1, OP_EQ, 1);
/* (No AlternateDirAuthority) - A2 - dir_port: 60092 */
int found_A2 = 0;
@@ -2673,7 +2696,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60092 ?
1 : 0)
);
- tt_assert(found_A2 == 0);
+ tt_int_op(found_A2, OP_EQ, 0);
/* There's no easy way of checking that we have included all the
* default v3 non-Bridge directory authorities, so let's assume that
@@ -2699,7 +2722,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60090 ?
1 : 0)
);
- tt_assert(found_D0 == 0);
+ tt_int_op(found_D0, OP_EQ, 0);
/* AlternateBridgeAuthority - B1 - dir_port: 60091 */
int found_B1 = 0;
@@ -2711,7 +2734,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60091 ?
1 : 0)
);
- tt_assert(found_B1 == 1);
+ tt_int_op(found_B1, OP_EQ, 1);
/* (No AlternateDirAuthority) - A2 - dir_port: 60092 */
int found_A2 = 0;
@@ -2723,7 +2746,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60092 ?
1 : 0)
);
- tt_assert(found_A2 == 0);
+ tt_int_op(found_A2, OP_EQ, 0);
/* (No Custom FallbackDir) - No Nickname - dir_port: 60093 */
int found_non_default_fallback = 0;
@@ -2735,7 +2758,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60093 ?
1 : 0)
);
- tt_assert(found_non_default_fallback == 0);
+ tt_int_op(found_non_default_fallback, OP_EQ, 0);
/* Default FallbackDir - No Nickname - dir_port: 60099 */
int found_default_fallback = 0;
@@ -2747,7 +2770,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60099 ?
1 : 0)
);
- tt_assert(found_default_fallback == 1);
+ tt_int_op(found_default_fallback, OP_EQ, 1);
/* There's no easy way of checking that we have included all the
* default v3 non-Bridge directory authorities, so let's assume that
@@ -2791,7 +2814,7 @@ test_config_adding_dir_servers(void *arg)
/* check outcome */
/* we must not have added the default fallback dirs */
- tt_assert(n_add_default_fallback_dir_servers_known_default == 0);
+ tt_int_op(n_add_default_fallback_dir_servers_known_default, OP_EQ, 0);
/* we have more fallbacks than just the authorities */
tt_assert(networkstatus_consensus_can_use_extra_fallbacks(options) == 1);
@@ -2813,7 +2836,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60090 ?
1 : 0)
);
- tt_assert(found_D0 == 0);
+ tt_int_op(found_D0, OP_EQ, 0);
/* (No AlternateBridgeAuthority) - B1 - dir_port: 60091 */
int found_B1 = 0;
@@ -2825,7 +2848,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60091 ?
1 : 0)
);
- tt_assert(found_B1 == 0);
+ tt_int_op(found_B1, OP_EQ, 0);
/* AlternateDirAuthority - A2 - dir_port: 60092 */
int found_A2 = 0;
@@ -2837,7 +2860,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60092 ?
1 : 0)
);
- tt_assert(found_A2 == 1);
+ tt_int_op(found_A2, OP_EQ, 1);
/* There's no easy way of checking that we have included all the
* default Bridge authorities (except for hard-coding tonga's details),
@@ -2864,7 +2887,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60090 ?
1 : 0)
);
- tt_assert(found_D0 == 0);
+ tt_int_op(found_D0, OP_EQ, 0);
/* (No AlternateBridgeAuthority) - B1 - dir_port: 60091 */
int found_B1 = 0;
@@ -2876,7 +2899,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60091 ?
1 : 0)
);
- tt_assert(found_B1 == 0);
+ tt_int_op(found_B1, OP_EQ, 0);
/* AlternateDirAuthority - A2 - dir_port: 60092 */
int found_A2 = 0;
@@ -2888,7 +2911,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60092 ?
1 : 0)
);
- tt_assert(found_A2 == 1);
+ tt_int_op(found_A2, OP_EQ, 1);
/* Custom FallbackDir - No Nickname - dir_port: 60093 */
int found_non_default_fallback = 0;
@@ -2900,7 +2923,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60093 ?
1 : 0)
);
- tt_assert(found_non_default_fallback == 1);
+ tt_int_op(found_non_default_fallback, OP_EQ, 1);
/* (No Default FallbackDir) - No Nickname - dir_port: 60099 */
int found_default_fallback = 0;
@@ -2912,7 +2935,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60099 ?
1 : 0)
);
- tt_assert(found_default_fallback == 0);
+ tt_int_op(found_default_fallback, OP_EQ, 0);
/* There's no easy way of checking that we have included all the
* default Bridge authorities (except for hard-coding tonga's details),
@@ -2948,7 +2971,7 @@ test_config_adding_dir_servers(void *arg)
/* check outcome */
/* we must not have added the default fallback dirs */
- tt_assert(n_add_default_fallback_dir_servers_known_default == 0);
+ tt_int_op(n_add_default_fallback_dir_servers_known_default, OP_EQ, 0);
/* we just have the authorities */
tt_assert(networkstatus_consensus_can_use_extra_fallbacks(options) == 0);
@@ -2971,7 +2994,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60090 ?
1 : 0)
);
- tt_assert(found_D0 == 0);
+ tt_int_op(found_D0, OP_EQ, 0);
/* (No AlternateBridgeAuthority) - B1 - dir_port: 60091 */
int found_B1 = 0;
@@ -2983,7 +3006,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60091 ?
1 : 0)
);
- tt_assert(found_B1 == 0);
+ tt_int_op(found_B1, OP_EQ, 0);
/* AlternateDirAuthority - A2 - dir_port: 60092 */
int found_A2 = 0;
@@ -2995,7 +3018,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60092 ?
1 : 0)
);
- tt_assert(found_A2 == 1);
+ tt_int_op(found_A2, OP_EQ, 1);
/* There's no easy way of checking that we have included all the
* default Bridge authorities (except for hard-coding tonga's details),
@@ -3022,7 +3045,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60090 ?
1 : 0)
);
- tt_assert(found_D0 == 0);
+ tt_int_op(found_D0, OP_EQ, 0);
/* (No AlternateBridgeAuthority) - B1 - dir_port: 60091 */
int found_B1 = 0;
@@ -3034,7 +3057,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60091 ?
1 : 0)
);
- tt_assert(found_B1 == 0);
+ tt_int_op(found_B1, OP_EQ, 0);
/* AlternateDirAuthority - A2 - dir_port: 60092 */
int found_A2 = 0;
@@ -3046,7 +3069,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60092 ?
1 : 0)
);
- tt_assert(found_A2 == 1);
+ tt_int_op(found_A2, OP_EQ, 1);
/* (No Custom FallbackDir) - No Nickname - dir_port: 60093 */
int found_non_default_fallback = 0;
@@ -3058,7 +3081,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60093 ?
1 : 0)
);
- tt_assert(found_non_default_fallback == 0);
+ tt_int_op(found_non_default_fallback, OP_EQ, 0);
/* (No Default FallbackDir) - No Nickname - dir_port: 60099 */
int found_default_fallback = 0;
@@ -3070,7 +3093,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60099 ?
1 : 0)
);
- tt_assert(found_default_fallback == 0);
+ tt_int_op(found_default_fallback, OP_EQ, 0);
/* There's no easy way of checking that we have included all the
* default Bridge authorities (except for hard-coding tonga's details),
@@ -3114,7 +3137,7 @@ test_config_adding_dir_servers(void *arg)
/* check outcome */
/* we must not have added the default fallback dirs */
- tt_assert(n_add_default_fallback_dir_servers_known_default == 0);
+ tt_int_op(n_add_default_fallback_dir_servers_known_default, OP_EQ, 0);
/* we have more fallbacks than just the authorities */
tt_assert(networkstatus_consensus_can_use_extra_fallbacks(options) == 1);
@@ -3136,7 +3159,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60090 ?
1 : 0)
);
- tt_assert(found_D0 == 0);
+ tt_int_op(found_D0, OP_EQ, 0);
/* (No AlternateBridgeAuthority) - B1 - dir_port: 60091 */
int found_B1 = 0;
@@ -3148,7 +3171,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60091 ?
1 : 0)
);
- tt_assert(found_B1 == 0);
+ tt_int_op(found_B1, OP_EQ, 0);
/* (No AlternateDirAuthority) - A2 - dir_port: 60092 */
int found_A2 = 0;
@@ -3160,7 +3183,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60092 ?
1 : 0)
);
- tt_assert(found_A2 == 0);
+ tt_int_op(found_A2, OP_EQ, 0);
/* There's no easy way of checking that we have included all the
* default Bridge & V3 Directory authorities, so let's assume that
@@ -3187,7 +3210,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60090 ?
1 : 0)
);
- tt_assert(found_D0 == 0);
+ tt_int_op(found_D0, OP_EQ, 0);
/* (No AlternateBridgeAuthority) - B1 - dir_port: 60091 */
int found_B1 = 0;
@@ -3199,7 +3222,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60091 ?
1 : 0)
);
- tt_assert(found_B1 == 0);
+ tt_int_op(found_B1, OP_EQ, 0);
/* (No AlternateDirAuthority) - A2 - dir_port: 60092 */
int found_A2 = 0;
@@ -3211,7 +3234,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60092 ?
1 : 0)
);
- tt_assert(found_A2 == 0);
+ tt_int_op(found_A2, OP_EQ, 0);
/* Custom FallbackDir - No Nickname - dir_port: 60093 */
int found_non_default_fallback = 0;
@@ -3223,7 +3246,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60093 ?
1 : 0)
);
- tt_assert(found_non_default_fallback == 1);
+ tt_int_op(found_non_default_fallback, OP_EQ, 1);
/* (No Default FallbackDir) - No Nickname - dir_port: 60099 */
int found_default_fallback = 0;
@@ -3235,7 +3258,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60099 ?
1 : 0)
);
- tt_assert(found_default_fallback == 0);
+ tt_int_op(found_default_fallback, OP_EQ, 0);
/* There's no easy way of checking that we have included all the
* default Bridge & V3 Directory authorities, so let's assume that
@@ -3277,7 +3300,7 @@ test_config_adding_dir_servers(void *arg)
/* check outcome */
/* we must have added the default fallback dirs */
- tt_assert(n_add_default_fallback_dir_servers_known_default == 1);
+ tt_int_op(n_add_default_fallback_dir_servers_known_default, OP_EQ, 1);
/* we have more fallbacks than just the authorities */
tt_assert(networkstatus_consensus_can_use_extra_fallbacks(options) == 1);
@@ -3299,7 +3322,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60090 ?
1 : 0)
);
- tt_assert(found_D0 == 0);
+ tt_int_op(found_D0, OP_EQ, 0);
/* (No AlternateBridgeAuthority) - B1 - dir_port: 60091 */
int found_B1 = 0;
@@ -3311,7 +3334,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60091 ?
1 : 0)
);
- tt_assert(found_B1 == 0);
+ tt_int_op(found_B1, OP_EQ, 0);
/* (No AlternateDirAuthority) - A2 - dir_port: 60092 */
int found_A2 = 0;
@@ -3323,7 +3346,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60092 ?
1 : 0)
);
- tt_assert(found_A2 == 0);
+ tt_int_op(found_A2, OP_EQ, 0);
/* There's no easy way of checking that we have included all the
* default Bridge & V3 Directory authorities, so let's assume that
@@ -3350,7 +3373,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60090 ?
1 : 0)
);
- tt_assert(found_D0 == 0);
+ tt_int_op(found_D0, OP_EQ, 0);
/* (No AlternateBridgeAuthority) - B1 - dir_port: 60091 */
int found_B1 = 0;
@@ -3362,7 +3385,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60091 ?
1 : 0)
);
- tt_assert(found_B1 == 0);
+ tt_int_op(found_B1, OP_EQ, 0);
/* (No AlternateDirAuthority) - A2 - dir_port: 60092 */
int found_A2 = 0;
@@ -3374,7 +3397,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60092 ?
1 : 0)
);
- tt_assert(found_A2 == 0);
+ tt_int_op(found_A2, OP_EQ, 0);
/* Custom FallbackDir - No Nickname - dir_port: 60093 */
int found_non_default_fallback = 0;
@@ -3386,7 +3409,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60093 ?
1 : 0)
);
- tt_assert(found_non_default_fallback == 0);
+ tt_int_op(found_non_default_fallback, OP_EQ, 0);
/* (No Default FallbackDir) - No Nickname - dir_port: 60099 */
int found_default_fallback = 0;
@@ -3398,7 +3421,7 @@ test_config_adding_dir_servers(void *arg)
(ds->dir_port == 60099 ?
1 : 0)
);
- tt_assert(found_default_fallback == 1);
+ tt_int_op(found_default_fallback, OP_EQ, 1);
/* There's no easy way of checking that we have included all the
* default Bridge & V3 Directory authorities, and the default
@@ -3455,7 +3478,7 @@ test_config_default_dir_servers(void *arg)
opts = NULL;
/* assume a release will never go out with less than 7 authorities */
- tt_assert(trusted_count >= 7);
+ tt_int_op(trusted_count, OP_GE, 7);
/* if we disable the default fallbacks, there must not be any extra */
tt_assert(fallback_count == trusted_count);
@@ -3468,7 +3491,7 @@ test_config_default_dir_servers(void *arg)
opts = NULL;
/* assume a release will never go out with less than 7 authorities */
- tt_assert(trusted_count >= 7);
+ tt_int_op(trusted_count, OP_GE, 7);
/* XX/teor - allow for default fallbacks to be added without breaking
* the unit tests. Set a minimum fallback count once the list is stable. */
tt_assert(fallback_count >= trusted_count);
@@ -3537,18 +3560,18 @@ test_config_directory_fetch(void *arg)
options->ClientOnly = 1;
tt_assert(server_mode(options) == 0);
tt_assert(public_server_mode(options) == 0);
- tt_assert(directory_fetches_from_authorities(options) == 0);
- tt_assert(networkstatus_consensus_can_use_multiple_directories(options)
- == 1);
+ tt_int_op(directory_fetches_from_authorities(options), OP_EQ, 0);
+ tt_int_op(networkstatus_consensus_can_use_multiple_directories(options),
+ OP_EQ, 1);
/* Bridge Clients can use multiple directory mirrors for bootstrap */
memset(options, 0, sizeof(or_options_t));
options->UseBridges = 1;
tt_assert(server_mode(options) == 0);
tt_assert(public_server_mode(options) == 0);
- tt_assert(directory_fetches_from_authorities(options) == 0);
- tt_assert(networkstatus_consensus_can_use_multiple_directories(options)
- == 1);
+ tt_int_op(directory_fetches_from_authorities(options), OP_EQ, 0);
+ tt_int_op(networkstatus_consensus_can_use_multiple_directories(options),
+ OP_EQ, 1);
/* Bridge Relays (Bridges) must act like clients, and use multiple
* directory mirrors for bootstrap */
@@ -3557,9 +3580,9 @@ test_config_directory_fetch(void *arg)
options->ORPort_set = 1;
tt_assert(server_mode(options) == 1);
tt_assert(public_server_mode(options) == 0);
- tt_assert(directory_fetches_from_authorities(options) == 0);
- tt_assert(networkstatus_consensus_can_use_multiple_directories(options)
- == 1);
+ tt_int_op(directory_fetches_from_authorities(options), OP_EQ, 0);
+ tt_int_op(networkstatus_consensus_can_use_multiple_directories(options),
+ OP_EQ, 1);
/* Clients set to FetchDirInfoEarly must fetch it from the authorities,
* but can use multiple authorities for bootstrap */
@@ -3567,9 +3590,9 @@ test_config_directory_fetch(void *arg)
options->FetchDirInfoEarly = 1;
tt_assert(server_mode(options) == 0);
tt_assert(public_server_mode(options) == 0);
- tt_assert(directory_fetches_from_authorities(options) == 1);
- tt_assert(networkstatus_consensus_can_use_multiple_directories(options)
- == 1);
+ tt_int_op(directory_fetches_from_authorities(options), OP_EQ, 1);
+ tt_int_op(networkstatus_consensus_can_use_multiple_directories(options),
+ OP_EQ, 1);
/* OR servers only fetch the consensus from the authorities when they don't
* know their own address, but never use multiple directories for bootstrap
@@ -3580,16 +3603,16 @@ test_config_directory_fetch(void *arg)
mock_router_pick_published_address_result = -1;
tt_assert(server_mode(options) == 1);
tt_assert(public_server_mode(options) == 1);
- tt_assert(directory_fetches_from_authorities(options) == 1);
- tt_assert(networkstatus_consensus_can_use_multiple_directories(options)
- == 0);
+ tt_int_op(directory_fetches_from_authorities(options), OP_EQ, 1);
+ tt_int_op(networkstatus_consensus_can_use_multiple_directories(options),
+ OP_EQ, 0);
mock_router_pick_published_address_result = 0;
tt_assert(server_mode(options) == 1);
tt_assert(public_server_mode(options) == 1);
- tt_assert(directory_fetches_from_authorities(options) == 0);
- tt_assert(networkstatus_consensus_can_use_multiple_directories(options)
- == 0);
+ tt_int_op(directory_fetches_from_authorities(options), OP_EQ, 0);
+ tt_int_op(networkstatus_consensus_can_use_multiple_directories(options),
+ OP_EQ, 0);
/* Exit OR servers only fetch the consensus from the authorities when they
* refuse unknown exits, but never use multiple directories for bootstrap
@@ -3607,17 +3630,17 @@ test_config_directory_fetch(void *arg)
options->RefuseUnknownExits = 1;
tt_assert(server_mode(options) == 1);
tt_assert(public_server_mode(options) == 1);
- tt_assert(directory_fetches_from_authorities(options) == 1);
- tt_assert(networkstatus_consensus_can_use_multiple_directories(options)
- == 0);
+ tt_int_op(directory_fetches_from_authorities(options), OP_EQ, 1);
+ tt_int_op(networkstatus_consensus_can_use_multiple_directories(options),
+ OP_EQ, 0);
options->RefuseUnknownExits = 0;
mock_router_pick_published_address_result = 0;
tt_assert(server_mode(options) == 1);
tt_assert(public_server_mode(options) == 1);
- tt_assert(directory_fetches_from_authorities(options) == 0);
- tt_assert(networkstatus_consensus_can_use_multiple_directories(options)
- == 0);
+ tt_int_op(directory_fetches_from_authorities(options), OP_EQ, 0);
+ tt_int_op(networkstatus_consensus_can_use_multiple_directories(options),
+ OP_EQ, 0);
/* Dir servers fetch the consensus from the authorities, unless they are not
* advertising themselves (hibernating) or have no routerinfo or are not
@@ -3636,26 +3659,26 @@ test_config_directory_fetch(void *arg)
mock_router_get_my_routerinfo_result = &routerinfo;
tt_assert(server_mode(options) == 1);
tt_assert(public_server_mode(options) == 1);
- tt_assert(directory_fetches_from_authorities(options) == 1);
- tt_assert(networkstatus_consensus_can_use_multiple_directories(options)
- == 0);
+ tt_int_op(directory_fetches_from_authorities(options), OP_EQ, 1);
+ tt_int_op(networkstatus_consensus_can_use_multiple_directories(options),
+ OP_EQ, 0);
mock_advertised_server_mode_result = 0;
routerinfo.dir_port = 1;
mock_router_get_my_routerinfo_result = &routerinfo;
tt_assert(server_mode(options) == 1);
tt_assert(public_server_mode(options) == 1);
- tt_assert(directory_fetches_from_authorities(options) == 0);
- tt_assert(networkstatus_consensus_can_use_multiple_directories(options)
- == 0);
+ tt_int_op(directory_fetches_from_authorities(options), OP_EQ, 0);
+ tt_int_op(networkstatus_consensus_can_use_multiple_directories(options),
+ OP_EQ, 0);
mock_advertised_server_mode_result = 1;
mock_router_get_my_routerinfo_result = NULL;
tt_assert(server_mode(options) == 1);
tt_assert(public_server_mode(options) == 1);
- tt_assert(directory_fetches_from_authorities(options) == 0);
- tt_assert(networkstatus_consensus_can_use_multiple_directories(options)
- == 0);
+ tt_int_op(directory_fetches_from_authorities(options), OP_EQ, 0);
+ tt_int_op(networkstatus_consensus_can_use_multiple_directories(options),
+ OP_EQ, 0);
mock_advertised_server_mode_result = 1;
routerinfo.dir_port = 0;
@@ -3663,9 +3686,9 @@ test_config_directory_fetch(void *arg)
mock_router_get_my_routerinfo_result = &routerinfo;
tt_assert(server_mode(options) == 1);
tt_assert(public_server_mode(options) == 1);
- tt_assert(directory_fetches_from_authorities(options) == 0);
- tt_assert(networkstatus_consensus_can_use_multiple_directories(options)
- == 0);
+ tt_int_op(directory_fetches_from_authorities(options), OP_EQ, 0);
+ tt_int_op(networkstatus_consensus_can_use_multiple_directories(options),
+ OP_EQ, 0);
mock_advertised_server_mode_result = 1;
routerinfo.dir_port = 1;
@@ -3673,9 +3696,9 @@ test_config_directory_fetch(void *arg)
mock_router_get_my_routerinfo_result = &routerinfo;
tt_assert(server_mode(options) == 1);
tt_assert(public_server_mode(options) == 1);
- tt_assert(directory_fetches_from_authorities(options) == 1);
- tt_assert(networkstatus_consensus_can_use_multiple_directories(options)
- == 0);
+ tt_int_op(directory_fetches_from_authorities(options), OP_EQ, 1);
+ tt_int_op(networkstatus_consensus_can_use_multiple_directories(options),
+ OP_EQ, 0);
done:
tor_free(options);
@@ -3722,119 +3745,119 @@ test_config_port_cfg_line_extract_addrport(void *arg)
tt_int_op(port_cfg_line_extract_addrport("", &a, &unixy, &rest), OP_EQ, 0);
tt_int_op(unixy, OP_EQ, 0);
- tt_str_op(a, OP_EQ, "");;
+ tt_str_op(a, OP_EQ, "");
tt_str_op(rest, OP_EQ, "");
tor_free(a);
tt_int_op(port_cfg_line_extract_addrport("hello", &a, &unixy, &rest),
OP_EQ, 0);
tt_int_op(unixy, OP_EQ, 0);
- tt_str_op(a, OP_EQ, "hello");;
+ tt_str_op(a, OP_EQ, "hello");
tt_str_op(rest, OP_EQ, "");
tor_free(a);
tt_int_op(port_cfg_line_extract_addrport(" flipperwalt gersplut",
&a, &unixy, &rest), OP_EQ, 0);
tt_int_op(unixy, OP_EQ, 0);
- tt_str_op(a, OP_EQ, "flipperwalt");;
+ tt_str_op(a, OP_EQ, "flipperwalt");
tt_str_op(rest, OP_EQ, "gersplut");
tor_free(a);
tt_int_op(port_cfg_line_extract_addrport(" flipperwalt \t gersplut",
&a, &unixy, &rest), OP_EQ, 0);
tt_int_op(unixy, OP_EQ, 0);
- tt_str_op(a, OP_EQ, "flipperwalt");;
+ tt_str_op(a, OP_EQ, "flipperwalt");
tt_str_op(rest, OP_EQ, "gersplut");
tor_free(a);
tt_int_op(port_cfg_line_extract_addrport("flipperwalt \t gersplut",
&a, &unixy, &rest), OP_EQ, 0);
tt_int_op(unixy, OP_EQ, 0);
- tt_str_op(a, OP_EQ, "flipperwalt");;
+ tt_str_op(a, OP_EQ, "flipperwalt");
tt_str_op(rest, OP_EQ, "gersplut");
tor_free(a);
tt_int_op(port_cfg_line_extract_addrport("unix:flipperwalt \t gersplut",
&a, &unixy, &rest), OP_EQ, 0);
tt_int_op(unixy, OP_EQ, 1);
- tt_str_op(a, OP_EQ, "flipperwalt");;
+ tt_str_op(a, OP_EQ, "flipperwalt");
tt_str_op(rest, OP_EQ, "gersplut");
tor_free(a);
tt_int_op(port_cfg_line_extract_addrport("lolol",
&a, &unixy, &rest), OP_EQ, 0);
tt_int_op(unixy, OP_EQ, 0);
- tt_str_op(a, OP_EQ, "lolol");;
+ tt_str_op(a, OP_EQ, "lolol");
tt_str_op(rest, OP_EQ, "");
tor_free(a);
tt_int_op(port_cfg_line_extract_addrport("unix:lolol",
&a, &unixy, &rest), OP_EQ, 0);
tt_int_op(unixy, OP_EQ, 1);
- tt_str_op(a, OP_EQ, "lolol");;
+ tt_str_op(a, OP_EQ, "lolol");
tt_str_op(rest, OP_EQ, "");
tor_free(a);
tt_int_op(port_cfg_line_extract_addrport("unix:lolol ",
&a, &unixy, &rest), OP_EQ, 0);
tt_int_op(unixy, OP_EQ, 1);
- tt_str_op(a, OP_EQ, "lolol");;
+ tt_str_op(a, OP_EQ, "lolol");
tt_str_op(rest, OP_EQ, "");
tor_free(a);
tt_int_op(port_cfg_line_extract_addrport(" unix:lolol",
&a, &unixy, &rest), OP_EQ, 0);
tt_int_op(unixy, OP_EQ, 1);
- tt_str_op(a, OP_EQ, "lolol");;
+ tt_str_op(a, OP_EQ, "lolol");
tt_str_op(rest, OP_EQ, "");
tor_free(a);
tt_int_op(port_cfg_line_extract_addrport("foobar:lolol",
&a, &unixy, &rest), OP_EQ, 0);
tt_int_op(unixy, OP_EQ, 0);
- tt_str_op(a, OP_EQ, "foobar:lolol");;
+ tt_str_op(a, OP_EQ, "foobar:lolol");
tt_str_op(rest, OP_EQ, "");
tor_free(a);
tt_int_op(port_cfg_line_extract_addrport(":lolol",
&a, &unixy, &rest), OP_EQ, 0);
tt_int_op(unixy, OP_EQ, 0);
- tt_str_op(a, OP_EQ, ":lolol");;
+ tt_str_op(a, OP_EQ, ":lolol");
tt_str_op(rest, OP_EQ, "");
tor_free(a);
tt_int_op(port_cfg_line_extract_addrport("unix:\"lolol\"",
&a, &unixy, &rest), OP_EQ, 0);
tt_int_op(unixy, OP_EQ, 1);
- tt_str_op(a, OP_EQ, "lolol");;
+ tt_str_op(a, OP_EQ, "lolol");
tt_str_op(rest, OP_EQ, "");
tor_free(a);
tt_int_op(port_cfg_line_extract_addrport("unix:\"lolol\" ",
&a, &unixy, &rest), OP_EQ, 0);
tt_int_op(unixy, OP_EQ, 1);
- tt_str_op(a, OP_EQ, "lolol");;
+ tt_str_op(a, OP_EQ, "lolol");
tt_str_op(rest, OP_EQ, "");
tor_free(a);
tt_int_op(port_cfg_line_extract_addrport("unix:\"lolol\" foo ",
&a, &unixy, &rest), OP_EQ, 0);
tt_int_op(unixy, OP_EQ, 1);
- tt_str_op(a, OP_EQ, "lolol");;
+ tt_str_op(a, OP_EQ, "lolol");
tt_str_op(rest, OP_EQ, "foo ");
tor_free(a);
tt_int_op(port_cfg_line_extract_addrport("unix:\"lol ol\" foo ",
&a, &unixy, &rest), OP_EQ, 0);
tt_int_op(unixy, OP_EQ, 1);
- tt_str_op(a, OP_EQ, "lol ol");;
+ tt_str_op(a, OP_EQ, "lol ol");
tt_str_op(rest, OP_EQ, "foo ");
tor_free(a);
tt_int_op(port_cfg_line_extract_addrport("unix:\"lol\\\" ol\" foo ",
&a, &unixy, &rest), OP_EQ, 0);
tt_int_op(unixy, OP_EQ, 1);
- tt_str_op(a, OP_EQ, "lol\" ol");;
+ tt_str_op(a, OP_EQ, "lol\" ol");
tt_str_op(rest, OP_EQ, "foo ");
tor_free(a);
@@ -3861,144 +3884,6 @@ mock_config_line(const char *key, const char *val)
}
static void
-test_config_parse_port_config__listenaddress(void *data)
-{
- (void)data;
- int ret;
- config_line_t *config_listen_address = NULL, *config_listen_address2 = NULL,
- *config_listen_address3 = NULL;
- config_line_t *config_port1 = NULL, *config_port2 = NULL,
- *config_port3 = NULL, *config_port4 = NULL, *config_port5 = NULL;
- smartlist_t *slout = NULL;
- port_cfg_t *port_cfg = NULL;
-
- // Test basic invocation with no arguments
- ret = parse_port_config(NULL, NULL, NULL, NULL, 0, NULL, 0, 0);
- tt_int_op(ret, OP_EQ, 0);
-
- // Setup some test data
- config_listen_address = mock_config_line("DNSListenAddress", "127.0.0.1");
- config_listen_address2 = mock_config_line("DNSListenAddress", "x$$$:::345");
- config_listen_address3 = mock_config_line("DNSListenAddress",
- "127.0.0.1:1442");
- config_port1 = mock_config_line("DNSPort", "42");
- config_port2 = mock_config_line("DNSPort", "43");
- config_port1->next = config_port2;
- config_port3 = mock_config_line("DNSPort", "auto");
- config_port4 = mock_config_line("DNSPort", "55542");
- config_port5 = mock_config_line("DNSPort", "666777");
-
- // Test failure when we have a ListenAddress line and several
- // Port lines for the same portname
- ret = parse_port_config(NULL, config_port1, config_listen_address, "DNS", 0,
- NULL, 0, 0);
-
- tt_int_op(ret, OP_EQ, -1);
-
- // Test case when we have a listen address, no default port and allow
- // spurious listen address lines
- ret = parse_port_config(NULL, NULL, config_listen_address, "DNS", 0, NULL,
- 0, CL_PORT_ALLOW_EXTRA_LISTENADDR);
- tt_int_op(ret, OP_EQ, 1);
-
- // Test case when we have a listen address, no default port but doesn't
- // allow spurious listen address lines
- ret = parse_port_config(NULL, NULL, config_listen_address, "DNS", 0, NULL,
- 0, 0);
- tt_int_op(ret, OP_EQ, -1);
-
- // Test case when we have a listen address, and a port that points to auto,
- // should use the AUTO port
- slout = smartlist_new();
- ret = parse_port_config(slout, config_port3, config_listen_address, "DNS",
- 0, NULL, 0, 0);
- tt_int_op(ret, OP_EQ, 0);
- tt_int_op(smartlist_len(slout), OP_EQ, 1);
- port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
- tt_int_op(port_cfg->port, OP_EQ, CFG_AUTO_PORT);
-
- // Test when we have a listen address and a custom port
- ret = parse_port_config(slout, config_port4, config_listen_address, "DNS",
- 0, NULL, 0, 0);
- tt_int_op(ret, OP_EQ, 0);
- tt_int_op(smartlist_len(slout), OP_EQ, 2);
- port_cfg = (port_cfg_t *)smartlist_get(slout, 1);
- tt_int_op(port_cfg->port, OP_EQ, 55542);
-
- // Test when we have a listen address and an invalid custom port
- ret = parse_port_config(slout, config_port5, config_listen_address, "DNS",
- 0, NULL, 0, 0);
- tt_int_op(ret, OP_EQ, -1);
-
- // Test we get a server port configuration when asked for it
- ret = parse_port_config(slout, NULL, config_listen_address, "DNS", 0, NULL,
- 123, CL_PORT_SERVER_OPTIONS);
- tt_int_op(ret, OP_EQ, 0);
- tt_int_op(smartlist_len(slout), OP_EQ, 4);
- port_cfg = (port_cfg_t *)smartlist_get(slout, 2);
- tt_int_op(port_cfg->port, OP_EQ, 123);
- tt_int_op(port_cfg->server_cfg.no_listen, OP_EQ, 1);
- tt_int_op(port_cfg->server_cfg.bind_ipv4_only, OP_EQ, 1);
-
- // Test an invalid ListenAddress configuration
- ret = parse_port_config(NULL, NULL, config_listen_address2, "DNS", 0, NULL,
- 222, 0);
- tt_int_op(ret, OP_EQ, -1);
-
- // Test default to the port in the listen address if available
- ret = parse_port_config(slout, config_port2, config_listen_address3, "DNS",
- 0, NULL, 0, 0);
- tt_int_op(ret, OP_EQ, 0);
- tt_int_op(smartlist_len(slout), OP_EQ, 5);
- port_cfg = (port_cfg_t *)smartlist_get(slout, 4);
- tt_int_op(port_cfg->port, OP_EQ, 1442);
-
- // Test we work correctly without an out, but with a listen address
- // and a port
- ret = parse_port_config(NULL, config_port2, config_listen_address, "DNS",
- 0, NULL, 0, 0);
- tt_int_op(ret, OP_EQ, 0);
-
- // Test warning nonlocal control
- ret = parse_port_config(slout, config_port2, config_listen_address, "DNS",
- CONN_TYPE_CONTROL_LISTENER, NULL, 0,
- CL_PORT_WARN_NONLOCAL);
- tt_int_op(ret, OP_EQ, 0);
-
- // Test warning nonlocal ext or listener
- ret = parse_port_config(slout, config_port2, config_listen_address, "DNS",
- CONN_TYPE_EXT_OR_LISTENER, NULL, 0,
- CL_PORT_WARN_NONLOCAL);
- tt_int_op(ret, OP_EQ, 0);
-
- // Test warning nonlocal other
- SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
- smartlist_clear(slout);
- ret = parse_port_config(slout, config_port2, config_listen_address, "DNS",
- 0, NULL, 0, CL_PORT_WARN_NONLOCAL);
- tt_int_op(ret, OP_EQ, 0);
-
- // Test warning nonlocal control without an out
- ret = parse_port_config(NULL, config_port2, config_listen_address, "DNS",
- CONN_TYPE_CONTROL_LISTENER, NULL, 0,
- CL_PORT_WARN_NONLOCAL);
- tt_int_op(ret, OP_EQ, 0);
-
- done:
- config_free_lines(config_listen_address);
- config_free_lines(config_listen_address2);
- config_free_lines(config_listen_address3);
- config_free_lines(config_port1);
- /* 2 was linked from 1. */
- config_free_lines(config_port3);
- config_free_lines(config_port4);
- config_free_lines(config_port5);
- if (slout)
- SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
- smartlist_free(slout);
-}
-
-static void
test_config_parse_port_config__ports__no_ports_given(void *data)
{
(void)data;
@@ -4009,40 +3894,40 @@ test_config_parse_port_config__ports__no_ports_given(void *data)
slout = smartlist_new();
// Test no defaultport, no defaultaddress and no out
- ret = parse_port_config(NULL, NULL, NULL, "DNS", 0, NULL, 0, 0);
+ ret = parse_port_config(NULL, NULL, "DNS", 0, NULL, 0, 0);
tt_int_op(ret, OP_EQ, 0);
// Test with defaultport, no defaultaddress and no out
- ret = parse_port_config(NULL, NULL, NULL, "DNS", 0, NULL, 42, 0);
+ ret = parse_port_config(NULL, NULL, "DNS", 0, NULL, 42, 0);
tt_int_op(ret, OP_EQ, 0);
// Test no defaultport, with defaultaddress and no out
- ret = parse_port_config(NULL, NULL, NULL, "DNS", 0, "127.0.0.2", 0, 0);
+ ret = parse_port_config(NULL, NULL, "DNS", 0, "127.0.0.2", 0, 0);
tt_int_op(ret, OP_EQ, 0);
// Test with defaultport, with defaultaddress and no out
- ret = parse_port_config(NULL, NULL, NULL, "DNS", 0, "127.0.0.2", 42, 0);
+ ret = parse_port_config(NULL, NULL, "DNS", 0, "127.0.0.2", 42, 0);
tt_int_op(ret, OP_EQ, 0);
// Test no defaultport, no defaultaddress and with out
- ret = parse_port_config(slout, NULL, NULL, "DNS", 0, NULL, 0, 0);
+ ret = parse_port_config(slout, NULL, "DNS", 0, NULL, 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 0);
// Test with defaultport, no defaultaddress and with out
- ret = parse_port_config(slout, NULL, NULL, "DNS", 0, NULL, 42, 0);
+ ret = parse_port_config(slout, NULL, "DNS", 0, NULL, 42, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 0);
// Test no defaultport, with defaultaddress and with out
- ret = parse_port_config(slout, NULL, NULL, "DNS", 0, "127.0.0.2", 0, 0);
+ ret = parse_port_config(slout, NULL, "DNS", 0, "127.0.0.2", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 0);
// Test with defaultport, with defaultaddress and out, adds a new port cfg
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
- ret = parse_port_config(slout, NULL, NULL, "DNS", 0, "127.0.0.2", 42, 0);
+ ret = parse_port_config(slout, NULL, "DNS", 0, "127.0.0.2", 42, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
@@ -4053,7 +3938,7 @@ test_config_parse_port_config__ports__no_ports_given(void *data)
// for a unix address
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
- ret = parse_port_config(slout, NULL, NULL, "DNS", 0, "/foo/bar/unixdomain",
+ ret = parse_port_config(slout, NULL, "DNS", 0, "/foo/bar/unixdomain",
42, CL_PORT_IS_UNIXSOCKET);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4082,28 +3967,28 @@ test_config_parse_port_config__ports__ports_given(void *data)
// Test error when encounters an invalid Port specification
config_port_invalid = mock_config_line("DNSPort", "");
- ret = parse_port_config(NULL, config_port_invalid, NULL, "DNS", 0, NULL,
+ ret = parse_port_config(NULL, config_port_invalid, "DNS", 0, NULL,
0, 0);
tt_int_op(ret, OP_EQ, -1);
// Test error when encounters an empty unix domain specification
config_free_lines(config_port_invalid); config_port_invalid = NULL;
config_port_invalid = mock_config_line("DNSPort", "unix:");
- ret = parse_port_config(NULL, config_port_invalid, NULL, "DNS", 0, NULL,
+ ret = parse_port_config(NULL, config_port_invalid, "DNS", 0, NULL,
0, 0);
tt_int_op(ret, OP_EQ, -1);
// Test error when encounters a unix domain specification but the listener
// doesn't support domain sockets
config_port_valid = mock_config_line("DNSPort", "unix:/tmp/foo/bar");
- ret = parse_port_config(NULL, config_port_valid, NULL, "DNS",
+ ret = parse_port_config(NULL, config_port_valid, "DNS",
CONN_TYPE_AP_DNS_LISTENER, NULL, 0, 0);
tt_int_op(ret, OP_EQ, -1);
// Test valid unix domain
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
- ret = parse_port_config(slout, config_port_valid, NULL, "SOCKS",
+ ret = parse_port_config(slout, config_port_valid, "SOCKS",
CONN_TYPE_AP_LISTENER, NULL, 0, 0);
#ifdef _WIN32
tt_int_op(ret, OP_EQ, -1);
@@ -4118,16 +4003,17 @@ test_config_parse_port_config__ports__ports_given(void *data)
tt_int_op(port_cfg->entry_cfg.dns_request, OP_EQ, 1);
tt_int_op(port_cfg->entry_cfg.ipv4_traffic, OP_EQ, 1);
tt_int_op(port_cfg->entry_cfg.onion_traffic, OP_EQ, 1);
- tt_int_op(port_cfg->entry_cfg.cache_ipv4_answers, OP_EQ, 1);
+ tt_int_op(port_cfg->entry_cfg.cache_ipv4_answers, OP_EQ, 0);
tt_int_op(port_cfg->entry_cfg.prefer_ipv6_virtaddr, OP_EQ, 1);
-#endif
+#endif /* defined(_WIN32) */
// Test failure if we have no ipv4 and no ipv6 and no onion (DNS only)
config_free_lines(config_port_invalid); config_port_invalid = NULL;
config_port_invalid = mock_config_line("SOCKSPort",
"unix:/tmp/foo/bar NoIPv4Traffic "
+ "NoIPv6Traffic "
"NoOnionTraffic");
- ret = parse_port_config(NULL, config_port_invalid, NULL, "SOCKS",
+ ret = parse_port_config(NULL, config_port_invalid, "SOCKS",
CONN_TYPE_AP_LISTENER, NULL, 0,
CL_PORT_TAKES_HOSTNAMES);
tt_int_op(ret, OP_EQ, -1);
@@ -4136,7 +4022,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
config_free_lines(config_port_invalid); config_port_invalid = NULL;
config_port_invalid = mock_config_line("DNSPort",
"127.0.0.1:80 NoDNSRequest");
- ret = parse_port_config(NULL, config_port_invalid, NULL, "DNS",
+ ret = parse_port_config(NULL, config_port_invalid, "DNS",
CONN_TYPE_AP_DNS_LISTENER, NULL, 0,
CL_PORT_TAKES_HOSTNAMES);
tt_int_op(ret, OP_EQ, -1);
@@ -4147,8 +4033,9 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "127.0.0.1:80 "
+ "NoIPv6Traffic "
"NoIPv4Traffic NoOnionTraffic");
- ret = parse_port_config(slout, config_port_valid, NULL, "DNS",
+ ret = parse_port_config(slout, config_port_valid, "DNS",
CONN_TYPE_AP_DNS_LISTENER, NULL, 0,
CL_PORT_TAKES_HOSTNAMES);
tt_int_op(ret, OP_EQ, 0);
@@ -4162,8 +4049,9 @@ test_config_parse_port_config__ports__ports_given(void *data)
// Test failure if we have DNS but no ipv4 and no ipv6
config_free_lines(config_port_invalid); config_port_invalid = NULL;
config_port_invalid = mock_config_line("SOCKSPort",
+ "NoIPv6Traffic "
"unix:/tmp/foo/bar NoIPv4Traffic");
- ret = parse_port_config(NULL, config_port_invalid, NULL, "SOCKS",
+ ret = parse_port_config(NULL, config_port_invalid, "SOCKS",
CONN_TYPE_AP_LISTENER, NULL, 0,
CL_PORT_TAKES_HOSTNAMES);
tt_int_op(ret, OP_EQ, -1);
@@ -4174,8 +4062,9 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("SOCKSPort", "unix:/tmp/foo/bar "
+ "NoIPv6Traffic "
"NoDNSRequest NoIPv4Traffic");
- ret = parse_port_config(slout, config_port_valid, NULL, "SOCKS",
+ ret = parse_port_config(slout, config_port_valid, "SOCKS",
CONN_TYPE_AP_LISTENER, NULL, 0,
CL_PORT_TAKES_HOSTNAMES);
#ifdef _WIN32
@@ -4188,15 +4077,16 @@ test_config_parse_port_config__ports__ports_given(void *data)
tt_int_op(port_cfg->entry_cfg.ipv4_traffic, OP_EQ, 0);
tt_int_op(port_cfg->entry_cfg.ipv6_traffic, OP_EQ, 0);
tt_int_op(port_cfg->entry_cfg.onion_traffic, OP_EQ, 1);
-#endif
+#endif /* defined(_WIN32) */
// Test success with quoted unix: address.
config_free_lines(config_port_valid); config_port_valid = NULL;
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("SOCKSPort", "unix:\"/tmp/foo/ bar\" "
+ "NoIPv6Traffic "
"NoDNSRequest NoIPv4Traffic");
- ret = parse_port_config(slout, config_port_valid, NULL, "SOCKS",
+ ret = parse_port_config(slout, config_port_valid, "SOCKS",
CONN_TYPE_AP_LISTENER, NULL, 0,
CL_PORT_TAKES_HOSTNAMES);
#ifdef _WIN32
@@ -4209,15 +4099,16 @@ test_config_parse_port_config__ports__ports_given(void *data)
tt_int_op(port_cfg->entry_cfg.ipv4_traffic, OP_EQ, 0);
tt_int_op(port_cfg->entry_cfg.ipv6_traffic, OP_EQ, 0);
tt_int_op(port_cfg->entry_cfg.onion_traffic, OP_EQ, 1);
-#endif
+#endif /* defined(_WIN32) */
// Test failure with broken quoted unix: address.
config_free_lines(config_port_valid); config_port_valid = NULL;
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("SOCKSPort", "unix:\"/tmp/foo/ bar "
+ "NoIPv6Traffic "
"NoDNSRequest NoIPv4Traffic");
- ret = parse_port_config(slout, config_port_valid, NULL, "SOCKS",
+ ret = parse_port_config(slout, config_port_valid, "SOCKS",
CONN_TYPE_AP_LISTENER, NULL, 0,
CL_PORT_TAKES_HOSTNAMES);
tt_int_op(ret, OP_EQ, -1);
@@ -4227,8 +4118,9 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("SOCKSPort", "unix:\"\" "
+ "NoIPv6Traffic "
"NoDNSRequest NoIPv4Traffic");
- ret = parse_port_config(slout, config_port_valid, NULL, "SOCKS",
+ ret = parse_port_config(slout, config_port_valid, "SOCKS",
CONN_TYPE_AP_LISTENER, NULL, 0,
CL_PORT_TAKES_HOSTNAMES);
tt_int_op(ret, OP_EQ, -1);
@@ -4239,7 +4131,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
smartlist_clear(slout);
config_port_valid = mock_config_line("SOCKSPort", "unix:/tmp/foo/bar "
"OnionTrafficOnly");
- ret = parse_port_config(slout, config_port_valid, NULL, "SOCKS",
+ ret = parse_port_config(slout, config_port_valid, "SOCKS",
CONN_TYPE_AP_LISTENER, NULL, 0,
CL_PORT_TAKES_HOSTNAMES);
#ifdef _WIN32
@@ -4252,7 +4144,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
tt_int_op(port_cfg->entry_cfg.ipv4_traffic, OP_EQ, 0);
tt_int_op(port_cfg->entry_cfg.ipv6_traffic, OP_EQ, 0);
tt_int_op(port_cfg->entry_cfg.onion_traffic, OP_EQ, 1);
-#endif
+#endif /* defined(_WIN32) */
// Test success with no ipv4 but take ipv6
config_free_lines(config_port_valid); config_port_valid = NULL;
@@ -4260,7 +4152,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
smartlist_clear(slout);
config_port_valid = mock_config_line("SOCKSPort", "unix:/tmp/foo/bar "
"NoIPv4Traffic IPv6Traffic");
- ret = parse_port_config(slout, config_port_valid, NULL, "SOCKS",
+ ret = parse_port_config(slout, config_port_valid, "SOCKS",
CONN_TYPE_AP_LISTENER, NULL, 0,
CL_PORT_TAKES_HOSTNAMES);
#ifdef _WIN32
@@ -4271,7 +4163,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
tt_int_op(port_cfg->entry_cfg.ipv4_traffic, OP_EQ, 0);
tt_int_op(port_cfg->entry_cfg.ipv6_traffic, OP_EQ, 1);
-#endif
+#endif /* defined(_WIN32) */
// Test success with both ipv4 and ipv6
config_free_lines(config_port_valid); config_port_valid = NULL;
@@ -4279,7 +4171,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
smartlist_clear(slout);
config_port_valid = mock_config_line("SOCKSPort", "unix:/tmp/foo/bar "
"IPv4Traffic IPv6Traffic");
- ret = parse_port_config(slout, config_port_valid, NULL, "SOCKS",
+ ret = parse_port_config(slout, config_port_valid, "SOCKS",
CONN_TYPE_AP_LISTENER, NULL, 0,
CL_PORT_TAKES_HOSTNAMES);
#ifdef _WIN32
@@ -4290,33 +4182,33 @@ test_config_parse_port_config__ports__ports_given(void *data)
port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
tt_int_op(port_cfg->entry_cfg.ipv4_traffic, OP_EQ, 1);
tt_int_op(port_cfg->entry_cfg.ipv6_traffic, OP_EQ, 1);
-#endif
+#endif /* defined(_WIN32) */
// Test failure if we specify world writable for an IP Port
config_free_lines(config_port_invalid); config_port_invalid = NULL;
config_port_invalid = mock_config_line("DNSPort", "42 WorldWritable");
- ret = parse_port_config(NULL, config_port_invalid, NULL, "DNS", 0,
+ ret = parse_port_config(NULL, config_port_invalid, "DNS", 0,
"127.0.0.3", 0, 0);
tt_int_op(ret, OP_EQ, -1);
// Test failure if we specify group writable for an IP Port
config_free_lines(config_port_invalid); config_port_invalid = NULL;
config_port_invalid = mock_config_line("DNSPort", "42 GroupWritable");
- ret = parse_port_config(NULL, config_port_invalid, NULL, "DNS", 0,
+ ret = parse_port_config(NULL, config_port_invalid, "DNS", 0,
"127.0.0.3", 0, 0);
tt_int_op(ret, OP_EQ, -1);
// Test failure if we specify group writable for an IP Port
config_free_lines(config_port_invalid); config_port_invalid = NULL;
config_port_invalid = mock_config_line("DNSPort", "42 RelaxDirModeCheck");
- ret = parse_port_config(NULL, config_port_invalid, NULL, "DNS", 0,
+ ret = parse_port_config(NULL, config_port_invalid, "DNS", 0,
"127.0.0.3", 0, 0);
tt_int_op(ret, OP_EQ, -1);
// Test success with only a port (this will fail without a default address)
config_free_lines(config_port_valid); config_port_valid = NULL;
config_port_valid = mock_config_line("DNSPort", "42");
- ret = parse_port_config(NULL, config_port_valid, NULL, "DNS", 0,
+ ret = parse_port_config(NULL, config_port_valid, "DNS", 0,
"127.0.0.3", 0, 0);
tt_int_op(ret, OP_EQ, 0);
@@ -4325,7 +4217,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 IsolateDestPort");
- ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+ ret = parse_port_config(slout, config_port_valid, "DNS", 0,
"127.0.0.3", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4338,7 +4230,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 NoIsolateDestPorts");
- ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+ ret = parse_port_config(slout, config_port_valid, "DNS", 0,
"127.0.0.3", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4351,7 +4243,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 IsolateDestAddr");
- ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+ ret = parse_port_config(slout, config_port_valid, "DNS", 0,
"127.0.0.3", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4364,7 +4256,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 IsolateSOCKSAuth");
- ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+ ret = parse_port_config(slout, config_port_valid, "DNS", 0,
"127.0.0.3", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4377,7 +4269,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 IsolateClientProtocol");
- ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+ ret = parse_port_config(slout, config_port_valid, "DNS", 0,
"127.0.0.3", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4390,7 +4282,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 IsolateClientAddr");
- ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+ ret = parse_port_config(slout, config_port_valid, "DNS", 0,
"127.0.0.3", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4401,7 +4293,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
// Test success with ignored unknown options
config_free_lines(config_port_valid); config_port_valid = NULL;
config_port_valid = mock_config_line("DNSPort", "42 ThisOptionDoesntExist");
- ret = parse_port_config(NULL, config_port_valid, NULL, "DNS", 0,
+ ret = parse_port_config(NULL, config_port_valid, "DNS", 0,
"127.0.0.3", 0, 0);
tt_int_op(ret, OP_EQ, 0);
@@ -4410,7 +4302,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 NoIsolateSOCKSAuth");
- ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+ ret = parse_port_config(slout, config_port_valid, "DNS", 0,
"127.0.0.3", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4423,7 +4315,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
smartlist_clear(slout);
config_port_valid = mock_config_line("SOCKSPort",
"42 IPv6Traffic PreferIPv6");
- ret = parse_port_config(slout, config_port_valid, NULL, "SOCKS",
+ ret = parse_port_config(slout, config_port_valid, "SOCKS",
CONN_TYPE_AP_LISTENER, "127.0.0.42", 0,
CL_PORT_TAKES_HOSTNAMES);
tt_int_op(ret, OP_EQ, 0);
@@ -4436,7 +4328,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 CacheIPv4DNS");
- ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+ ret = parse_port_config(slout, config_port_valid, "DNS", 0,
"127.0.0.42", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4449,12 +4341,12 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 CacheIPv6DNS");
- ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+ ret = parse_port_config(slout, config_port_valid, "DNS", 0,
"127.0.0.42", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
- tt_int_op(port_cfg->entry_cfg.cache_ipv4_answers, OP_EQ, 1);
+ tt_int_op(port_cfg->entry_cfg.cache_ipv4_answers, OP_EQ, 0);
tt_int_op(port_cfg->entry_cfg.cache_ipv6_answers, OP_EQ, 1);
// Test success with no cache ipv4 DNS
@@ -4462,7 +4354,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 NoCacheIPv4DNS");
- ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+ ret = parse_port_config(slout, config_port_valid, "DNS", 0,
"127.0.0.42", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4475,7 +4367,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 CacheDNS");
- ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+ ret = parse_port_config(slout, config_port_valid, "DNS", 0,
"127.0.0.42", 0, CL_PORT_TAKES_HOSTNAMES);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4488,7 +4380,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 UseIPv4Cache");
- ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+ ret = parse_port_config(slout, config_port_valid, "DNS", 0,
"127.0.0.42", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4501,7 +4393,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 UseIPv6Cache");
- ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+ ret = parse_port_config(slout, config_port_valid, "DNS", 0,
"127.0.0.42", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4514,7 +4406,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 UseDNSCache");
- ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+ ret = parse_port_config(slout, config_port_valid, "DNS", 0,
"127.0.0.42", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4527,7 +4419,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 NoPreferIPv6Automap");
- ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+ ret = parse_port_config(slout, config_port_valid, "DNS", 0,
"127.0.0.42", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4539,7 +4431,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 PreferSOCKSNoAuth");
- ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+ ret = parse_port_config(slout, config_port_valid, "DNS", 0,
"127.0.0.42", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4554,14 +4446,14 @@ test_config_parse_port_config__ports__ports_given(void *data)
config_port_invalid = mock_config_line("DNSPort", "0");
config_port_valid = mock_config_line("DNSPort", "42");
config_port_invalid->next = config_port_valid;
- ret = parse_port_config(slout, config_port_invalid, NULL, "DNS", 0,
+ ret = parse_port_config(slout, config_port_invalid, "DNS", 0,
"127.0.0.42", 0, 0);
tt_int_op(ret, OP_EQ, -1);
// Test success with warn non-local control
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
- ret = parse_port_config(slout, config_port_valid, NULL, "Control",
+ ret = parse_port_config(slout, config_port_valid, "Control",
CONN_TYPE_CONTROL_LISTENER, "127.0.0.42", 0,
CL_PORT_WARN_NONLOCAL);
tt_int_op(ret, OP_EQ, 0);
@@ -4569,7 +4461,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
// Test success with warn non-local listener
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
- ret = parse_port_config(slout, config_port_valid, NULL, "ExtOR",
+ ret = parse_port_config(slout, config_port_valid, "ExtOR",
CONN_TYPE_EXT_OR_LISTENER, "127.0.0.42", 0,
CL_PORT_WARN_NONLOCAL);
tt_int_op(ret, OP_EQ, 0);
@@ -4577,12 +4469,12 @@ test_config_parse_port_config__ports__ports_given(void *data)
// Test success with warn non-local other
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
- ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+ ret = parse_port_config(slout, config_port_valid, "DNS", 0,
"127.0.0.42", 0, CL_PORT_WARN_NONLOCAL);
tt_int_op(ret, OP_EQ, 0);
// Test success with warn non-local other without out
- ret = parse_port_config(NULL, config_port_valid, NULL, "DNS", 0,
+ ret = parse_port_config(NULL, config_port_valid, "DNS", 0,
"127.0.0.42", 0, CL_PORT_WARN_NONLOCAL);
tt_int_op(ret, OP_EQ, 0);
@@ -4593,7 +4485,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 IPv4Traffic "
"IPv6Traffic");
- ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+ ret = parse_port_config(slout, config_port_valid, "DNS", 0,
"127.0.0.44", 0,
CL_PORT_TAKES_HOSTNAMES |
CL_PORT_NO_STREAM_OPTIONS);
@@ -4601,14 +4493,14 @@ test_config_parse_port_config__ports__ports_given(void *data)
tt_int_op(smartlist_len(slout), OP_EQ, 1);
port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
tt_int_op(port_cfg->entry_cfg.ipv4_traffic, OP_EQ, 1);
- tt_int_op(port_cfg->entry_cfg.ipv6_traffic, OP_EQ, 0);
+ tt_int_op(port_cfg->entry_cfg.ipv6_traffic, OP_EQ, 1);
// Test failure for a SessionGroup argument with invalid value
config_free_lines(config_port_invalid); config_port_invalid = NULL;
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_invalid = mock_config_line("DNSPort", "42 SessionGroup=invalid");
- ret = parse_port_config(slout, config_port_invalid, NULL, "DNS", 0,
+ ret = parse_port_config(slout, config_port_invalid, "DNS", 0,
"127.0.0.44", 0, CL_PORT_NO_STREAM_OPTIONS);
tt_int_op(ret, OP_EQ, -1);
@@ -4620,7 +4512,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_invalid = mock_config_line("DNSPort", "42 SessionGroup=123");
- ret = parse_port_config(slout, config_port_invalid, NULL, "DNS", 0,
+ ret = parse_port_config(slout, config_port_invalid, "DNS", 0,
"127.0.0.44", 0, 0);
tt_int_op(ret, OP_EQ, -1);
@@ -4630,7 +4522,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
smartlist_clear(slout);
config_port_invalid = mock_config_line("DNSPort", "42 SessionGroup=123 "
"SessionGroup=321");
- ret = parse_port_config(slout, config_port_invalid, NULL, "DNS", 0,
+ ret = parse_port_config(slout, config_port_invalid, "DNS", 0,
"127.0.0.44", 0, CL_PORT_NO_STREAM_OPTIONS);
tt_int_op(ret, OP_EQ, -1);
@@ -4639,7 +4531,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "42 SessionGroup=1111122");
- ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+ ret = parse_port_config(slout, config_port_valid, "DNS", 0,
"127.0.0.44", 0, CL_PORT_NO_STREAM_OPTIONS);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4651,7 +4543,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "0");
- ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+ ret = parse_port_config(slout, config_port_valid, "DNS", 0,
"127.0.0.45", 0, CL_PORT_IS_UNIXSOCKET);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 0);
@@ -4661,7 +4553,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "something");
- ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+ ret = parse_port_config(slout, config_port_valid, "DNS", 0,
"127.0.0.45", 0, CL_PORT_IS_UNIXSOCKET);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4674,7 +4566,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "auto");
- ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+ ret = parse_port_config(slout, config_port_valid, "DNS", 0,
"127.0.0.46", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4688,7 +4580,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "127.0.0.122:auto");
- ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+ ret = parse_port_config(slout, config_port_valid, "DNS", 0,
"127.0.0.46", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4700,8 +4592,10 @@ test_config_parse_port_config__ports__ports_given(void *data)
// Test failure when asked to parse an invalid address followed by auto
config_free_lines(config_port_invalid); config_port_invalid = NULL;
config_port_invalid = mock_config_line("DNSPort", "invalidstuff!!:auto");
- ret = parse_port_config(NULL, config_port_invalid, NULL, "DNS", 0,
+ MOCK(tor_addr_lookup, mock_tor_addr_lookup__fail_on_bad_addrs);
+ ret = parse_port_config(NULL, config_port_invalid, "DNS", 0,
"127.0.0.46", 0, 0);
+ UNMOCK(tor_addr_lookup);
tt_int_op(ret, OP_EQ, -1);
// Test success with parsing both an address and a real port
@@ -4709,7 +4603,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "127.0.0.123:656");
- ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0,
+ ret = parse_port_config(slout, config_port_valid, "DNS", 0,
"127.0.0.46", 0, 0);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4723,7 +4617,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_invalid = mock_config_line("DNSPort", "something wrong");
- ret = parse_port_config(slout, config_port_invalid, NULL, "DNS", 0,
+ ret = parse_port_config(slout, config_port_invalid, "DNS", 0,
"127.0.0.46", 0, 0);
tt_int_op(ret, OP_EQ, -1);
@@ -4732,7 +4626,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_invalid = mock_config_line("DNSPort", "127.0.1.0:123:auto");
- ret = parse_port_config(slout, config_port_invalid, NULL, "DNS", 0,
+ ret = parse_port_config(slout, config_port_invalid, "DNS", 0,
"127.0.0.46", 0, 0);
tt_int_op(ret, OP_EQ, -1);
@@ -4742,7 +4636,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("SOCKSPort", "unix:/tmp/somewhere");
- ret = parse_port_config(slout, config_port_valid, NULL, "SOCKS",
+ ret = parse_port_config(slout, config_port_valid, "SOCKS",
CONN_TYPE_AP_LISTENER, "127.0.0.46", 0,
CL_PORT_DFLT_GROUP_WRITABLE);
#ifdef _WIN32
@@ -4752,7 +4646,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
tt_int_op(smartlist_len(slout), OP_EQ, 1);
port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
tt_int_op(port_cfg->is_group_writable, OP_EQ, 1);
-#endif
+#endif /* defined(_WIN32) */
done:
if (slout)
@@ -4777,7 +4671,7 @@ test_config_parse_port_config__ports__server_options(void *data)
config_free_lines(config_port_valid); config_port_valid = NULL;
config_port_valid = mock_config_line("DNSPort",
"127.0.0.124:656 NoAdvertise");
- ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0, NULL, 0,
+ ret = parse_port_config(slout, config_port_valid, "DNS", 0, NULL, 0,
CL_PORT_SERVER_OPTIONS);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4790,7 +4684,7 @@ test_config_parse_port_config__ports__server_options(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "127.0.0.124:656 NoListen");
- ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0, NULL, 0,
+ ret = parse_port_config(slout, config_port_valid, "DNS", 0, NULL, 0,
CL_PORT_SERVER_OPTIONS);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4804,7 +4698,7 @@ test_config_parse_port_config__ports__server_options(void *data)
smartlist_clear(slout);
config_port_invalid = mock_config_line("DNSPort", "127.0.0.124:656 NoListen "
"NoAdvertise");
- ret = parse_port_config(slout, config_port_invalid, NULL, "DNS", 0, NULL,
+ ret = parse_port_config(slout, config_port_invalid, "DNS", 0, NULL,
0, CL_PORT_SERVER_OPTIONS);
tt_int_op(ret, OP_EQ, -1);
@@ -4813,7 +4707,7 @@ test_config_parse_port_config__ports__server_options(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "127.0.0.124:656 IPv4Only");
- ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0, NULL, 0,
+ ret = parse_port_config(slout, config_port_valid, "DNS", 0, NULL, 0,
CL_PORT_SERVER_OPTIONS);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4826,7 +4720,7 @@ test_config_parse_port_config__ports__server_options(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "[::1]:656 IPv6Only");
- ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0, NULL, 0,
+ ret = parse_port_config(slout, config_port_valid, "DNS", 0, NULL, 0,
CL_PORT_SERVER_OPTIONS);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4840,7 +4734,7 @@ test_config_parse_port_config__ports__server_options(void *data)
smartlist_clear(slout);
config_port_invalid = mock_config_line("DNSPort", "127.0.0.124:656 IPv6Only "
"IPv4Only");
- ret = parse_port_config(slout, config_port_invalid, NULL, "DNS", 0, NULL,
+ ret = parse_port_config(slout, config_port_invalid, "DNS", 0, NULL,
0, CL_PORT_SERVER_OPTIONS);
tt_int_op(ret, OP_EQ, -1);
@@ -4849,7 +4743,7 @@ test_config_parse_port_config__ports__server_options(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_valid = mock_config_line("DNSPort", "127.0.0.124:656 unknown");
- ret = parse_port_config(slout, config_port_valid, NULL, "DNS", 0, NULL, 0,
+ ret = parse_port_config(slout, config_port_valid, "DNS", 0, NULL, 0,
CL_PORT_SERVER_OPTIONS);
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
@@ -4860,7 +4754,7 @@ test_config_parse_port_config__ports__server_options(void *data)
smartlist_clear(slout);
config_port_invalid = mock_config_line("DNSPort",
"127.0.0.124:656 IPv6Only");
- ret = parse_port_config(slout, config_port_invalid, NULL, "DNS", 0, NULL,
+ ret = parse_port_config(slout, config_port_invalid, "DNS", 0, NULL,
0, CL_PORT_SERVER_OPTIONS);
tt_int_op(ret, OP_EQ, -1);
@@ -4869,7 +4763,7 @@ test_config_parse_port_config__ports__server_options(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_invalid = mock_config_line("DNSPort", "[::1]:656 IPv4Only");
- ret = parse_port_config(slout, config_port_invalid, NULL, "DNS", 0, NULL,
+ ret = parse_port_config(slout, config_port_invalid, "DNS", 0, NULL,
0, CL_PORT_SERVER_OPTIONS);
tt_int_op(ret, OP_EQ, -1);
@@ -4878,7 +4772,7 @@ test_config_parse_port_config__ports__server_options(void *data)
SMARTLIST_FOREACH(slout,port_cfg_t *,pf,port_cfg_free(pf));
smartlist_clear(slout);
config_port_invalid = mock_config_line("ORPort", "unix:\"\"");
- ret = parse_port_config(slout, config_port_invalid, NULL, "ORPort", 0, NULL,
+ ret = parse_port_config(slout, config_port_invalid, "ORPort", 0, NULL,
0, CL_PORT_SERVER_OPTIONS);
tt_int_op(ret, OP_EQ, -1);
@@ -4890,6 +4784,738 @@ test_config_parse_port_config__ports__server_options(void *data)
config_free_lines(config_port_valid); config_port_valid = NULL;
}
+static void
+test_config_parse_log_severity(void *data)
+{
+ int ret;
+ const char *severity_log_lines[] = {
+ "debug file /tmp/debug.log",
+ "debug\tfile /tmp/debug.log",
+ "[handshake]debug [~net,~mm]info notice stdout",
+ "[handshake]debug\t[~net,~mm]info\tnotice\tstdout",
+ NULL
+ };
+ int i;
+ log_severity_list_t *severity;
+
+ (void) data;
+
+ severity = tor_malloc(sizeof(log_severity_list_t));
+ for (i = 0; severity_log_lines[i]; i++) {
+ memset(severity, 0, sizeof(log_severity_list_t));
+ ret = parse_log_severity_config(&severity_log_lines[i], severity);
+ tt_int_op(ret, OP_EQ, 0);
+ }
+
+ done:
+ tor_free(severity);
+}
+
+static void
+test_config_include_limit(void *data)
+{
+ (void)data;
+
+ config_line_t *result = NULL;
+ char *torrc_path = NULL;
+ char *dir = tor_strdup(get_fname("test_include_limit"));
+ tt_ptr_op(dir, OP_NE, NULL);
+
+#ifdef _WIN32
+ tt_int_op(mkdir(dir), OP_EQ, 0);
+#else
+ tt_int_op(mkdir(dir, 0700), OP_EQ, 0);
+#endif
+
+ tor_asprintf(&torrc_path, "%s"PATH_SEPARATOR"torrc", dir);
+ char torrc_contents[1000];
+ tor_snprintf(torrc_contents, sizeof(torrc_contents), "%%include %s",
+ torrc_path);
+ tt_int_op(write_str_to_file(torrc_path, torrc_contents, 0), OP_EQ, 0);
+
+ tt_int_op(config_get_lines_include(torrc_contents, &result, 0, NULL),
+ OP_EQ, -1);
+
+ done:
+ config_free_lines(result);
+ tor_free(torrc_path);
+ tor_free(dir);
+}
+
+static void
+test_config_include_does_not_exist(void *data)
+{
+ (void)data;
+
+ config_line_t *result = NULL;
+ char *dir = tor_strdup(get_fname("test_include_does_not_exist"));
+ char *missing_path = NULL;
+ tt_ptr_op(dir, OP_NE, NULL);
+
+#ifdef _WIN32
+ tt_int_op(mkdir(dir), OP_EQ, 0);
+#else
+ tt_int_op(mkdir(dir, 0700), OP_EQ, 0);
+#endif
+
+ tor_asprintf(&missing_path, "%s"PATH_SEPARATOR"missing", dir);
+ char torrc_contents[1000];
+ tor_snprintf(torrc_contents, sizeof(torrc_contents), "%%include %s",
+ missing_path);
+
+ tt_int_op(config_get_lines_include(torrc_contents, &result, 0, NULL),
+ OP_EQ, -1);
+
+ done:
+ config_free_lines(result);
+ tor_free(dir);
+ tor_free(missing_path);
+}
+
+static void
+test_config_include_error_in_included_file(void *data)
+{
+ (void)data;
+ config_line_t *result = NULL;
+
+ char *dir = tor_strdup(get_fname("test_error_in_included_file"));
+ char *invalid_path = NULL;
+ tt_ptr_op(dir, OP_NE, NULL);
+
+#ifdef _WIN32
+ tt_int_op(mkdir(dir), OP_EQ, 0);
+#else
+ tt_int_op(mkdir(dir, 0700), OP_EQ, 0);
+#endif
+
+ tor_asprintf(&invalid_path, "%s"PATH_SEPARATOR"invalid", dir);
+ tt_int_op(write_str_to_file(invalid_path, "unclosed \"", 0), OP_EQ, 0);
+
+ char torrc_contents[1000];
+ tor_snprintf(torrc_contents, sizeof(torrc_contents), "%%include %s",
+ invalid_path);
+
+ tt_int_op(config_get_lines_include(torrc_contents, &result, 0, NULL),
+ OP_EQ, -1);
+
+ done:
+ config_free_lines(result);
+ tor_free(dir);
+ tor_free(invalid_path);
+}
+
+static void
+test_config_include_empty_file_folder(void *data)
+{
+ (void)data;
+ config_line_t *result = NULL;
+
+ char *folder_path = NULL;
+ char *file_path = NULL;
+ char *dir = tor_strdup(get_fname("test_include_empty_file_folder"));
+ tt_ptr_op(dir, OP_NE, NULL);
+
+#ifdef _WIN32
+ tt_int_op(mkdir(dir), OP_EQ, 0);
+#else
+ tt_int_op(mkdir(dir, 0700), OP_EQ, 0);
+#endif
+
+ tor_asprintf(&folder_path, "%s"PATH_SEPARATOR"empty_dir", dir);
+#ifdef _WIN32
+ tt_int_op(mkdir(folder_path), OP_EQ, 0);
+#else
+ tt_int_op(mkdir(folder_path, 0700), OP_EQ, 0);
+#endif
+ tor_asprintf(&file_path, "%s"PATH_SEPARATOR"empty_file", dir);
+ tt_int_op(write_str_to_file(file_path, "", 0), OP_EQ, 0);
+
+ char torrc_contents[1000];
+ tor_snprintf(torrc_contents, sizeof(torrc_contents),
+ "%%include %s\n"
+ "%%include %s\n",
+ folder_path, file_path);
+
+ int include_used;
+ tt_int_op(config_get_lines_include(torrc_contents, &result, 0,&include_used),
+ OP_EQ, 0);
+ tt_ptr_op(result, OP_EQ, NULL);
+ tt_int_op(include_used, OP_EQ, 1);
+
+ done:
+ config_free_lines(result);
+ tor_free(folder_path);
+ tor_free(file_path);
+ tor_free(dir);
+}
+
+#ifndef _WIN32
+static void
+test_config_include_no_permission(void *data)
+{
+ (void)data;
+ config_line_t *result = NULL;
+
+ char *folder_path = NULL;
+ char *dir = NULL;
+ if (geteuid() == 0)
+ tt_skip();
+
+ dir = tor_strdup(get_fname("test_include_forbidden_folder"));
+ tt_ptr_op(dir, OP_NE, NULL);
+
+ tt_int_op(mkdir(dir, 0700), OP_EQ, 0);
+
+ tor_asprintf(&folder_path, "%s"PATH_SEPARATOR"forbidden_dir", dir);
+ tt_int_op(mkdir(folder_path, 0100), OP_EQ, 0);
+
+ char torrc_contents[1000];
+ tor_snprintf(torrc_contents, sizeof(torrc_contents),
+ "%%include %s\n",
+ folder_path);
+
+ int include_used;
+ tt_int_op(config_get_lines_include(torrc_contents, &result, 0,&include_used),
+ OP_EQ, -1);
+ tt_ptr_op(result, OP_EQ, NULL);
+
+ done:
+ config_free_lines(result);
+ tor_free(folder_path);
+ if (dir)
+ chmod(dir, 0700);
+ tor_free(dir);
+}
+#endif
+
+static void
+test_config_include_recursion_before_after(void *data)
+{
+ (void)data;
+
+ config_line_t *result = NULL;
+ char *torrc_path = NULL;
+ char *dir = tor_strdup(get_fname("test_include_recursion_before_after"));
+ tt_ptr_op(dir, OP_NE, NULL);
+
+#ifdef _WIN32
+ tt_int_op(mkdir(dir), OP_EQ, 0);
+#else
+ tt_int_op(mkdir(dir, 0700), OP_EQ, 0);
+#endif
+
+ tor_asprintf(&torrc_path, "%s"PATH_SEPARATOR"torrc", dir);
+
+ char file_contents[1000];
+ const int limit = MAX_INCLUDE_RECURSION_LEVEL;
+ int i;
+ // Loop backwards so file_contents has the contents of the first file by the
+ // end of the loop
+ for (i = limit; i > 0; i--) {
+ if (i < limit) {
+ tor_snprintf(file_contents, sizeof(file_contents),
+ "Test %d\n"
+ "%%include %s%d\n"
+ "Test %d\n",
+ i, torrc_path, i + 1, 2 * limit - i);
+ } else {
+ tor_snprintf(file_contents, sizeof(file_contents), "Test %d\n", i);
+ }
+
+ if (i > 1) {
+ char *file_path = NULL;
+ tor_asprintf(&file_path, "%s%d", torrc_path, i);
+ tt_int_op(write_str_to_file(file_path, file_contents, 0), OP_EQ, 0);
+ tor_free(file_path);
+ }
+ }
+
+ int include_used;
+ tt_int_op(config_get_lines_include(file_contents, &result, 0, &include_used),
+ OP_EQ, 0);
+ tt_ptr_op(result, OP_NE, NULL);
+ tt_int_op(include_used, OP_EQ, 1);
+
+ int len = 0;
+ config_line_t *next;
+ for (next = result; next != NULL; next = next->next) {
+ char expected[10];
+ tor_snprintf(expected, sizeof(expected), "%d", len + 1);
+ tt_str_op(next->key, OP_EQ, "Test");
+ tt_str_op(next->value, OP_EQ, expected);
+ len++;
+ }
+ tt_int_op(len, OP_EQ, 2 * limit - 1);
+
+ done:
+ config_free_lines(result);
+ tor_free(dir);
+ tor_free(torrc_path);
+}
+
+static void
+test_config_include_recursion_after_only(void *data)
+{
+ (void)data;
+
+ config_line_t *result = NULL;
+ char *torrc_path = NULL;
+ char *dir = tor_strdup(get_fname("test_include_recursion_after_only"));
+ tt_ptr_op(dir, OP_NE, NULL);
+
+#ifdef _WIN32
+ tt_int_op(mkdir(dir), OP_EQ, 0);
+#else
+ tt_int_op(mkdir(dir, 0700), OP_EQ, 0);
+#endif
+
+ tor_asprintf(&torrc_path, "%s"PATH_SEPARATOR"torrc", dir);
+
+ char file_contents[1000];
+ const int limit = MAX_INCLUDE_RECURSION_LEVEL;
+ int i;
+ // Loop backwards so file_contents has the contents of the first file by the
+ // end of the loop
+ for (i = limit; i > 0; i--) {
+ int n = (i - limit - 1) * -1;
+ if (i < limit) {
+ tor_snprintf(file_contents, sizeof(file_contents),
+ "%%include %s%d\n"
+ "Test %d\n",
+ torrc_path, i + 1, n);
+ } else {
+ tor_snprintf(file_contents, sizeof(file_contents), "Test %d\n", n);
+ }
+
+ if (i > 1) {
+ char *file_path = NULL;
+ tor_asprintf(&file_path, "%s%d", torrc_path, i);
+ tt_int_op(write_str_to_file(file_path, file_contents, 0), OP_EQ, 0);
+ tor_free(file_path);
+ }
+ }
+
+ int include_used;
+ tt_int_op(config_get_lines_include(file_contents, &result, 0, &include_used),
+ OP_EQ, 0);
+ tt_ptr_op(result, OP_NE, NULL);
+ tt_int_op(include_used, OP_EQ, 1);
+
+ int len = 0;
+ config_line_t *next;
+ for (next = result; next != NULL; next = next->next) {
+ char expected[10];
+ tor_snprintf(expected, sizeof(expected), "%d", len + 1);
+ tt_str_op(next->key, OP_EQ, "Test");
+ tt_str_op(next->value, OP_EQ, expected);
+ len++;
+ }
+ tt_int_op(len, OP_EQ, limit);
+
+ done:
+ config_free_lines(result);
+ tor_free(dir);
+ tor_free(torrc_path);
+}
+
+static void
+test_config_include_folder_order(void *data)
+{
+ (void)data;
+
+ config_line_t *result = NULL;
+ char *torrcd = NULL;
+ char *path = NULL;
+ char *path2 = NULL;
+ char *dir = tor_strdup(get_fname("test_include_folder_order"));
+ tt_ptr_op(dir, OP_NE, NULL);
+
+#ifdef _WIN32
+ tt_int_op(mkdir(dir), OP_EQ, 0);
+#else
+ tt_int_op(mkdir(dir, 0700), OP_EQ, 0);
+#endif
+
+ tor_asprintf(&torrcd, "%s"PATH_SEPARATOR"%s", dir, "torrc.d");
+
+#ifdef _WIN32
+ tt_int_op(mkdir(torrcd), OP_EQ, 0);
+#else
+ tt_int_op(mkdir(torrcd, 0700), OP_EQ, 0);
+#endif
+
+ // test that files in subfolders are ignored
+ tor_asprintf(&path, "%s"PATH_SEPARATOR"%s", torrcd, "subfolder");
+
+#ifdef _WIN32
+ tt_int_op(mkdir(path), OP_EQ, 0);
+#else
+ tt_int_op(mkdir(path, 0700), OP_EQ, 0);
+#endif
+
+ tor_asprintf(&path2, "%s"PATH_SEPARATOR"%s", path, "01_ignore");
+ tt_int_op(write_str_to_file(path2, "ShouldNotSee 1\n", 0), OP_EQ, 0);
+ tor_free(path);
+
+ // test that files starting with . are ignored
+ tor_asprintf(&path, "%s"PATH_SEPARATOR"%s", torrcd, ".dot");
+ tt_int_op(write_str_to_file(path, "ShouldNotSee 2\n", 0), OP_EQ, 0);
+ tor_free(path);
+
+ // test file order
+ tor_asprintf(&path, "%s"PATH_SEPARATOR"%s", torrcd, "01_1st");
+ tt_int_op(write_str_to_file(path, "Test 1\n", 0), OP_EQ, 0);
+ tor_free(path);
+
+ tor_asprintf(&path, "%s"PATH_SEPARATOR"%s", torrcd, "02_2nd");
+ tt_int_op(write_str_to_file(path, "Test 2\n", 0), OP_EQ, 0);
+ tor_free(path);
+
+ tor_asprintf(&path, "%s"PATH_SEPARATOR"%s", torrcd, "aa_3rd");
+ tt_int_op(write_str_to_file(path, "Test 3\n", 0), OP_EQ, 0);
+ tor_free(path);
+
+ tor_asprintf(&path, "%s"PATH_SEPARATOR"%s", torrcd, "ab_4th");
+ tt_int_op(write_str_to_file(path, "Test 4\n", 0), OP_EQ, 0);
+ tor_free(path);
+
+ char torrc_contents[1000];
+ tor_snprintf(torrc_contents, sizeof(torrc_contents),
+ "%%include %s\n",
+ torrcd);
+
+ int include_used;
+ tt_int_op(config_get_lines_include(torrc_contents, &result, 0,&include_used),
+ OP_EQ, 0);
+ tt_ptr_op(result, OP_NE, NULL);
+ tt_int_op(include_used, OP_EQ, 1);
+
+ int len = 0;
+ config_line_t *next;
+ for (next = result; next != NULL; next = next->next) {
+ char expected[10];
+ tor_snprintf(expected, sizeof(expected), "%d", len + 1);
+ tt_str_op(next->key, OP_EQ, "Test");
+ tt_str_op(next->value, OP_EQ, expected);
+ len++;
+ }
+ tt_int_op(len, OP_EQ, 4);
+
+ done:
+ config_free_lines(result);
+ tor_free(torrcd);
+ tor_free(path);
+ tor_free(path2);
+ tor_free(dir);
+}
+
+static void
+test_config_include_path_syntax(void *data)
+{
+ (void)data;
+
+ config_line_t *result = NULL;
+ char *dir = tor_strdup(get_fname("test_include_path_syntax"));
+ char *esc_dir = NULL, *dir_with_pathsep = NULL,
+ *esc_dir_with_pathsep = NULL, *torrc_contents = NULL;
+ tt_ptr_op(dir, OP_NE, NULL);
+
+#ifdef _WIN32
+ tt_int_op(mkdir(dir), OP_EQ, 0);
+#else
+ tt_int_op(mkdir(dir, 0700), OP_EQ, 0);
+#endif
+
+ esc_dir = esc_for_log(dir);
+ tor_asprintf(&dir_with_pathsep, "%s%s", dir, PATH_SEPARATOR);
+ esc_dir_with_pathsep = esc_for_log(dir_with_pathsep);
+
+ tor_asprintf(&torrc_contents,
+ "%%include %s\n"
+ "%%include %s%s \n" // space to avoid suppressing newline
+ "%%include %s\n",
+ esc_dir,
+ dir, PATH_SEPARATOR,
+ esc_dir_with_pathsep);
+
+ int include_used;
+ tt_int_op(config_get_lines_include(torrc_contents, &result, 0,&include_used),
+ OP_EQ, 0);
+ tt_ptr_op(result, OP_EQ, NULL);
+ tt_int_op(include_used, OP_EQ, 1);
+
+ done:
+ config_free_lines(result);
+ tor_free(dir);
+ tor_free(torrc_contents);
+ tor_free(esc_dir);
+ tor_free(dir_with_pathsep);
+ tor_free(esc_dir_with_pathsep);
+}
+
+static void
+test_config_include_not_processed(void *data)
+{
+ (void)data;
+
+ char torrc_contents[1000] = "%include does_not_exist\n";
+ config_line_t *result = NULL;
+ tt_int_op(config_get_lines(torrc_contents, &result, 0),OP_EQ, 0);
+ tt_ptr_op(result, OP_NE, NULL);
+
+ int len = 0;
+ config_line_t *next;
+ for (next = result; next != NULL; next = next->next) {
+ tt_str_op(next->key, OP_EQ, "%include");
+ tt_str_op(next->value, OP_EQ, "does_not_exist");
+ len++;
+ }
+ tt_int_op(len, OP_EQ, 1);
+
+ done:
+ config_free_lines(result);
+}
+
+static void
+test_config_include_has_include(void *data)
+{
+ (void)data;
+
+ config_line_t *result = NULL;
+ char *dir = tor_strdup(get_fname("test_include_has_include"));
+ tt_ptr_op(dir, OP_NE, NULL);
+
+#ifdef _WIN32
+ tt_int_op(mkdir(dir), OP_EQ, 0);
+#else
+ tt_int_op(mkdir(dir, 0700), OP_EQ, 0);
+#endif
+
+ char torrc_contents[1000] = "Test 1\n";
+ int include_used;
+
+ tt_int_op(config_get_lines_include(torrc_contents, &result, 0,&include_used),
+ OP_EQ, 0);
+ tt_int_op(include_used, OP_EQ, 0);
+ config_free_lines(result);
+
+ tor_snprintf(torrc_contents, sizeof(torrc_contents), "%%include %s\n", dir);
+ tt_int_op(config_get_lines_include(torrc_contents, &result, 0,&include_used),
+ OP_EQ, 0);
+ tt_int_op(include_used, OP_EQ, 1);
+
+ done:
+ config_free_lines(result);
+ tor_free(dir);
+}
+
+static void
+test_config_include_flag_both_without(void *data)
+{
+ (void)data;
+
+ char *errmsg = NULL;
+ char conf_empty[1000];
+ tor_snprintf(conf_empty, sizeof(conf_empty),
+ "DataDirectory %s\n",
+ get_fname(NULL));
+ // test with defaults-torrc and torrc without include
+ int ret = options_init_from_string(conf_empty, conf_empty, CMD_RUN_UNITTESTS,
+ NULL, &errmsg);
+ tt_int_op(ret, OP_EQ, 0);
+
+ const or_options_t *options = get_options();
+ tt_int_op(options->IncludeUsed, OP_EQ, 0);
+
+ done:
+ tor_free(errmsg);
+}
+
+static void
+test_config_include_flag_torrc_only(void *data)
+{
+ (void)data;
+
+ char *errmsg = NULL;
+ char *path = NULL;
+ char *dir = tor_strdup(get_fname("test_include_flag_torrc_only"));
+ tt_ptr_op(dir, OP_NE, NULL);
+
+#ifdef _WIN32
+ tt_int_op(mkdir(dir), OP_EQ, 0);
+#else
+ tt_int_op(mkdir(dir, 0700), OP_EQ, 0);
+#endif
+
+ tor_asprintf(&path, "%s"PATH_SEPARATOR"%s", dir, "dummy");
+ tt_int_op(write_str_to_file(path, "\n", 0), OP_EQ, 0);
+
+ char conf_empty[1000];
+ tor_snprintf(conf_empty, sizeof(conf_empty),
+ "DataDirectory %s\n",
+ get_fname(NULL));
+ char conf_include[1000];
+ tor_snprintf(conf_include, sizeof(conf_include), "%%include %s", path);
+
+ // test with defaults-torrc without include and torrc with include
+ int ret = options_init_from_string(conf_empty, conf_include,
+ CMD_RUN_UNITTESTS, NULL, &errmsg);
+ tt_int_op(ret, OP_EQ, 0);
+
+ const or_options_t *options = get_options();
+ tt_int_op(options->IncludeUsed, OP_EQ, 1);
+
+ done:
+ tor_free(errmsg);
+ tor_free(path);
+ tor_free(dir);
+}
+
+static void
+test_config_include_flag_defaults_only(void *data)
+{
+ (void)data;
+
+ char *errmsg = NULL;
+ char *path = NULL;
+ char *dir = tor_strdup(get_fname("test_include_flag_defaults_only"));
+ tt_ptr_op(dir, OP_NE, NULL);
+
+#ifdef _WIN32
+ tt_int_op(mkdir(dir), OP_EQ, 0);
+#else
+ tt_int_op(mkdir(dir, 0700), OP_EQ, 0);
+#endif
+
+ tor_asprintf(&path, "%s"PATH_SEPARATOR"%s", dir, "dummy");
+ tt_int_op(write_str_to_file(path, "\n", 0), OP_EQ, 0);
+
+ char conf_empty[1000];
+ tor_snprintf(conf_empty, sizeof(conf_empty),
+ "DataDirectory %s\n",
+ get_fname(NULL));
+ char conf_include[1000];
+ tor_snprintf(conf_include, sizeof(conf_include), "%%include %s", path);
+
+ // test with defaults-torrc with include and torrc without include
+ int ret = options_init_from_string(conf_include, conf_empty,
+ CMD_RUN_UNITTESTS, NULL, &errmsg);
+ tt_int_op(ret, OP_EQ, 0);
+
+ const or_options_t *options = get_options();
+ tt_int_op(options->IncludeUsed, OP_EQ, 0);
+
+ done:
+ tor_free(errmsg);
+ tor_free(path);
+ tor_free(dir);
+}
+
+static void
+test_config_dup_and_filter(void *arg)
+{
+ (void)arg;
+ /* Test normal input. */
+ config_line_t *line = NULL;
+ config_line_append(&line, "abc", "def");
+ config_line_append(&line, "ghi", "jkl");
+ config_line_append(&line, "ABCD", "mno");
+
+ config_line_t *line_dup = config_lines_dup_and_filter(line, "aBc");
+ tt_ptr_op(line_dup, OP_NE, NULL);
+ tt_ptr_op(line_dup->next, OP_NE, NULL);
+ tt_ptr_op(line_dup->next->next, OP_EQ, NULL);
+
+ tt_str_op(line_dup->key, OP_EQ, "abc");
+ tt_str_op(line_dup->value, OP_EQ, "def");
+ tt_str_op(line_dup->next->key, OP_EQ, "ABCD");
+ tt_str_op(line_dup->next->value, OP_EQ, "mno");
+
+ /* empty output */
+ config_free_lines(line_dup);
+ line_dup = config_lines_dup_and_filter(line, "skdjfsdkljf");
+ tt_ptr_op(line_dup, OP_EQ, NULL);
+
+ /* empty input */
+ config_free_lines(line_dup);
+ line_dup = config_lines_dup_and_filter(NULL, "abc");
+ tt_ptr_op(line_dup, OP_EQ, NULL);
+
+ done:
+ config_free_lines(line);
+ config_free_lines(line_dup);
+}
+
+/* If we're not configured to be a bridge, but we set
+ * BridgeDistribution, then options_validate () should return -1. */
+static void
+test_config_check_bridge_distribution_setting_not_a_bridge(void *arg)
+{
+ or_options_t* options = get_options_mutable();
+ or_options_t* old_options = options;
+ or_options_t* default_options = options;
+ char* message = NULL;
+ int ret;
+
+ (void)arg;
+
+ options->BridgeRelay = 0;
+ options->BridgeDistribution = (char*)("https");
+
+ ret = options_validate(old_options, options, default_options, 0, &message);
+
+ tt_int_op(ret, OP_EQ, -1);
+ tt_str_op(message, OP_EQ, "You set BridgeDistribution, but you "
+ "didn't set BridgeRelay!");
+ done:
+ tor_free(message);
+ options->BridgeDistribution = NULL;
+}
+
+/* If the BridgeDistribution setting was valid, 0 should be returned. */
+static void
+test_config_check_bridge_distribution_setting_valid(void *arg)
+{
+ int ret = check_bridge_distribution_setting("https");
+
+ (void)arg;
+
+ tt_int_op(ret, OP_EQ, 0);
+ done:
+ return;
+}
+
+/* If the BridgeDistribution setting was invalid, -1 should be returned. */
+static void
+test_config_check_bridge_distribution_setting_invalid(void *arg)
+{
+ int ret = check_bridge_distribution_setting("hyphens-are-allowed");
+
+ (void)arg;
+
+ tt_int_op(ret, OP_EQ, 0);
+
+ ret = check_bridge_distribution_setting("asterisks*are*forbidden");
+
+ tt_int_op(ret, OP_EQ, -1);
+ done:
+ return;
+}
+
+/* If the BridgeDistribution setting was unrecognised, a warning should be
+ * logged and 0 should be returned. */
+static void
+test_config_check_bridge_distribution_setting_unrecognised(void *arg)
+{
+ int ret = check_bridge_distribution_setting("unicorn");
+
+ (void)arg;
+
+ tt_int_op(ret, OP_EQ, 0);
+ done:
+ return;
+}
+
#define CONFIG_TEST(name, flags) \
{ #name, test_config_ ## name, flags, NULL, NULL }
@@ -4912,10 +5538,31 @@ struct testcase_t config_tests[] = {
CONFIG_TEST(fix_my_family, 0),
CONFIG_TEST(directory_fetch, 0),
CONFIG_TEST(port_cfg_line_extract_addrport, 0),
- CONFIG_TEST(parse_port_config__listenaddress, 0),
CONFIG_TEST(parse_port_config__ports__no_ports_given, 0),
CONFIG_TEST(parse_port_config__ports__server_options, 0),
CONFIG_TEST(parse_port_config__ports__ports_given, 0),
+ CONFIG_TEST(parse_log_severity, 0),
+ CONFIG_TEST(include_limit, 0),
+ CONFIG_TEST(include_does_not_exist, 0),
+ CONFIG_TEST(include_error_in_included_file, 0),
+ CONFIG_TEST(include_empty_file_folder, 0),
+#ifndef _WIN32
+ CONFIG_TEST(include_no_permission, 0),
+#endif
+ CONFIG_TEST(include_recursion_before_after, 0),
+ CONFIG_TEST(include_recursion_after_only, 0),
+ CONFIG_TEST(include_folder_order, 0),
+ CONFIG_TEST(include_path_syntax, 0),
+ CONFIG_TEST(include_not_processed, 0),
+ CONFIG_TEST(include_has_include, 0),
+ CONFIG_TEST(include_flag_both_without, TT_FORK),
+ CONFIG_TEST(include_flag_torrc_only, TT_FORK),
+ CONFIG_TEST(include_flag_defaults_only, TT_FORK),
+ CONFIG_TEST(dup_and_filter, 0),
+ CONFIG_TEST(check_bridge_distribution_setting_not_a_bridge, TT_FORK),
+ CONFIG_TEST(check_bridge_distribution_setting_valid, 0),
+ CONFIG_TEST(check_bridge_distribution_setting_invalid, 0),
+ CONFIG_TEST(check_bridge_distribution_setting_unrecognised, 0),
END_OF_TESTCASES
};
diff --git a/src/test/test_connection.c b/src/test/test_connection.c
index d394fc9852..314b90cfda 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"
@@ -10,15 +10,15 @@
#include "test.h"
#include "connection.h"
+#include "hs_common.h"
#include "main.h"
#include "microdesc.h"
#include "networkstatus.h"
#include "rendcache.h"
#include "directory.h"
-static void test_conn_lookup_addr_helper(const char *address,
- int family,
- tor_addr_t *addr);
+#include "test_connection.h"
+#include "test_helpers.h"
static void * test_conn_get_basic_setup(const struct testcase_t *tc);
static int test_conn_get_basic_teardown(const struct testcase_t *tc,
@@ -61,48 +61,7 @@ static int test_conn_get_rsrc_teardown(const struct testcase_t *tc,
#define TEST_CONN_UNATTACHED_STATE (AP_CONN_STATE_CIRCUIT_WAIT)
#define TEST_CONN_ATTACHED_STATE (AP_CONN_STATE_CONNECT_WAIT)
-#define TEST_CONN_FD_INIT 50
-static int mock_connection_connect_sockaddr_called = 0;
-static int fake_socket_number = TEST_CONN_FD_INIT;
-
-static int
-mock_connection_connect_sockaddr(connection_t *conn,
- const struct sockaddr *sa,
- socklen_t sa_len,
- const struct sockaddr *bindaddr,
- socklen_t bindaddr_len,
- int *socket_error)
-{
- (void)sa_len;
- (void)bindaddr;
- (void)bindaddr_len;
-
- tor_assert(conn);
- tor_assert(sa);
- tor_assert(socket_error);
-
- mock_connection_connect_sockaddr_called++;
-
- conn->s = fake_socket_number++;
- tt_assert(SOCKET_OK(conn->s));
- /* We really should call tor_libevent_initialize() here. Because we don't,
- * we are relying on other parts of the code not checking if the_event_base
- * (and therefore event->ev_base) is NULL. */
- tt_assert(connection_add_connecting(conn) == 0);
-
- done:
- /* Fake "connected" status */
- return 1;
-}
-
-static int
-fake_close_socket(evutil_socket_t sock)
-{
- (void)sock;
- return 0;
-}
-
-static void
+void
test_conn_lookup_addr_helper(const char *address, int family, tor_addr_t *addr)
{
int rv = 0;
@@ -111,7 +70,7 @@ test_conn_lookup_addr_helper(const char *address, int family, tor_addr_t *addr)
rv = tor_addr_lookup(address, family, addr);
/* XXXX - should we retry on transient failure? */
- tt_assert(rv == 0);
+ tt_int_op(rv, OP_EQ, 0);
tt_assert(tor_addr_is_loopback(addr));
tt_assert(tor_addr_is_v4(addr));
@@ -121,51 +80,6 @@ test_conn_lookup_addr_helper(const char *address, int family, tor_addr_t *addr)
tor_addr_make_null(addr, TEST_CONN_FAMILY);
}
-static connection_t *
-test_conn_get_connection(uint8_t state, uint8_t type, uint8_t purpose)
-{
- connection_t *conn = NULL;
- tor_addr_t addr;
- int socket_err = 0;
- int in_progress = 0;
-
- MOCK(connection_connect_sockaddr,
- mock_connection_connect_sockaddr);
- MOCK(tor_close_socket, fake_close_socket);
-
- init_connection_lists();
-
- conn = connection_new(type, TEST_CONN_FAMILY);
- tt_assert(conn);
-
- test_conn_lookup_addr_helper(TEST_CONN_ADDRESS, TEST_CONN_FAMILY, &addr);
- tt_assert(!tor_addr_is_null(&addr));
-
- tor_addr_copy_tight(&conn->addr, &addr);
- conn->port = TEST_CONN_PORT;
- mock_connection_connect_sockaddr_called = 0;
- in_progress = connection_connect(conn, TEST_CONN_ADDRESS_PORT, &addr,
- TEST_CONN_PORT, &socket_err);
- tt_assert(mock_connection_connect_sockaddr_called == 1);
- tt_assert(!socket_err);
- tt_assert(in_progress == 0 || in_progress == 1);
-
- /* fake some of the attributes so the connection looks OK */
- conn->state = state;
- conn->purpose = purpose;
- assert_connection_ok(conn, time(NULL));
-
- UNMOCK(connection_connect_sockaddr);
- UNMOCK(tor_close_socket);
- return conn;
-
- /* On failure */
- done:
- UNMOCK(connection_connect_sockaddr);
- UNMOCK(tor_close_socket);
- return NULL;
-}
-
static void *
test_conn_get_basic_setup(const struct testcase_t *tc)
{
@@ -264,14 +178,10 @@ test_conn_get_rend_setup(const struct testcase_t *tc)
rend_cache_init();
- /* TODO: use directory_initiate_command_rend() to do this - maybe? */
- conn->rend_data = tor_malloc_zero(sizeof(rend_data_t));
+ /* TODO: use directory_initiate_request() to do this - maybe? */
tor_assert(strlen(TEST_CONN_REND_ADDR) == REND_SERVICE_ID_LEN_BASE32);
- memcpy(conn->rend_data->onion_address,
- TEST_CONN_REND_ADDR,
- REND_SERVICE_ID_LEN_BASE32+1);
- conn->rend_data->hsdirs_fp = smartlist_new();
-
+ conn->rend_data = rend_data_client_create(TEST_CONN_REND_ADDR, NULL, NULL,
+ REND_NO_AUTH);
assert_connection_ok(&conn->base_, time(NULL));
return conn;
@@ -382,7 +292,7 @@ test_conn_download_status_teardown(const struct testcase_t *tc, void *arg)
/* connection_free_() cleans up requested_resource */
rv = test_conn_get_rsrc_teardown(tc, conn);
- tt_assert(rv == 1);
+ tt_int_op(rv, OP_EQ, 1);
}
} SMARTLIST_FOREACH_END(conn);
@@ -456,12 +366,13 @@ test_conn_get_basic(void *arg)
* its attributes, but get NULL when we supply a different value. */
tt_assert(connection_get_by_global_id(conn->global_identifier) == conn);
- tt_assert(connection_get_by_global_id(!conn->global_identifier) == NULL);
+ tt_ptr_op(connection_get_by_global_id(!conn->global_identifier), OP_EQ,
+ NULL);
tt_assert(connection_get_by_type(conn->type) == conn);
tt_assert(connection_get_by_type(TEST_CONN_TYPE) == conn);
- tt_assert(connection_get_by_type(!conn->type) == NULL);
- tt_assert(connection_get_by_type(!TEST_CONN_TYPE) == NULL);
+ tt_ptr_op(connection_get_by_type(!conn->type), OP_EQ, NULL);
+ tt_ptr_op(connection_get_by_type(!TEST_CONN_TYPE), OP_EQ, NULL);
tt_assert(connection_get_by_type_state(conn->type, conn->state)
== conn);
@@ -551,7 +462,8 @@ test_conn_get_rend(void *arg)
tt_assert(connection_get_by_type_state_rendquery(
conn->base_.type,
conn->base_.state,
- conn->rend_data->onion_address)
+ rend_data_get_address(
+ conn->rend_data))
== TO_CONN(conn));
tt_assert(connection_get_by_type_state_rendquery(
TEST_CONN_TYPE,
@@ -574,7 +486,7 @@ test_conn_get_rend(void *arg)
#define sl_is_conn_assert(sl_input, conn) \
do { \
the_sl = (sl_input); \
- tt_assert(smartlist_len((the_sl)) == 1); \
+ tt_int_op(smartlist_len((the_sl)), OP_EQ, 1); \
tt_assert(smartlist_get((the_sl), 0) == (conn)); \
smartlist_free(the_sl); the_sl = NULL; \
} while (0)
@@ -582,7 +494,7 @@ test_conn_get_rend(void *arg)
#define sl_no_conn_assert(sl_input) \
do { \
the_sl = (sl_input); \
- tt_assert(smartlist_len((the_sl)) == 0); \
+ tt_int_op(smartlist_len((the_sl)), OP_EQ, 0); \
smartlist_free(the_sl); the_sl = NULL; \
} while (0)
@@ -628,43 +540,32 @@ test_conn_get_rsrc(void *arg)
TEST_CONN_RSRC_2,
!TEST_CONN_STATE));
- tt_assert(connection_dir_count_by_purpose_and_resource(
- conn->base_.purpose,
- conn->requested_resource)
- == 1);
- tt_assert(connection_dir_count_by_purpose_and_resource(
- TEST_CONN_RSRC_PURPOSE,
- TEST_CONN_RSRC)
- == 1);
- tt_assert(connection_dir_count_by_purpose_and_resource(
- !conn->base_.purpose,
- "")
- == 0);
- tt_assert(connection_dir_count_by_purpose_and_resource(
- !TEST_CONN_RSRC_PURPOSE,
- TEST_CONN_RSRC_2)
- == 0);
-
- tt_assert(connection_dir_count_by_purpose_resource_and_state(
- conn->base_.purpose,
- conn->requested_resource,
- conn->base_.state)
- == 1);
- tt_assert(connection_dir_count_by_purpose_resource_and_state(
- TEST_CONN_RSRC_PURPOSE,
- TEST_CONN_RSRC,
- TEST_CONN_STATE)
- == 1);
- tt_assert(connection_dir_count_by_purpose_resource_and_state(
- !conn->base_.purpose,
- "",
- !conn->base_.state)
- == 0);
- tt_assert(connection_dir_count_by_purpose_resource_and_state(
- !TEST_CONN_RSRC_PURPOSE,
- TEST_CONN_RSRC_2,
- !TEST_CONN_STATE)
- == 0);
+ tt_int_op(connection_dir_count_by_purpose_and_resource(
+ conn->base_.purpose, conn->requested_resource),
+ OP_EQ, 1);
+ tt_int_op(connection_dir_count_by_purpose_and_resource(
+ TEST_CONN_RSRC_PURPOSE, TEST_CONN_RSRC),
+ OP_EQ, 1);
+ tt_int_op(connection_dir_count_by_purpose_and_resource(
+ !conn->base_.purpose, ""),
+ OP_EQ, 0);
+ tt_int_op(connection_dir_count_by_purpose_and_resource(
+ !TEST_CONN_RSRC_PURPOSE, TEST_CONN_RSRC_2),
+ OP_EQ, 0);
+
+ tt_int_op(connection_dir_count_by_purpose_resource_and_state(
+ conn->base_.purpose, conn->requested_resource,
+ conn->base_.state),
+ OP_EQ, 1);
+ tt_int_op(connection_dir_count_by_purpose_resource_and_state(
+ TEST_CONN_RSRC_PURPOSE, TEST_CONN_RSRC, TEST_CONN_STATE),
+ OP_EQ, 1);
+ tt_int_op(connection_dir_count_by_purpose_resource_and_state(
+ !conn->base_.purpose, "", !conn->base_.state),
+ OP_EQ, 0);
+ tt_int_op(connection_dir_count_by_purpose_resource_and_state(
+ !TEST_CONN_RSRC_PURPOSE, TEST_CONN_RSRC_2, !TEST_CONN_STATE),
+ OP_EQ, 0);
done:
smartlist_free(the_sl);
@@ -690,117 +591,127 @@ test_conn_download_status(void *arg)
const char *other_res = networkstatus_get_flavor_name(other_flavor);
/* no connections */
- tt_assert(networkstatus_consensus_is_already_downloading(res) == 0);
- tt_assert(networkstatus_consensus_is_already_downloading(other_res) == 0);
- tt_assert(connection_dir_count_by_purpose_and_resource(
- TEST_CONN_RSRC_PURPOSE,
- res) == 0);
- tt_assert(connection_dir_count_by_purpose_and_resource(
- TEST_CONN_RSRC_PURPOSE,
- other_res) == 0);
+ tt_int_op(networkstatus_consensus_is_already_downloading(res), OP_EQ, 0);
+ tt_int_op(networkstatus_consensus_is_already_downloading(other_res), OP_EQ,
+ 0);
+ tt_int_op(connection_dir_count_by_purpose_and_resource(
+ TEST_CONN_RSRC_PURPOSE, res),
+ OP_EQ, 0);
+ tt_int_op(connection_dir_count_by_purpose_and_resource(
+ TEST_CONN_RSRC_PURPOSE, other_res),
+ OP_EQ, 0);
/* one connection, not downloading */
conn = test_conn_download_status_add_a_connection(res);
- tt_assert(networkstatus_consensus_is_already_downloading(res) == 0);
- tt_assert(networkstatus_consensus_is_already_downloading(other_res) == 0);
- tt_assert(connection_dir_count_by_purpose_and_resource(
- TEST_CONN_RSRC_PURPOSE,
- res) == 1);
- tt_assert(connection_dir_count_by_purpose_and_resource(
- TEST_CONN_RSRC_PURPOSE,
- other_res) == 0);
+ tt_int_op(networkstatus_consensus_is_already_downloading(res), OP_EQ, 0);
+ tt_int_op(networkstatus_consensus_is_already_downloading(other_res), OP_EQ,
+ 0);
+ tt_int_op(connection_dir_count_by_purpose_and_resource(
+ TEST_CONN_RSRC_PURPOSE, res),
+ OP_EQ, 1);
+ tt_int_op(connection_dir_count_by_purpose_and_resource(
+ TEST_CONN_RSRC_PURPOSE, other_res),
+ OP_EQ, 0);
/* one connection, downloading but not linked (not possible on a client,
* but possible on a relay) */
conn->base_.state = TEST_CONN_DL_STATE;
- tt_assert(networkstatus_consensus_is_already_downloading(res) == 0);
- tt_assert(networkstatus_consensus_is_already_downloading(other_res) == 0);
- tt_assert(connection_dir_count_by_purpose_and_resource(
- TEST_CONN_RSRC_PURPOSE,
- res) == 1);
- tt_assert(connection_dir_count_by_purpose_and_resource(
- TEST_CONN_RSRC_PURPOSE,
- other_res) == 0);
+ tt_int_op(networkstatus_consensus_is_already_downloading(res), OP_EQ, 0);
+ tt_int_op(networkstatus_consensus_is_already_downloading(other_res), OP_EQ,
+ 0);
+ tt_int_op(connection_dir_count_by_purpose_and_resource(
+ TEST_CONN_RSRC_PURPOSE, res),
+ OP_EQ, 1);
+ tt_int_op(connection_dir_count_by_purpose_and_resource(
+ TEST_CONN_RSRC_PURPOSE, other_res),
+ OP_EQ, 0);
/* one connection, downloading and linked, but not yet attached */
ap_conn = test_conn_get_linked_connection(TO_CONN(conn),
TEST_CONN_UNATTACHED_STATE);
- tt_assert(networkstatus_consensus_is_already_downloading(res) == 0);
- tt_assert(networkstatus_consensus_is_already_downloading(other_res) == 0);
- tt_assert(connection_dir_count_by_purpose_and_resource(
- TEST_CONN_RSRC_PURPOSE,
- res) == 1);
- tt_assert(connection_dir_count_by_purpose_and_resource(
- TEST_CONN_RSRC_PURPOSE,
- other_res) == 0);
+ tt_int_op(networkstatus_consensus_is_already_downloading(res), OP_EQ, 0);
+ tt_int_op(networkstatus_consensus_is_already_downloading(other_res), OP_EQ,
+ 0);
+ tt_int_op(connection_dir_count_by_purpose_and_resource(
+ TEST_CONN_RSRC_PURPOSE, res),
+ OP_EQ, 1);
+ tt_int_op(connection_dir_count_by_purpose_and_resource(
+ TEST_CONN_RSRC_PURPOSE, other_res),
+ OP_EQ, 0);
/* one connection, downloading and linked and attached */
ap_conn->state = TEST_CONN_ATTACHED_STATE;
- tt_assert(networkstatus_consensus_is_already_downloading(res) == 1);
- tt_assert(networkstatus_consensus_is_already_downloading(other_res) == 0);
- tt_assert(connection_dir_count_by_purpose_and_resource(
- TEST_CONN_RSRC_PURPOSE,
- res) == 1);
- tt_assert(connection_dir_count_by_purpose_and_resource(
- TEST_CONN_RSRC_PURPOSE,
- other_res) == 0);
+ tt_int_op(networkstatus_consensus_is_already_downloading(res), OP_EQ, 1);
+ tt_int_op(networkstatus_consensus_is_already_downloading(other_res), OP_EQ,
+ 0);
+ tt_int_op(connection_dir_count_by_purpose_and_resource(
+ TEST_CONN_RSRC_PURPOSE, res),
+ OP_EQ, 1);
+ tt_int_op(connection_dir_count_by_purpose_and_resource(
+ TEST_CONN_RSRC_PURPOSE, other_res),
+ OP_EQ, 0);
/* one connection, linked and attached but not downloading */
conn->base_.state = TEST_CONN_STATE;
- tt_assert(networkstatus_consensus_is_already_downloading(res) == 0);
- tt_assert(networkstatus_consensus_is_already_downloading(other_res) == 0);
- tt_assert(connection_dir_count_by_purpose_and_resource(
- TEST_CONN_RSRC_PURPOSE,
- res) == 1);
- tt_assert(connection_dir_count_by_purpose_and_resource(
- TEST_CONN_RSRC_PURPOSE,
- other_res) == 0);
+ tt_int_op(networkstatus_consensus_is_already_downloading(res), OP_EQ, 0);
+ tt_int_op(networkstatus_consensus_is_already_downloading(other_res), OP_EQ,
+ 0);
+ tt_int_op(connection_dir_count_by_purpose_and_resource(
+ TEST_CONN_RSRC_PURPOSE, res),
+ OP_EQ, 1);
+ tt_int_op(connection_dir_count_by_purpose_and_resource(
+ TEST_CONN_RSRC_PURPOSE, other_res),
+ OP_EQ, 0);
/* two connections, both not downloading */
conn2 = test_conn_download_status_add_a_connection(res);
- tt_assert(networkstatus_consensus_is_already_downloading(res) == 0);
- tt_assert(networkstatus_consensus_is_already_downloading(other_res) == 0);
- tt_assert(connection_dir_count_by_purpose_and_resource(
- TEST_CONN_RSRC_PURPOSE,
- res) == 2);
- tt_assert(connection_dir_count_by_purpose_and_resource(
- TEST_CONN_RSRC_PURPOSE,
- other_res) == 0);
+ tt_int_op(networkstatus_consensus_is_already_downloading(res), OP_EQ, 0);
+ tt_int_op(networkstatus_consensus_is_already_downloading(other_res), OP_EQ,
+ 0);
+ tt_int_op(connection_dir_count_by_purpose_and_resource(
+ TEST_CONN_RSRC_PURPOSE, res),
+ OP_EQ, 2);
+ tt_int_op(connection_dir_count_by_purpose_and_resource(
+ TEST_CONN_RSRC_PURPOSE, other_res),
+ OP_EQ, 0);
/* two connections, one downloading */
conn->base_.state = TEST_CONN_DL_STATE;
- tt_assert(networkstatus_consensus_is_already_downloading(res) == 1);
- tt_assert(networkstatus_consensus_is_already_downloading(other_res) == 0);
- tt_assert(connection_dir_count_by_purpose_and_resource(
- TEST_CONN_RSRC_PURPOSE,
- res) == 2);
- tt_assert(connection_dir_count_by_purpose_and_resource(
- TEST_CONN_RSRC_PURPOSE,
- other_res) == 0);
+ tt_int_op(networkstatus_consensus_is_already_downloading(res), OP_EQ, 1);
+ tt_int_op(networkstatus_consensus_is_already_downloading(other_res), OP_EQ,
+ 0);
+ tt_int_op(connection_dir_count_by_purpose_and_resource(
+ TEST_CONN_RSRC_PURPOSE, res),
+ OP_EQ, 2);
+ tt_int_op(connection_dir_count_by_purpose_and_resource(
+ TEST_CONN_RSRC_PURPOSE, other_res),
+ OP_EQ, 0);
conn->base_.state = TEST_CONN_STATE;
/* more connections, all not downloading */
/* ignore the return value, it's free'd using the connection list */
(void)test_conn_download_status_add_a_connection(res);
- tt_assert(networkstatus_consensus_is_already_downloading(res) == 0);
- tt_assert(networkstatus_consensus_is_already_downloading(other_res) == 0);
- tt_assert(connection_dir_count_by_purpose_and_resource(
- TEST_CONN_RSRC_PURPOSE,
- res) == 3);
- tt_assert(connection_dir_count_by_purpose_and_resource(
- TEST_CONN_RSRC_PURPOSE,
- other_res) == 0);
+ tt_int_op(networkstatus_consensus_is_already_downloading(res), OP_EQ, 0);
+ tt_int_op(networkstatus_consensus_is_already_downloading(other_res), OP_EQ,
+ 0);
+ tt_int_op(connection_dir_count_by_purpose_and_resource(
+ TEST_CONN_RSRC_PURPOSE, res),
+ OP_EQ, 3);
+ tt_int_op(connection_dir_count_by_purpose_and_resource(
+ TEST_CONN_RSRC_PURPOSE, other_res),
+ OP_EQ, 0);
/* more connections, one downloading */
conn->base_.state = TEST_CONN_DL_STATE;
- tt_assert(networkstatus_consensus_is_already_downloading(res) == 1);
- tt_assert(networkstatus_consensus_is_already_downloading(other_res) == 0);
- tt_assert(connection_dir_count_by_purpose_and_resource(
- TEST_CONN_RSRC_PURPOSE,
- res) == 3);
- tt_assert(connection_dir_count_by_purpose_and_resource(
- TEST_CONN_RSRC_PURPOSE,
- other_res) == 0);
+ tt_int_op(networkstatus_consensus_is_already_downloading(res), OP_EQ, 1);
+ tt_int_op(networkstatus_consensus_is_already_downloading(other_res), OP_EQ,
+ 0);
+ tt_int_op(connection_dir_count_by_purpose_and_resource(
+ TEST_CONN_RSRC_PURPOSE, res),
+ OP_EQ, 3);
+ tt_int_op(connection_dir_count_by_purpose_and_resource(
+ TEST_CONN_RSRC_PURPOSE, other_res),
+ OP_EQ, 0);
/* more connections, two downloading (should never happen, but needs
* to be tested for completeness) */
@@ -808,38 +719,41 @@ test_conn_download_status(void *arg)
/* ignore the return value, it's free'd using the connection list */
(void)test_conn_get_linked_connection(TO_CONN(conn2),
TEST_CONN_ATTACHED_STATE);
- tt_assert(networkstatus_consensus_is_already_downloading(res) == 1);
- tt_assert(networkstatus_consensus_is_already_downloading(other_res) == 0);
- tt_assert(connection_dir_count_by_purpose_and_resource(
- TEST_CONN_RSRC_PURPOSE,
- res) == 3);
- tt_assert(connection_dir_count_by_purpose_and_resource(
- TEST_CONN_RSRC_PURPOSE,
- other_res) == 0);
+ tt_int_op(networkstatus_consensus_is_already_downloading(res), OP_EQ, 1);
+ tt_int_op(networkstatus_consensus_is_already_downloading(other_res), OP_EQ,
+ 0);
+ tt_int_op(connection_dir_count_by_purpose_and_resource(
+ TEST_CONN_RSRC_PURPOSE, res),
+ OP_EQ, 3);
+ tt_int_op(connection_dir_count_by_purpose_and_resource(
+ TEST_CONN_RSRC_PURPOSE, other_res),
+ OP_EQ, 0);
conn->base_.state = TEST_CONN_STATE;
/* more connections, a different one downloading */
- tt_assert(networkstatus_consensus_is_already_downloading(res) == 1);
- tt_assert(networkstatus_consensus_is_already_downloading(other_res) == 0);
- tt_assert(connection_dir_count_by_purpose_and_resource(
- TEST_CONN_RSRC_PURPOSE,
- res) == 3);
- tt_assert(connection_dir_count_by_purpose_and_resource(
- TEST_CONN_RSRC_PURPOSE,
- other_res) == 0);
+ tt_int_op(networkstatus_consensus_is_already_downloading(res), OP_EQ, 1);
+ tt_int_op(networkstatus_consensus_is_already_downloading(other_res), OP_EQ,
+ 0);
+ tt_int_op(connection_dir_count_by_purpose_and_resource(
+ TEST_CONN_RSRC_PURPOSE, res),
+ OP_EQ, 3);
+ tt_int_op(connection_dir_count_by_purpose_and_resource(
+ TEST_CONN_RSRC_PURPOSE, other_res),
+ OP_EQ, 0);
/* a connection for the other flavor (could happen if a client is set to
* cache directory documents), one preferred flavor downloading
*/
conn4 = test_conn_download_status_add_a_connection(other_res);
- tt_assert(networkstatus_consensus_is_already_downloading(res) == 1);
- tt_assert(networkstatus_consensus_is_already_downloading(other_res) == 0);
- tt_assert(connection_dir_count_by_purpose_and_resource(
- TEST_CONN_RSRC_PURPOSE,
- res) == 3);
- tt_assert(connection_dir_count_by_purpose_and_resource(
- TEST_CONN_RSRC_PURPOSE,
- other_res) == 1);
+ tt_int_op(networkstatus_consensus_is_already_downloading(res), OP_EQ, 1);
+ tt_int_op(networkstatus_consensus_is_already_downloading(other_res), OP_EQ,
+ 0);
+ tt_int_op(connection_dir_count_by_purpose_and_resource(
+ TEST_CONN_RSRC_PURPOSE, res),
+ OP_EQ, 3);
+ tt_int_op(connection_dir_count_by_purpose_and_resource(
+ TEST_CONN_RSRC_PURPOSE, other_res),
+ OP_EQ, 1);
/* a connection for the other flavor (could happen if a client is set to
* cache directory documents), both flavors downloading
@@ -848,14 +762,15 @@ test_conn_download_status(void *arg)
/* ignore the return value, it's free'd using the connection list */
(void)test_conn_get_linked_connection(TO_CONN(conn4),
TEST_CONN_ATTACHED_STATE);
- tt_assert(networkstatus_consensus_is_already_downloading(res) == 1);
- tt_assert(networkstatus_consensus_is_already_downloading(other_res) == 1);
- tt_assert(connection_dir_count_by_purpose_and_resource(
- TEST_CONN_RSRC_PURPOSE,
- res) == 3);
- tt_assert(connection_dir_count_by_purpose_and_resource(
- TEST_CONN_RSRC_PURPOSE,
- other_res) == 1);
+ tt_int_op(networkstatus_consensus_is_already_downloading(res), OP_EQ, 1);
+ tt_int_op(networkstatus_consensus_is_already_downloading(other_res), OP_EQ,
+ 1);
+ tt_int_op(connection_dir_count_by_purpose_and_resource(
+ TEST_CONN_RSRC_PURPOSE, res),
+ OP_EQ, 3);
+ tt_int_op(connection_dir_count_by_purpose_and_resource(
+ TEST_CONN_RSRC_PURPOSE, other_res),
+ OP_EQ, 1);
done:
/* the teardown function removes all the connections in the global list*/;
diff --git a/src/test/test_connection.h b/src/test/test_connection.h
new file mode 100644
index 0000000000..392783b53b
--- /dev/null
+++ b/src/test/test_connection.h
@@ -0,0 +1,13 @@
+/* Copyright (c) 2014-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/** Some constants used by test_connection and helpers */
+#define TEST_CONN_FAMILY (AF_INET)
+#define TEST_CONN_ADDRESS "127.0.0.1"
+#define TEST_CONN_PORT (12345)
+#define TEST_CONN_ADDRESS_PORT "127.0.0.1:12345"
+#define TEST_CONN_FD_INIT 50
+
+void test_conn_lookup_addr_helper(const char *address,
+ int family, tor_addr_t *addr);
+
diff --git a/src/test/test_conscache.c b/src/test/test_conscache.c
new file mode 100644
index 0000000000..ddb1bc53c1
--- /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_ptr_op(e_tmp, OP_EQ, 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_ptr_op(e_tmp, OP_EQ, NULL); // so deleted.
+ e_tmp = consensus_cache_find_first(cache, "index", "14"); // refcnt == 2
+ tt_ptr_op(e_tmp, OP_EQ, 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..fda3a7f186
--- /dev/null
+++ b/src/test/test_consdiff.c
@@ -0,0 +1,1185 @@
+/* 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;
+ int items[6] = {0,0,0,0,0,0};
+
+ /* Create a regular smartlist. */
+ (void)arg;
+ smartlist_add(sl, &items[1]);
+ smartlist_add(sl, &items[2]);
+ smartlist_add(sl, &items[3]);
+ smartlist_add(sl, &items[4]);
+ smartlist_add(sl, &items[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(&items[3], OP_EQ, smartlist_get(sls->list, sls->offset));
+ tt_ptr_op(&items[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(&items[3], OP_EQ, smartlist_get(sls->list, sls->offset));
+ tt_ptr_op(&items[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(strcmp("/foo", "Afoo"), OP_LT, 0);
+ tt_int_op(base64cmp_wrapper("/foo", "Afoo"), OP_GT, 0);
+ tt_int_op(strcmp("Afoo", "0foo"), OP_GT, 0);
+ tt_int_op(base64cmp_wrapper("Afoo", "0foo"), OP_LT, 0);
+
+ /* Comparisons that would return the same as with strcmp(). */
+ tt_int_op(strcmp("afoo", "Afoo"), OP_GT, 0);
+ tt_int_op(base64cmp_wrapper("afoo", "Afoo"), OP_GT, 0);
+
+ /* Different lengths */
+ tt_int_op(base64cmp_wrapper("afoo", "afooo"), OP_LT, 0);
+ tt_int_op(base64cmp_wrapper("afooo", "afoo"), OP_GT, 0);
+
+ 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);
+
+ /* $ for a non-delete command. */
+ smartlist_add_linecpy(diff, area, "1,$c");
+ mock_clean_saved_logs();
+ cons2 = apply_ed_diff(cons1, diff, 0);
+ tt_ptr_op(NULL, OP_EQ, cons2);
+ expect_single_log_msg_containing("it wanted to use $ with a command "
+ "other than delete");
+
+ 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_as_signed(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_as_signed(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(11, 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 "
+ "95D70F5A3CC65F920AA8B44C4563D7781A082674329661884E19E94B79D539C2 "
+ "7AFECEFA4599BA33D603653E3D2368F648DF4AC4723929B0F7CF39281596B0C1"));
+ tt_assert(line_str_eq(smartlist_get(diff, 2), "6,$d"));
+ tt_assert(line_str_eq(smartlist_get(diff, 3), "3,4c"));
+ tt_assert(line_str_eq(smartlist_get(diff, 4), "bar"));
+ tt_assert(line_str_eq(smartlist_get(diff, 5),
+ "directory-signature foo bar"));
+ tt_assert(line_str_eq(smartlist_get(diff, 6),
+ "."));
+ tt_assert(line_str_eq(smartlist_get(diff, 7), "1a"));
+ tt_assert(line_str_eq(smartlist_get(diff, 8),
+ "r name aaaaaaaaaaaaaaaaa etc"));
+ tt_assert(line_str_eq(smartlist_get(diff, 9), "foo"));
+ tt_assert(line_str_eq(smartlist_get(diff, 10), "."));
+
+ /* 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 /* 0 */
+
+ /* 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..80d3f943ab
--- /dev/null
+++ b/src/test/test_consdiffmgr.c
@@ -0,0 +1,896 @@
+/* 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 "routerparse.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 = { 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 *random_stuff2 = crypto_random_hostname(3, 10, "", "");
+
+ 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"
+ "directory-signature hello-there\n"
+ "directory-signature %s\n",
+ flavor_string,
+ valid_after_string,
+ random_stuff,
+ random_stuff2);
+ tor_free(random_stuff);
+ tor_free(random_stuff2);
+ 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(workqueue_priority_t prio,
+ enum workqueue_reply_t (*fn)(void *, void *),
+ void (*reply_fn)(void *),
+ void *arg)
+{
+ (void) prio;
+
+ 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];
+ if (router_get_networkstatus_v3_sha3_as_signed(digest, str1)<0) {
+ TT_FAIL(("Unable to compute sha3-as-signed"));
+ return CONSDIFF_NOT_FOUND;
+ }
+ 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 /* 0 */
+
+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_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_ptr_op(cdm_cache_lookup_consensus(FLAV_MICRODESC, now - 60), OP_EQ, NULL);
+ tt_ptr_op(cdm_cache_lookup_consensus(FLAV_NS, now - 61), OP_EQ, NULL);
+
+ 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);
+ router_get_networkstatus_v3_sha3_as_signed(md_ns_sha3, md_ns_body);
+ 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];
+ 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);
+ }
+
+ /* 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];
+ 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);
+ }
+
+ /* 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, and make delete */
+ tt_int_op(0, OP_EQ, consdiffmgr_add_consensus(md_body[3], md_ns[3]));
+ tt_int_op(2 * n_diff_compression_methods() +
+ (n_consensus_compression_methods() - 1) , 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 d8b82e0661..c4dba73750 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"
@@ -501,31 +501,31 @@ test_container_smartlist_pos(void *arg)
(void) arg;
smartlist_t *sl = smartlist_new();
- smartlist_add(sl, tor_strdup("This"));
- smartlist_add(sl, tor_strdup("is"));
- smartlist_add(sl, tor_strdup("a"));
- smartlist_add(sl, tor_strdup("test"));
- smartlist_add(sl, tor_strdup("for"));
- smartlist_add(sl, tor_strdup("a"));
- smartlist_add(sl, tor_strdup("function"));
+ smartlist_add_strdup(sl, "This");
+ smartlist_add_strdup(sl, "is");
+ smartlist_add_strdup(sl, "a");
+ smartlist_add_strdup(sl, "test");
+ smartlist_add_strdup(sl, "for");
+ smartlist_add_strdup(sl, "a");
+ smartlist_add_strdup(sl, "function");
/* Test string_pos */
- tt_int_op(smartlist_string_pos(NULL, "Fred"), ==, -1);
- tt_int_op(smartlist_string_pos(sl, "Fred"), ==, -1);
- tt_int_op(smartlist_string_pos(sl, "This"), ==, 0);
- tt_int_op(smartlist_string_pos(sl, "a"), ==, 2);
- tt_int_op(smartlist_string_pos(sl, "function"), ==, 6);
+ tt_int_op(smartlist_string_pos(NULL, "Fred"), OP_EQ, -1);
+ tt_int_op(smartlist_string_pos(sl, "Fred"), OP_EQ, -1);
+ tt_int_op(smartlist_string_pos(sl, "This"), OP_EQ, 0);
+ tt_int_op(smartlist_string_pos(sl, "a"), OP_EQ, 2);
+ tt_int_op(smartlist_string_pos(sl, "function"), OP_EQ, 6);
/* Test pos */
- tt_int_op(smartlist_pos(NULL, "Fred"), ==, -1);
- tt_int_op(smartlist_pos(sl, "Fred"), ==, -1);
- tt_int_op(smartlist_pos(sl, "This"), ==, -1);
- tt_int_op(smartlist_pos(sl, "a"), ==, -1);
- tt_int_op(smartlist_pos(sl, "function"), ==, -1);
- tt_int_op(smartlist_pos(sl, smartlist_get(sl,0)), ==, 0);
- tt_int_op(smartlist_pos(sl, smartlist_get(sl,2)), ==, 2);
- tt_int_op(smartlist_pos(sl, smartlist_get(sl,5)), ==, 5);
- tt_int_op(smartlist_pos(sl, smartlist_get(sl,6)), ==, 6);
+ tt_int_op(smartlist_pos(NULL, "Fred"), OP_EQ, -1);
+ tt_int_op(smartlist_pos(sl, "Fred"), OP_EQ, -1);
+ tt_int_op(smartlist_pos(sl, "This"), OP_EQ, -1);
+ tt_int_op(smartlist_pos(sl, "a"), OP_EQ, -1);
+ tt_int_op(smartlist_pos(sl, "function"), OP_EQ, -1);
+ tt_int_op(smartlist_pos(sl, smartlist_get(sl,0)), OP_EQ, 0);
+ tt_int_op(smartlist_pos(sl, smartlist_get(sl,2)), OP_EQ, 2);
+ tt_int_op(smartlist_pos(sl, smartlist_get(sl,5)), OP_EQ, 5);
+ tt_int_op(smartlist_pos(sl, smartlist_get(sl,6)), OP_EQ, 6);
done:
SMARTLIST_FOREACH(sl, char *, str, tor_free(str));
@@ -681,7 +681,7 @@ test_container_pqueue(void *arg)
{
smartlist_t *sl = smartlist_new();
int (*cmp)(const void *, const void*);
- const int offset = STRUCT_OFFSET(pq_entry_t, idx);
+ const int offset = offsetof(pq_entry_t, idx);
#define ENTRY(s) pq_entry_t s = { #s, -1 }
ENTRY(cows);
ENTRY(zebras);
@@ -830,7 +830,7 @@ test_container_strmap(void *arg)
found_keys = smartlist_new();
while (!strmap_iter_done(iter)) {
strmap_iter_get(iter,&k,&v);
- smartlist_add(found_keys, tor_strdup(k));
+ smartlist_add_strdup(found_keys, k);
tt_ptr_op(v,OP_EQ, strmap_get(map, k));
if (!strcmp(k, "K2")) {
@@ -882,6 +882,46 @@ test_container_strmap(void *arg)
tor_free(v105);
}
+static void
+test_container_smartlist_remove(void *arg)
+{
+ (void) arg;
+ int array[5];
+ smartlist_t *sl = smartlist_new();
+ int i,j;
+
+ for (j=0; j < 2; ++j)
+ for (i=0; i < 5; ++i)
+ smartlist_add(sl, &array[i]);
+
+ smartlist_remove(sl, &array[0]);
+ smartlist_remove(sl, &array[3]);
+ smartlist_remove(sl, &array[4]);
+ tt_assert(! smartlist_contains(sl, &array[0]));
+ tt_assert(smartlist_contains(sl, &array[1]));
+ tt_assert(smartlist_contains(sl, &array[2]));
+ tt_assert(! smartlist_contains(sl, &array[3]));
+ tt_assert(! smartlist_contains(sl, &array[4]));
+ tt_int_op(smartlist_len(sl), OP_EQ, 4);
+
+ smartlist_clear(sl);
+ for (j=0; j < 2; ++j)
+ for (i=0; i < 5; ++i)
+ smartlist_add(sl, &array[i]);
+
+ smartlist_remove_keeporder(sl, &array[0]);
+ smartlist_remove_keeporder(sl, &array[3]);
+ smartlist_remove_keeporder(sl, &array[4]);
+ tt_int_op(smartlist_len(sl), OP_EQ, 4);
+ tt_ptr_op(smartlist_get(sl, 0), OP_EQ, &array[1]);
+ tt_ptr_op(smartlist_get(sl, 1), OP_EQ, &array[2]);
+ tt_ptr_op(smartlist_get(sl, 2), OP_EQ, &array[1]);
+ tt_ptr_op(smartlist_get(sl, 3), OP_EQ, &array[2]);
+
+ done:
+ smartlist_free(sl);
+}
+
/** Run unit tests for getting the median of a list. */
static void
test_container_order_functions(void *arg)
@@ -950,13 +990,13 @@ test_container_order_functions(void *arg)
tt_assert(15 == median_time(times, 5));
int32_t int32s[] = { -5, -10, -50, 100 };
- tt_int_op(-5, ==, median_int32(int32s, 1));
- tt_int_op(-10, ==, median_int32(int32s, 2));
- tt_int_op(-10, ==, median_int32(int32s, 3));
- tt_int_op(-10, ==, median_int32(int32s, 4));
+ tt_int_op(-5, OP_EQ, median_int32(int32s, 1));
+ tt_int_op(-10, OP_EQ, median_int32(int32s, 2));
+ tt_int_op(-10, OP_EQ, median_int32(int32s, 3));
+ tt_int_op(-10, OP_EQ, median_int32(int32s, 4));
long longs[] = { -30, 30, 100, -100, 7 };
- tt_int_op(7, ==, find_nth_long(longs, 5, 2));
+ tt_int_op(7, OP_EQ, find_nth_long(longs, 5, 2));
done:
;
@@ -1066,7 +1106,7 @@ test_container_fp_pair_map(void *arg)
tt_int_op(fp_pair_map_size(map),OP_EQ, 4);
fp_pair_map_assert_ok(map);
fp_pair_map_set(map, &fp5, v104);
- fp_pair_map_set(map, &fp6, v105);
+ fp_pair_map_set_by_digests(map, fp6.first, fp6.second, v105);
fp_pair_map_assert_ok(map);
/* Test iterator. */
@@ -1084,7 +1124,8 @@ test_container_fp_pair_map(void *arg)
/* Make sure we removed fp2, but not the others. */
tt_ptr_op(fp_pair_map_get(map, &fp2),OP_EQ, NULL);
- tt_ptr_op(fp_pair_map_get(map, &fp5),OP_EQ, v104);
+ tt_ptr_op(fp_pair_map_get_by_digests(map, fp5.first, fp5.second),
+ OP_EQ, v104);
fp_pair_map_assert_ok(map);
/* Clean up after ourselves. */
@@ -1113,31 +1154,31 @@ test_container_smartlist_most_frequent(void *arg)
const char *cp;
cp = smartlist_get_most_frequent_string_(sl, &count);
- tt_int_op(count, ==, 0);
- tt_ptr_op(cp, ==, NULL);
+ tt_int_op(count, OP_EQ, 0);
+ tt_ptr_op(cp, OP_EQ, NULL);
/* String must be sorted before we call get_most_frequent */
smartlist_split_string(sl, "abc:def:ghi", ":", 0, 0);
cp = smartlist_get_most_frequent_string_(sl, &count);
- tt_int_op(count, ==, 1);
- tt_str_op(cp, ==, "ghi"); /* Ties broken in favor of later element */
+ tt_int_op(count, OP_EQ, 1);
+ tt_str_op(cp, OP_EQ, "ghi"); /* Ties broken in favor of later element */
smartlist_split_string(sl, "def:ghi", ":", 0, 0);
smartlist_sort_strings(sl);
cp = smartlist_get_most_frequent_string_(sl, &count);
- tt_int_op(count, ==, 2);
- tt_ptr_op(cp, !=, NULL);
- tt_str_op(cp, ==, "ghi"); /* Ties broken in favor of later element */
+ tt_int_op(count, OP_EQ, 2);
+ tt_ptr_op(cp, OP_NE, NULL);
+ tt_str_op(cp, OP_EQ, "ghi"); /* Ties broken in favor of later element */
smartlist_split_string(sl, "def:abc:qwop", ":", 0, 0);
smartlist_sort_strings(sl);
cp = smartlist_get_most_frequent_string_(sl, &count);
- tt_int_op(count, ==, 3);
- tt_ptr_op(cp, !=, NULL);
- tt_str_op(cp, ==, "def"); /* No tie */
+ tt_int_op(count, OP_EQ, 3);
+ tt_ptr_op(cp, OP_NE, NULL);
+ tt_str_op(cp, OP_EQ, "def"); /* No tie */
done:
SMARTLIST_FOREACH(sl, char *, str, tor_free(str));
@@ -1166,7 +1207,7 @@ test_container_smartlist_sort_ptrs(void *arg)
smartlist_shuffle(sl);
smartlist_sort_pointers(sl);
for (j = 0; j < ARRAY_LENGTH(arrayptrs); ++j) {
- tt_ptr_op(smartlist_get(sl, j), ==, arrayptrs[j]);
+ tt_ptr_op(smartlist_get(sl, j), OP_EQ, arrayptrs[j]);
}
}
@@ -1192,11 +1233,11 @@ test_container_smartlist_strings_eq(void *arg)
} while (0)
/* Both NULL, so equal */
- tt_int_op(1, ==, smartlist_strings_eq(NULL, NULL));
+ tt_int_op(1, OP_EQ, smartlist_strings_eq(NULL, NULL));
/* One NULL, not equal. */
- tt_int_op(0, ==, smartlist_strings_eq(NULL, sl1));
- tt_int_op(0, ==, smartlist_strings_eq(sl1, NULL));
+ tt_int_op(0, OP_EQ, smartlist_strings_eq(NULL, sl1));
+ tt_int_op(0, OP_EQ, smartlist_strings_eq(sl1, NULL));
/* Both empty, both equal. */
EQ_SHOULD_SAY("", "", 1);
@@ -1239,6 +1280,7 @@ struct testcase_t container_tests[] = {
CONTAINER_LEGACY(smartlist_digests),
CONTAINER_LEGACY(smartlist_join),
CONTAINER_LEGACY(smartlist_pos),
+ CONTAINER(smartlist_remove, 0),
CONTAINER(smartlist_ints_eq, 0),
CONTAINER_LEGACY(bitarray),
CONTAINER_LEGACY(digestset),
diff --git a/src/test/test_controller.c b/src/test/test_controller.c
index f19c846144..472fcb8c53 100644
--- a/src/test/test_controller.c
+++ b/src/test/test_controller.c
@@ -1,14 +1,16 @@
-/* Copyright (c) 2015-2016, The Tor Project, Inc. */
+/* Copyright (c) 2015-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CONTROL_PRIVATE
#include "or.h"
+#include "bridges.h"
#include "control.h"
#include "entrynodes.h"
#include "networkstatus.h"
#include "rendservice.h"
#include "routerlist.h"
#include "test.h"
+#include "test_helpers.h"
static void
test_add_onion_helper_keyarg(void *arg)
@@ -29,7 +31,7 @@ test_add_onion_helper_keyarg(void *arg)
tt_assert(pk);
tt_str_op(key_new_alg, OP_EQ, "RSA1024");
tt_assert(key_new_blob);
- tt_assert(!err_msg);
+ tt_ptr_op(err_msg, OP_EQ, NULL);
/* Test "BEST" key generation (Assumes BEST = RSA1024). */
crypto_pk_free(pk);
@@ -39,7 +41,7 @@ test_add_onion_helper_keyarg(void *arg)
tt_assert(pk);
tt_str_op(key_new_alg, OP_EQ, "RSA1024");
tt_assert(key_new_blob);
- tt_assert(!err_msg);
+ tt_ptr_op(err_msg, OP_EQ, NULL);
/* Test discarding the private key. */
crypto_pk_free(pk);
@@ -47,17 +49,17 @@ test_add_onion_helper_keyarg(void *arg)
pk = add_onion_helper_keyarg("NEW:BEST", 1, &key_new_alg, &key_new_blob,
&err_msg);
tt_assert(pk);
- tt_assert(!key_new_alg);
- tt_assert(!key_new_blob);
- tt_assert(!err_msg);
+ tt_ptr_op(key_new_alg, OP_EQ, NULL);
+ tt_ptr_op(key_new_blob, OP_EQ, NULL);
+ tt_ptr_op(err_msg, OP_EQ, NULL);
/* Test generating a invalid key type. */
crypto_pk_free(pk);
pk = add_onion_helper_keyarg("NEW:RSA512", 0, &key_new_alg, &key_new_blob,
&err_msg);
- tt_assert(!pk);
- tt_assert(!key_new_alg);
- tt_assert(!key_new_blob);
+ tt_ptr_op(pk, OP_EQ, NULL);
+ tt_ptr_op(key_new_alg, OP_EQ, NULL);
+ tt_ptr_op(key_new_blob, OP_EQ, NULL);
tt_assert(err_msg);
/* Test loading a RSA1024 key. */
@@ -68,10 +70,10 @@ test_add_onion_helper_keyarg(void *arg)
pk2 = add_onion_helper_keyarg(arg_str, 0, &key_new_alg, &key_new_blob,
&err_msg);
tt_assert(pk2);
- tt_assert(!key_new_alg);
- tt_assert(!key_new_blob);
- tt_assert(!err_msg);
- tt_assert(crypto_pk_cmp_keys(pk, pk2) == 0);
+ tt_ptr_op(key_new_alg, OP_EQ, NULL);
+ tt_ptr_op(key_new_blob, OP_EQ, NULL);
+ tt_ptr_op(err_msg, OP_EQ, NULL);
+ tt_int_op(crypto_pk_cmp_keys(pk, pk2), OP_EQ, 0);
/* Test loading a invalid key type. */
tor_free(arg_str);
@@ -79,9 +81,9 @@ test_add_onion_helper_keyarg(void *arg)
tor_asprintf(&arg_str, "RSA512:%s", encoded);
pk = add_onion_helper_keyarg(arg_str, 0, &key_new_alg, &key_new_blob,
&err_msg);
- tt_assert(!pk);
- tt_assert(!key_new_alg);
- tt_assert(!key_new_blob);
+ tt_ptr_op(pk, OP_EQ, NULL);
+ tt_ptr_op(key_new_alg, OP_EQ, NULL);
+ tt_ptr_op(key_new_blob, OP_EQ, NULL);
tt_assert(err_msg);
/* Test loading a invalid key. */
@@ -92,9 +94,9 @@ test_add_onion_helper_keyarg(void *arg)
tor_asprintf(&arg_str, "RSA1024:%s", encoded);
pk = add_onion_helper_keyarg(arg_str, 0, &key_new_alg, &key_new_blob,
&err_msg);
- tt_assert(!pk);
- tt_assert(!key_new_alg);
- tt_assert(!key_new_blob);
+ tt_ptr_op(pk, OP_EQ, NULL);
+ tt_ptr_op(key_new_alg, OP_EQ, NULL);
+ tt_ptr_op(key_new_blob, OP_EQ, NULL);
tt_assert(err_msg);
done:
@@ -107,6 +109,45 @@ test_add_onion_helper_keyarg(void *arg)
}
static void
+test_getinfo_helper_onion(void *arg)
+{
+ (void)arg;
+ control_connection_t dummy;
+ /* Get results out */
+ char *answer = NULL;
+ const char *errmsg = NULL;
+ char *service_id = NULL;
+ int rt = 0;
+
+ dummy.ephemeral_onion_services = NULL;
+
+ /* successfully get an empty answer */
+ rt = getinfo_helper_onions(&dummy, "onions/current", &answer, &errmsg);
+ tt_int_op(rt, OP_EQ, 0);
+ tt_str_op(answer, OP_EQ, "");
+ tor_free(answer);
+
+ /* successfully get an empty answer */
+ rt = getinfo_helper_onions(&dummy, "onions/detached", &answer, &errmsg);
+ tt_int_op(rt, OP_EQ, 0);
+ tt_str_op(answer, OP_EQ, "");
+ tor_free(answer);
+
+ /* get an answer for one onion service */
+ service_id = tor_strdup("dummy_onion_id");
+ dummy.ephemeral_onion_services = smartlist_new();
+ smartlist_add(dummy.ephemeral_onion_services, service_id);
+ rt = getinfo_helper_onions(&dummy, "onions/current", &answer, &errmsg);
+ tt_int_op(rt, OP_EQ, 0);
+ tt_str_op(answer, OP_EQ, "dummy_onion_id");
+
+ done:
+ tor_free(answer);
+ tor_free(service_id);
+ smartlist_free(dummy.ephemeral_onion_services);
+}
+
+static void
test_rend_service_parse_port_config(void *arg)
{
const char *sep = ",";
@@ -118,25 +159,25 @@ test_rend_service_parse_port_config(void *arg)
/* Test "VIRTPORT" only. */
cfg = rend_service_parse_port_config("80", sep, &err_msg);
tt_assert(cfg);
- tt_assert(!err_msg);
+ tt_ptr_op(err_msg, OP_EQ, NULL);
/* Test "VIRTPORT,TARGET" (Target is port). */
rend_service_port_config_free(cfg);
cfg = rend_service_parse_port_config("80,8080", sep, &err_msg);
tt_assert(cfg);
- tt_assert(!err_msg);
+ tt_ptr_op(err_msg, OP_EQ, NULL);
/* Test "VIRTPORT,TARGET" (Target is IPv4:port). */
rend_service_port_config_free(cfg);
cfg = rend_service_parse_port_config("80,192.0.2.1:8080", sep, &err_msg);
tt_assert(cfg);
- tt_assert(!err_msg);
+ tt_ptr_op(err_msg, OP_EQ, NULL);
/* Test "VIRTPORT,TARGET" (Target is IPv6:port). */
rend_service_port_config_free(cfg);
cfg = rend_service_parse_port_config("80,[2001:db8::1]:8080", sep, &err_msg);
tt_assert(cfg);
- tt_assert(!err_msg);
+ tt_ptr_op(err_msg, OP_EQ, NULL);
rend_service_port_config_free(cfg);
cfg = NULL;
@@ -145,13 +186,13 @@ test_rend_service_parse_port_config(void *arg)
/* Test empty config. */
rend_service_port_config_free(cfg);
cfg = rend_service_parse_port_config("", sep, &err_msg);
- tt_assert(!cfg);
+ tt_ptr_op(cfg, OP_EQ, NULL);
tt_assert(err_msg);
/* Test invalid port. */
tor_free(err_msg);
cfg = rend_service_parse_port_config("90001", sep, &err_msg);
- tt_assert(!cfg);
+ tt_ptr_op(cfg, OP_EQ, NULL);
tt_assert(err_msg);
tor_free(err_msg);
@@ -163,7 +204,7 @@ test_rend_service_parse_port_config(void *arg)
cfg = rend_service_parse_port_config("100 unix:\"/tmp/foo bar\"",
" ", &err_msg);
tt_assert(cfg);
- tt_assert(!err_msg);
+ tt_ptr_op(err_msg, OP_EQ, NULL);
rend_service_port_config_free(cfg);
cfg = NULL;
@@ -172,22 +213,24 @@ test_rend_service_parse_port_config(void *arg)
cfg = rend_service_parse_port_config("100 unix:\"/tmp/foo bar\"",
" ", &err_msg);
tt_assert(cfg);
- tt_assert(!err_msg);
+ tt_ptr_op(err_msg, OP_EQ, NULL);
rend_service_port_config_free(cfg);
cfg = NULL;
/* quoted unix port, missing end quote */
cfg = rend_service_parse_port_config("100 unix:\"/tmp/foo bar",
" ", &err_msg);
- tt_assert(!cfg);
+ tt_ptr_op(cfg, OP_EQ, NULL);
tt_str_op(err_msg, OP_EQ, "Couldn't process address <unix:\"/tmp/foo bar> "
"from hidden service configuration");
tor_free(err_msg);
/* bogus IP address */
- cfg = rend_service_parse_port_config("100 1.2.3.4.5:9000",
+ MOCK(tor_addr_lookup, mock_tor_addr_lookup__fail_on_bad_addrs);
+ cfg = rend_service_parse_port_config("100 foo!!.example.com:9000",
" ", &err_msg);
- tt_assert(!cfg);
+ UNMOCK(tor_addr_lookup);
+ tt_ptr_op(cfg, OP_EQ, NULL);
tt_str_op(err_msg, OP_EQ, "Unparseable address in hidden service port "
"configuration.");
tor_free(err_msg);
@@ -195,7 +238,7 @@ test_rend_service_parse_port_config(void *arg)
/* bogus port port */
cfg = rend_service_parse_port_config("100 99999",
" ", &err_msg);
- tt_assert(!cfg);
+ tt_ptr_op(cfg, OP_EQ, NULL);
tt_str_op(err_msg, OP_EQ, "Unparseable or out-of-range port \"99999\" "
"in hidden service port configuration.");
tor_free(err_msg);
@@ -218,7 +261,7 @@ test_add_onion_helper_clientauth(void *arg)
client = add_onion_helper_clientauth("alice", &created, &err_msg);
tt_assert(client);
tt_assert(created);
- tt_assert(!err_msg);
+ tt_ptr_op(err_msg, OP_EQ, NULL);
rend_authorized_client_free(client);
/* Test "ClientName:Blob" */
@@ -226,26 +269,26 @@ test_add_onion_helper_clientauth(void *arg)
&created, &err_msg);
tt_assert(client);
tt_assert(!created);
- tt_assert(!err_msg);
+ tt_ptr_op(err_msg, OP_EQ, NULL);
rend_authorized_client_free(client);
/* Test invalid client names */
client = add_onion_helper_clientauth("no*asterisks*allowed", &created,
&err_msg);
- tt_assert(!client);
+ tt_ptr_op(client, OP_EQ, NULL);
tt_assert(err_msg);
tor_free(err_msg);
/* Test invalid auth cookie */
client = add_onion_helper_clientauth("alice:12345", &created, &err_msg);
- tt_assert(!client);
+ tt_ptr_op(client, OP_EQ, NULL);
tt_assert(err_msg);
tor_free(err_msg);
/* Test invalid syntax */
client = add_onion_helper_clientauth(":475hGBHPlq7Mc0cRZitK/B", &created,
&err_msg);
- tt_assert(!client);
+ tt_ptr_op(client, OP_EQ, NULL);
tt_assert(err_msg);
tor_free(err_msg);
@@ -501,7 +544,7 @@ cert_dl_status_def_for_auth_mock(const char *digest)
download_status_t *dl = NULL;
char digest_str[HEX_DIGEST_LEN+1];
- tt_assert(digest != NULL);
+ tt_ptr_op(digest, OP_NE, NULL);
base16_encode(digest_str, HEX_DIGEST_LEN + 1,
digest, DIGEST_LEN);
digest_str[HEX_DIGEST_LEN] = '\0';
@@ -525,7 +568,7 @@ cert_dl_status_sks_for_auth_id_mock(const char *digest)
char *tmp;
int len;
- tt_assert(digest != NULL);
+ tt_ptr_op(digest, OP_NE, NULL);
base16_encode(digest_str, HEX_DIGEST_LEN + 1,
digest, DIGEST_LEN);
digest_str[HEX_DIGEST_LEN] = '\0';
@@ -579,11 +622,11 @@ cert_dl_status_fp_sk_mock(const char *fp_digest, const char *sk_digest)
* dl status we want.
*/
- tt_assert(fp_digest != NULL);
+ tt_ptr_op(fp_digest, OP_NE, NULL);
base16_encode(fp_digest_str, HEX_DIGEST_LEN + 1,
fp_digest, DIGEST_LEN);
fp_digest_str[HEX_DIGEST_LEN] = '\0';
- tt_assert(sk_digest != NULL);
+ tt_ptr_op(sk_digest, OP_NE, NULL);
base16_encode(sk_digest_str, HEX_DIGEST_LEN + 1,
sk_digest, DIGEST_LEN);
sk_digest_str[HEX_DIGEST_LEN] = '\0';
@@ -663,7 +706,7 @@ descbr_get_dl_by_digest_mock(const char *digest)
char digest_str[HEX_DIGEST_LEN+1];
if (!disable_descbr) {
- tt_assert(digest != NULL);
+ tt_ptr_op(digest, OP_NE, NULL);
base16_encode(digest_str, HEX_DIGEST_LEN + 1,
digest, DIGEST_LEN);
digest_str[HEX_DIGEST_LEN] = '\0';
@@ -730,7 +773,7 @@ test_download_status_consensus(void *arg)
/* Check that the unknown prefix case works; no mocks needed yet */
getinfo_helper_downloads(&dummy, "downloads/foo", &answer, &errmsg);
- tt_assert(answer == NULL);
+ tt_ptr_op(answer, OP_EQ, NULL);
tt_str_op(errmsg, OP_EQ, "Unknown download status query");
setup_ns_mocks();
@@ -745,8 +788,8 @@ test_download_status_consensus(void *arg)
sizeof(download_status_t));
getinfo_helper_downloads(&dummy, "downloads/networkstatus/ns",
&answer, &errmsg);
- tt_assert(answer != NULL);
- tt_assert(errmsg == NULL);
+ tt_ptr_op(answer, OP_NE, NULL);
+ tt_ptr_op(errmsg, OP_EQ, NULL);
tt_str_op(answer, OP_EQ, dls_sample_1_str);
tor_free(answer);
errmsg = NULL;
@@ -756,8 +799,8 @@ test_download_status_consensus(void *arg)
sizeof(download_status_t));
getinfo_helper_downloads(&dummy, "downloads/networkstatus/microdesc",
&answer, &errmsg);
- tt_assert(answer != NULL);
- tt_assert(errmsg == NULL);
+ tt_ptr_op(answer, OP_NE, NULL);
+ tt_ptr_op(errmsg, OP_EQ, NULL);
tt_str_op(answer, OP_EQ, dls_sample_2_str);
tor_free(answer);
errmsg = NULL;
@@ -767,8 +810,8 @@ test_download_status_consensus(void *arg)
sizeof(download_status_t));
getinfo_helper_downloads(&dummy, "downloads/networkstatus/ns/bootstrap",
&answer, &errmsg);
- tt_assert(answer != NULL);
- tt_assert(errmsg == NULL);
+ tt_ptr_op(answer, OP_NE, NULL);
+ tt_ptr_op(errmsg, OP_EQ, NULL);
tt_str_op(answer, OP_EQ, dls_sample_3_str);
tor_free(answer);
errmsg = NULL;
@@ -779,8 +822,8 @@ test_download_status_consensus(void *arg)
getinfo_helper_downloads(&dummy,
"downloads/networkstatus/microdesc/bootstrap",
&answer, &errmsg);
- tt_assert(answer != NULL);
- tt_assert(errmsg == NULL);
+ tt_ptr_op(answer, OP_NE, NULL);
+ tt_ptr_op(errmsg, OP_EQ, NULL);
tt_str_op(answer, OP_EQ, dls_sample_4_str);
tor_free(answer);
errmsg = NULL;
@@ -791,8 +834,8 @@ test_download_status_consensus(void *arg)
getinfo_helper_downloads(&dummy,
"downloads/networkstatus/ns/running",
&answer, &errmsg);
- tt_assert(answer != NULL);
- tt_assert(errmsg == NULL);
+ tt_ptr_op(answer, OP_NE, NULL);
+ tt_ptr_op(errmsg, OP_EQ, NULL);
tt_str_op(answer, OP_EQ, dls_sample_5_str);
tor_free(answer);
errmsg = NULL;
@@ -803,8 +846,8 @@ test_download_status_consensus(void *arg)
getinfo_helper_downloads(&dummy,
"downloads/networkstatus/microdesc/running",
&answer, &errmsg);
- tt_assert(answer != NULL);
- tt_assert(errmsg == NULL);
+ tt_ptr_op(answer, OP_NE, NULL);
+ tt_ptr_op(errmsg, OP_EQ, NULL);
tt_str_op(answer, OP_EQ, dls_sample_6_str);
tor_free(answer);
errmsg = NULL;
@@ -812,8 +855,8 @@ test_download_status_consensus(void *arg)
/* Now check the error case */
getinfo_helper_downloads(&dummy, "downloads/networkstatus/foo",
&answer, &errmsg);
- tt_assert(answer == NULL);
- tt_assert(errmsg != NULL);
+ tt_ptr_op(answer, OP_EQ, NULL);
+ tt_ptr_op(errmsg, OP_NE, NULL);
tt_str_op(errmsg, OP_EQ, "Unknown flavor");
errmsg = NULL;
@@ -847,8 +890,8 @@ test_download_status_cert(void *arg)
getinfo_helper_downloads(&dummy,
"downloads/cert/fps",
&answer, &errmsg);
- tt_assert(answer != NULL);
- tt_assert(errmsg == NULL);
+ tt_ptr_op(answer, OP_NE, NULL);
+ tt_ptr_op(errmsg, OP_EQ, NULL);
tt_str_op(answer, OP_EQ, auth_id_digest_expected_list);
tor_free(answer);
errmsg = NULL;
@@ -857,10 +900,10 @@ test_download_status_cert(void *arg)
memcpy(&auth_def_cert_download_status_1, &dls_sample_1,
sizeof(download_status_t));
tor_asprintf(&question, "downloads/cert/fp/%s", auth_id_digest_1_str);
- tt_assert(question != NULL);
+ tt_ptr_op(question, OP_NE, NULL);
getinfo_helper_downloads(&dummy, question, &answer, &errmsg);
- tt_assert(answer != NULL);
- tt_assert(errmsg == NULL);
+ tt_ptr_op(answer, OP_NE, NULL);
+ tt_ptr_op(errmsg, OP_EQ, NULL);
tt_str_op(answer, OP_EQ, dls_sample_1_str);
tor_free(question);
tor_free(answer);
@@ -870,10 +913,10 @@ test_download_status_cert(void *arg)
memcpy(&auth_def_cert_download_status_2, &dls_sample_2,
sizeof(download_status_t));
tor_asprintf(&question, "downloads/cert/fp/%s", auth_id_digest_2_str);
- tt_assert(question != NULL);
+ tt_ptr_op(question, OP_NE, NULL);
getinfo_helper_downloads(&dummy, question, &answer, &errmsg);
- tt_assert(answer != NULL);
- tt_assert(errmsg == NULL);
+ tt_ptr_op(answer, OP_NE, NULL);
+ tt_ptr_op(errmsg, OP_EQ, NULL);
tt_str_op(answer, OP_EQ, dls_sample_2_str);
tor_free(question);
tor_free(answer);
@@ -881,10 +924,10 @@ test_download_status_cert(void *arg)
/* Case 4 - list of signing key digests for 1st auth id */
tor_asprintf(&question, "downloads/cert/fp/%s/sks", auth_id_digest_1_str);
- tt_assert(question != NULL);
+ tt_ptr_op(question, OP_NE, NULL);
getinfo_helper_downloads(&dummy, question, &answer, &errmsg);
- tt_assert(answer != NULL);
- tt_assert(errmsg == NULL);
+ tt_ptr_op(answer, OP_NE, NULL);
+ tt_ptr_op(errmsg, OP_EQ, NULL);
tt_str_op(answer, OP_EQ, auth_1_sk_digest_expected_list);
tor_free(question);
tor_free(answer);
@@ -892,10 +935,10 @@ test_download_status_cert(void *arg)
/* Case 5 - list of signing key digests for 2nd auth id */
tor_asprintf(&question, "downloads/cert/fp/%s/sks", auth_id_digest_2_str);
- tt_assert(question != NULL);
+ tt_ptr_op(question, OP_NE, NULL);
getinfo_helper_downloads(&dummy, question, &answer, &errmsg);
- tt_assert(answer != NULL);
- tt_assert(errmsg == NULL);
+ tt_ptr_op(answer, OP_NE, NULL);
+ tt_ptr_op(errmsg, OP_EQ, NULL);
tt_str_op(answer, OP_EQ, auth_2_sk_digest_expected_list);
tor_free(question);
tor_free(answer);
@@ -906,10 +949,10 @@ test_download_status_cert(void *arg)
sizeof(download_status_t));
tor_asprintf(&question, "downloads/cert/fp/%s/%s",
auth_id_digest_1_str, auth_1_sk_1_str);
- tt_assert(question != NULL);
+ tt_ptr_op(question, OP_NE, NULL);
getinfo_helper_downloads(&dummy, question, &answer, &errmsg);
- tt_assert(answer != NULL);
- tt_assert(errmsg == NULL);
+ tt_ptr_op(answer, OP_NE, NULL);
+ tt_ptr_op(errmsg, OP_EQ, NULL);
tt_str_op(answer, OP_EQ, dls_sample_3_str);
tor_free(question);
tor_free(answer);
@@ -920,10 +963,10 @@ test_download_status_cert(void *arg)
sizeof(download_status_t));
tor_asprintf(&question, "downloads/cert/fp/%s/%s",
auth_id_digest_1_str, auth_1_sk_2_str);
- tt_assert(question != NULL);
+ tt_ptr_op(question, OP_NE, NULL);
getinfo_helper_downloads(&dummy, question, &answer, &errmsg);
- tt_assert(answer != NULL);
- tt_assert(errmsg == NULL);
+ tt_ptr_op(answer, OP_NE, NULL);
+ tt_ptr_op(errmsg, OP_EQ, NULL);
tt_str_op(answer, OP_EQ, dls_sample_4_str);
tor_free(question);
tor_free(answer);
@@ -934,10 +977,10 @@ test_download_status_cert(void *arg)
sizeof(download_status_t));
tor_asprintf(&question, "downloads/cert/fp/%s/%s",
auth_id_digest_2_str, auth_2_sk_1_str);
- tt_assert(question != NULL);
+ tt_ptr_op(question, OP_NE, NULL);
getinfo_helper_downloads(&dummy, question, &answer, &errmsg);
- tt_assert(answer != NULL);
- tt_assert(errmsg == NULL);
+ tt_ptr_op(answer, OP_NE, NULL);
+ tt_ptr_op(errmsg, OP_EQ, NULL);
tt_str_op(answer, OP_EQ, dls_sample_5_str);
tor_free(question);
tor_free(answer);
@@ -948,10 +991,10 @@ test_download_status_cert(void *arg)
sizeof(download_status_t));
tor_asprintf(&question, "downloads/cert/fp/%s/%s",
auth_id_digest_2_str, auth_2_sk_2_str);
- tt_assert(question != NULL);
+ tt_ptr_op(question, OP_NE, NULL);
getinfo_helper_downloads(&dummy, question, &answer, &errmsg);
- tt_assert(answer != NULL);
- tt_assert(errmsg == NULL);
+ tt_ptr_op(answer, OP_NE, NULL);
+ tt_ptr_op(errmsg, OP_EQ, NULL);
tt_str_op(answer, OP_EQ, dls_sample_6_str);
tor_free(question);
tor_free(answer);
@@ -962,8 +1005,8 @@ test_download_status_cert(void *arg)
/* Case 1 - query is garbage after downloads/cert/ part */
getinfo_helper_downloads(&dummy, "downloads/cert/blahdeblah",
&answer, &errmsg);
- tt_assert(answer == NULL);
- tt_assert(errmsg != NULL);
+ tt_ptr_op(answer, OP_EQ, NULL);
+ tt_ptr_op(errmsg, OP_NE, NULL);
tt_str_op(errmsg, OP_EQ, "Unknown certificate download status query");
errmsg = NULL;
@@ -973,8 +1016,8 @@ test_download_status_cert(void *arg)
*/
getinfo_helper_downloads(&dummy, "downloads/cert/fp/2B1D36D32B2942406",
&answer, &errmsg);
- tt_assert(answer == NULL);
- tt_assert(errmsg != NULL);
+ tt_ptr_op(answer, OP_EQ, NULL);
+ tt_ptr_op(errmsg, OP_NE, NULL);
tt_str_op(errmsg, OP_EQ, "That didn't look like a digest");
errmsg = NULL;
@@ -985,8 +1028,8 @@ test_download_status_cert(void *arg)
getinfo_helper_downloads(&dummy,
"downloads/cert/fp/82F52AF55D250115FE44D3GC81D49643241D56A1",
&answer, &errmsg);
- tt_assert(answer == NULL);
- tt_assert(errmsg != NULL);
+ tt_ptr_op(answer, OP_EQ, NULL);
+ tt_ptr_op(errmsg, OP_NE, NULL);
tt_str_op(errmsg, OP_EQ, "That didn't look like a digest");
errmsg = NULL;
@@ -997,8 +1040,8 @@ test_download_status_cert(void *arg)
getinfo_helper_downloads(&dummy,
"downloads/cert/fp/AC4F23B5745BDD2A77997B85B1FD85D05C2E0F61",
&answer, &errmsg);
- tt_assert(answer == NULL);
- tt_assert(errmsg != NULL);
+ tt_ptr_op(answer, OP_EQ, NULL);
+ tt_ptr_op(errmsg, OP_NE, NULL);
tt_str_op(errmsg, OP_EQ,
"Failed to get download status for this authority identity digest");
errmsg = NULL;
@@ -1010,8 +1053,8 @@ test_download_status_cert(void *arg)
getinfo_helper_downloads(&dummy,
"downloads/cert/fp/82F52AF55D250115FE44D3GC81D49643241D56A1/blah",
&answer, &errmsg);
- tt_assert(answer == NULL);
- tt_assert(errmsg != NULL);
+ tt_ptr_op(answer, OP_EQ, NULL);
+ tt_ptr_op(errmsg, OP_NE, NULL);
tt_str_op(errmsg, OP_EQ, "That didn't look like an identity digest");
errmsg = NULL;
@@ -1022,8 +1065,8 @@ test_download_status_cert(void *arg)
getinfo_helper_downloads(&dummy,
"downloads/cert/fp/82F52AF55D25/blah",
&answer, &errmsg);
- tt_assert(answer == NULL);
- tt_assert(errmsg != NULL);
+ tt_ptr_op(answer, OP_EQ, NULL);
+ tt_ptr_op(errmsg, OP_NE, NULL);
tt_str_op(errmsg, OP_EQ, "That didn't look like an identity digest");
errmsg = NULL;
@@ -1034,8 +1077,8 @@ test_download_status_cert(void *arg)
getinfo_helper_downloads(&dummy,
"downloads/cert/fp/AC4F23B5745BDD2A77997B85B1FD85D05C2E0F61/sks",
&answer, &errmsg);
- tt_assert(answer == NULL);
- tt_assert(errmsg != NULL);
+ tt_ptr_op(answer, OP_EQ, NULL);
+ tt_ptr_op(errmsg, OP_NE, NULL);
tt_str_op(errmsg, OP_EQ,
"Failed to get list of signing key digests for this authority "
"identity digest");
@@ -1049,8 +1092,8 @@ test_download_status_cert(void *arg)
"downloads/cert/fp/AC4F23B5745BDD2A77997B85B1FD85D05C2E0F61/"
"82F52AF55D250115FE44D3GC81D49643241D56A1",
&answer, &errmsg);
- tt_assert(answer == NULL);
- tt_assert(errmsg != NULL);
+ tt_ptr_op(answer, OP_EQ, NULL);
+ tt_ptr_op(errmsg, OP_NE, NULL);
tt_str_op(errmsg, OP_EQ, "That didn't look like a signing key digest");
errmsg = NULL;
@@ -1062,8 +1105,8 @@ test_download_status_cert(void *arg)
"downloads/cert/fp/AC4F23B5745BDD2A77997B85B1FD85D05C2E0F61/"
"82F52AF55D250115FE44D",
&answer, &errmsg);
- tt_assert(answer == NULL);
- tt_assert(errmsg != NULL);
+ tt_ptr_op(answer, OP_EQ, NULL);
+ tt_ptr_op(errmsg, OP_NE, NULL);
tt_str_op(errmsg, OP_EQ, "That didn't look like a signing key digest");
errmsg = NULL;
@@ -1075,8 +1118,8 @@ test_download_status_cert(void *arg)
"downloads/cert/fp/C6B05DF332F74DB9A13498EE3BBC7AA2F69FCB45/"
"3A214FC21AE25B012C2ECCB5F4EC8A3602D0545D",
&answer, &errmsg);
- tt_assert(answer == NULL);
- tt_assert(errmsg != NULL);
+ tt_ptr_op(answer, OP_EQ, NULL);
+ tt_ptr_op(errmsg, OP_NE, NULL);
tt_str_op(errmsg, OP_EQ,
"Failed to get download status for this identity/"
"signing key digest pair");
@@ -1090,8 +1133,8 @@ test_download_status_cert(void *arg)
"downloads/cert/fp/63CDD326DFEF0CA020BDD3FEB45A3286FE13A061/"
"3A214FC21AE25B012C2ECCB5F4EC8A3602D0545D",
&answer, &errmsg);
- tt_assert(answer == NULL);
- tt_assert(errmsg != NULL);
+ tt_ptr_op(answer, OP_EQ, NULL);
+ tt_ptr_op(errmsg, OP_NE, NULL);
tt_str_op(errmsg, OP_EQ,
"Failed to get download status for this identity/"
"signing key digest pair");
@@ -1105,8 +1148,8 @@ test_download_status_cert(void *arg)
"downloads/cert/fp/63CDD326DFEF0CA020BDD3FEB45A3286FE13A061/"
"9451B8F1B10952384EB58B5F230C0BB701626C9B",
&answer, &errmsg);
- tt_assert(answer == NULL);
- tt_assert(errmsg != NULL);
+ tt_ptr_op(answer, OP_EQ, NULL);
+ tt_ptr_op(errmsg, OP_NE, NULL);
tt_str_op(errmsg, OP_EQ,
"Failed to get download status for this identity/"
"signing key digest pair");
@@ -1142,8 +1185,8 @@ test_download_status_desc(void *arg)
getinfo_helper_downloads(&dummy,
"downloads/desc/descs",
&answer, &errmsg);
- tt_assert(answer != NULL);
- tt_assert(errmsg == NULL);
+ tt_ptr_op(answer, OP_NE, NULL);
+ tt_ptr_op(errmsg, OP_EQ, NULL);
tt_str_op(answer, OP_EQ, descbr_expected_list);
tor_free(answer);
errmsg = NULL;
@@ -1152,10 +1195,10 @@ test_download_status_desc(void *arg)
memcpy(&descbr_digest_1_dl, &dls_sample_1,
sizeof(download_status_t));
tor_asprintf(&question, "downloads/desc/%s", descbr_digest_1_str);
- tt_assert(question != NULL);
+ tt_ptr_op(question, OP_NE, NULL);
getinfo_helper_downloads(&dummy, question, &answer, &errmsg);
- tt_assert(answer != NULL);
- tt_assert(errmsg == NULL);
+ tt_ptr_op(answer, OP_NE, NULL);
+ tt_ptr_op(errmsg, OP_EQ, NULL);
tt_str_op(answer, OP_EQ, dls_sample_1_str);
tor_free(question);
tor_free(answer);
@@ -1165,10 +1208,10 @@ test_download_status_desc(void *arg)
memcpy(&descbr_digest_2_dl, &dls_sample_2,
sizeof(download_status_t));
tor_asprintf(&question, "downloads/desc/%s", descbr_digest_2_str);
- tt_assert(question != NULL);
+ tt_ptr_op(question, OP_NE, NULL);
getinfo_helper_downloads(&dummy, question, &answer, &errmsg);
- tt_assert(answer != NULL);
- tt_assert(errmsg == NULL);
+ tt_ptr_op(answer, OP_NE, NULL);
+ tt_ptr_op(errmsg, OP_EQ, NULL);
tt_str_op(answer, OP_EQ, dls_sample_2_str);
tor_free(question);
tor_free(answer);
@@ -1179,8 +1222,8 @@ test_download_status_desc(void *arg)
/* Case 1 - non-digest-length garbage after downloads/desc */
getinfo_helper_downloads(&dummy, "downloads/desc/blahdeblah",
&answer, &errmsg);
- tt_assert(answer == NULL);
- tt_assert(errmsg != NULL);
+ tt_ptr_op(answer, OP_EQ, NULL);
+ tt_ptr_op(errmsg, OP_NE, NULL);
tt_str_op(errmsg, OP_EQ, "Unknown router descriptor download status query");
errmsg = NULL;
@@ -1189,8 +1232,8 @@ test_download_status_desc(void *arg)
&dummy,
"downloads/desc/774EC52FD9A5B80A6FACZE536616E8022E3470AG",
&answer, &errmsg);
- tt_assert(answer == NULL);
- tt_assert(errmsg != NULL);
+ tt_ptr_op(answer, OP_EQ, NULL);
+ tt_ptr_op(errmsg, OP_NE, NULL);
tt_str_op(errmsg, OP_EQ, "That didn't look like a digest");
errmsg = NULL;
@@ -1199,8 +1242,8 @@ test_download_status_desc(void *arg)
&dummy,
"downloads/desc/B05B46135B0B2C04EBE1DD6A6AE4B12D7CD2226A",
&answer, &errmsg);
- tt_assert(answer == NULL);
- tt_assert(errmsg != NULL);
+ tt_ptr_op(answer, OP_EQ, NULL);
+ tt_ptr_op(errmsg, OP_NE, NULL);
tt_str_op(errmsg, OP_EQ, "No such descriptor digest found");
errmsg = NULL;
@@ -1209,8 +1252,8 @@ test_download_status_desc(void *arg)
getinfo_helper_downloads(&dummy,
"downloads/desc/descs",
&answer, &errmsg);
- tt_assert(answer == NULL);
- tt_assert(errmsg != NULL);
+ tt_ptr_op(answer, OP_EQ, NULL);
+ tt_ptr_op(errmsg, OP_NE, NULL);
tt_str_op(errmsg, OP_EQ,
"We don't seem to have a networkstatus-flavored consensus");
errmsg = NULL;
@@ -1246,8 +1289,8 @@ test_download_status_bridge(void *arg)
getinfo_helper_downloads(&dummy,
"downloads/bridge/bridges",
&answer, &errmsg);
- tt_assert(answer != NULL);
- tt_assert(errmsg == NULL);
+ tt_ptr_op(answer, OP_NE, NULL);
+ tt_ptr_op(errmsg, OP_EQ, NULL);
tt_str_op(answer, OP_EQ, descbr_expected_list);
tor_free(answer);
errmsg = NULL;
@@ -1256,10 +1299,10 @@ test_download_status_bridge(void *arg)
memcpy(&descbr_digest_1_dl, &dls_sample_3,
sizeof(download_status_t));
tor_asprintf(&question, "downloads/bridge/%s", descbr_digest_1_str);
- tt_assert(question != NULL);
+ tt_ptr_op(question, OP_NE, NULL);
getinfo_helper_downloads(&dummy, question, &answer, &errmsg);
- tt_assert(answer != NULL);
- tt_assert(errmsg == NULL);
+ tt_ptr_op(answer, OP_NE, NULL);
+ tt_ptr_op(errmsg, OP_EQ, NULL);
tt_str_op(answer, OP_EQ, dls_sample_3_str);
tor_free(question);
tor_free(answer);
@@ -1269,10 +1312,10 @@ test_download_status_bridge(void *arg)
memcpy(&descbr_digest_2_dl, &dls_sample_4,
sizeof(download_status_t));
tor_asprintf(&question, "downloads/bridge/%s", descbr_digest_2_str);
- tt_assert(question != NULL);
+ tt_ptr_op(question, OP_NE, NULL);
getinfo_helper_downloads(&dummy, question, &answer, &errmsg);
- tt_assert(answer != NULL);
- tt_assert(errmsg == NULL);
+ tt_ptr_op(answer, OP_NE, NULL);
+ tt_ptr_op(errmsg, OP_EQ, NULL);
tt_str_op(answer, OP_EQ, dls_sample_4_str);
tor_free(question);
tor_free(answer);
@@ -1283,8 +1326,8 @@ test_download_status_bridge(void *arg)
/* Case 1 - non-digest-length garbage after downloads/bridge */
getinfo_helper_downloads(&dummy, "downloads/bridge/blahdeblah",
&answer, &errmsg);
- tt_assert(answer == NULL);
- tt_assert(errmsg != NULL);
+ tt_ptr_op(answer, OP_EQ, NULL);
+ tt_ptr_op(errmsg, OP_NE, NULL);
tt_str_op(errmsg, OP_EQ, "Unknown bridge descriptor download status query");
errmsg = NULL;
@@ -1293,8 +1336,8 @@ test_download_status_bridge(void *arg)
&dummy,
"downloads/bridge/774EC52FD9A5B80A6FACZE536616E8022E3470AG",
&answer, &errmsg);
- tt_assert(answer == NULL);
- tt_assert(errmsg != NULL);
+ tt_ptr_op(answer, OP_EQ, NULL);
+ tt_ptr_op(errmsg, OP_NE, NULL);
tt_str_op(errmsg, OP_EQ, "That didn't look like a digest");
errmsg = NULL;
@@ -1303,8 +1346,8 @@ test_download_status_bridge(void *arg)
&dummy,
"downloads/bridge/B05B46135B0B2C04EBE1DD6A6AE4B12D7CD2226A",
&answer, &errmsg);
- tt_assert(answer == NULL);
- tt_assert(errmsg != NULL);
+ tt_ptr_op(answer, OP_EQ, NULL);
+ tt_ptr_op(errmsg, OP_NE, NULL);
tt_str_op(errmsg, OP_EQ, "No such bridge identity digest found");
errmsg = NULL;
@@ -1313,8 +1356,8 @@ test_download_status_bridge(void *arg)
getinfo_helper_downloads(&dummy,
"downloads/bridge/bridges",
&answer, &errmsg);
- tt_assert(answer == NULL);
- tt_assert(errmsg != NULL);
+ tt_ptr_op(answer, OP_EQ, NULL);
+ tt_ptr_op(errmsg, OP_NE, NULL);
tt_str_op(errmsg, OP_EQ, "We don't seem to be using bridges");
errmsg = NULL;
disable_descbr = 0;
@@ -1328,6 +1371,7 @@ test_download_status_bridge(void *arg)
struct testcase_t controller_tests[] = {
{ "add_onion_helper_keyarg", test_add_onion_helper_keyarg, 0, NULL, NULL },
+ { "getinfo_helper_onion", test_getinfo_helper_onion, 0, NULL, NULL },
{ "rend_service_parse_port_config", test_rend_service_parse_port_config, 0,
NULL, NULL },
{ "add_onion_helper_clientauth", test_add_onion_helper_clientauth, 0, NULL,
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 8fd9ca7671..83d97f2867 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)
@@ -1135,6 +1100,54 @@ test_crypto_sha3_xof(void *arg)
tor_free(mem_op_hex_tmp);
}
+/* Test our MAC-SHA3 function. There are not actually any MAC-SHA3 test
+ * vectors out there for our H(len(k) || k || m) construction. Hence what we
+ * are gonna do is test our crypto_mac_sha3_256() function against manually
+ * doing H(len(k) || k||m). If in the future the Keccak group decides to
+ * standarize an MAC construction and make test vectors, we should
+ * incorporate them here. */
+static void
+test_crypto_mac_sha3(void *arg)
+{
+ const char msg[] = "i am in a library somewhere using my computer";
+ const char key[] = "i'm from the past talking to the future.";
+
+ uint8_t hmac_test[DIGEST256_LEN];
+ char hmac_manual[DIGEST256_LEN];
+
+ (void) arg;
+
+ /* First let's use our nice HMAC-SHA3 function */
+ crypto_mac_sha3_256(hmac_test, sizeof(hmac_test),
+ (uint8_t *) key, strlen(key),
+ (uint8_t *) msg, strlen(msg));
+
+ /* Now let's try a manual H(len(k) || k || m) construction */
+ {
+ char *key_msg_concat = NULL, *all = NULL;
+ int result;
+ const uint64_t key_len_netorder = tor_htonll(strlen(key));
+ size_t all_len;
+
+ tor_asprintf(&key_msg_concat, "%s%s", key, msg);
+ all_len = sizeof(key_len_netorder) + strlen(key_msg_concat);
+ all = tor_malloc_zero(all_len);
+ memcpy(all, &key_len_netorder, sizeof(key_len_netorder));
+ memcpy(all + sizeof(key_len_netorder), key_msg_concat,
+ strlen(key_msg_concat));
+
+ result = crypto_digest256(hmac_manual, all, all_len, DIGEST_SHA3_256);
+ tor_free(key_msg_concat);
+ tor_free(all);
+ tt_int_op(result, OP_EQ, 0);
+ }
+
+ /* Now compare the two results */
+ tt_mem_op(hmac_test, OP_EQ, hmac_manual, DIGEST256_LEN);
+
+ done: ;
+}
+
/** Run unit tests for our public key crypto functions */
static void
test_crypto_pk(void *arg)
@@ -1195,12 +1208,12 @@ test_crypto_pk(void *arg)
tt_assert(! crypto_pk_write_private_key_to_filename(pk1,
get_fname("pkey1")));
/* failing case for read: can't read. */
- tt_assert(crypto_pk_read_private_key_from_filename(pk2,
- get_fname("xyzzy")) < 0);
+ tt_int_op(crypto_pk_read_private_key_from_filename(pk2, get_fname("xyzzy")),
+ OP_LT, 0);
write_str_to_file(get_fname("xyzzy"), "foobar", 6);
/* Failing case for read: no key. */
- tt_assert(crypto_pk_read_private_key_from_filename(pk2,
- get_fname("xyzzy")) < 0);
+ tt_int_op(crypto_pk_read_private_key_from_filename(pk2, get_fname("xyzzy")),
+ OP_LT, 0);
tt_assert(! crypto_pk_read_private_key_from_filename(pk2,
get_fname("pkey1")));
tt_int_op(15,OP_EQ,
@@ -1232,17 +1245,17 @@ test_crypto_pk(void *arg)
i = crypto_pk_asn1_encode(pk1, data1, 1024);
tt_int_op(i, OP_GT, 0);
pk2 = crypto_pk_asn1_decode(data1, i);
- tt_assert(crypto_pk_cmp_keys(pk1,pk2) == 0);
+ tt_int_op(crypto_pk_cmp_keys(pk1, pk2), OP_EQ, 0);
/* Try with hybrid encryption wrappers. */
crypto_rand(data1, 1024);
for (i = 85; i < 140; ++i) {
memset(data2,0,1024);
memset(data3,0,1024);
- len = crypto_pk_public_hybrid_encrypt(pk1,data2,sizeof(data2),
+ len = crypto_pk_obsolete_public_hybrid_encrypt(pk1,data2,sizeof(data2),
data1,i,PK_PKCS1_OAEP_PADDING,0);
tt_int_op(len, OP_GE, 0);
- len = crypto_pk_private_hybrid_decrypt(pk1,data3,sizeof(data3),
+ len = crypto_pk_obsolete_private_hybrid_decrypt(pk1,data3,sizeof(data3),
data2,len,PK_PKCS1_OAEP_PADDING,1);
tt_int_op(len,OP_EQ, i);
tt_mem_op(data1,OP_EQ, data3,i);
@@ -1251,9 +1264,9 @@ test_crypto_pk(void *arg)
/* Try copy_full */
crypto_pk_free(pk2);
pk2 = crypto_pk_copy_full(pk1);
- tt_assert(pk2 != NULL);
+ tt_ptr_op(pk2, OP_NE, NULL);
tt_ptr_op(pk1, OP_NE, pk2);
- tt_assert(crypto_pk_cmp_keys(pk1,pk2) == 0);
+ tt_int_op(crypto_pk_cmp_keys(pk1, pk2), OP_EQ, 0);
done:
if (pk1)
@@ -1331,17 +1344,17 @@ test_crypto_pk_base64(void *arg)
/* Test decoding a valid key. */
pk2 = crypto_pk_base64_decode(encoded, strlen(encoded));
tt_assert(pk2);
- tt_assert(crypto_pk_cmp_keys(pk1,pk2) == 0);
+ tt_int_op(crypto_pk_cmp_keys(pk1, pk2), OP_EQ, 0);
crypto_pk_free(pk2);
/* Test decoding a invalid key (not Base64). */
static const char *invalid_b64 = "The key is in another castle!";
pk2 = crypto_pk_base64_decode(invalid_b64, strlen(invalid_b64));
- tt_assert(!pk2);
+ tt_ptr_op(pk2, OP_EQ, NULL);
/* Test decoding a truncated Base64 blob. */
pk2 = crypto_pk_base64_decode(encoded, strlen(encoded)/2);
- tt_assert(!pk2);
+ tt_ptr_op(pk2, OP_EQ, NULL);
done:
crypto_pk_free(pk1);
@@ -1410,7 +1423,7 @@ do_truncate(const char *fname, size_t len)
tor_free(bytes);
return r;
}
-#endif
+#endif /* defined(HAVE_TRUNCATE) */
/** Sanity check for crypto pk digests */
static void
@@ -1433,6 +1446,7 @@ test_crypto_digests(void *arg)
AUTHORITY_SIGNKEY_A_DIGEST, HEX_DIGEST_LEN);
r = crypto_pk_get_common_digests(k, &pkey_digests);
+ tt_int_op(r, OP_EQ, 0);
tt_mem_op(hex_str(pkey_digests.d[DIGEST_SHA1], DIGEST_LEN),OP_EQ,
AUTHORITY_SIGNKEY_A_DIGEST, HEX_DIGEST_LEN);
@@ -1469,28 +1483,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
@@ -1519,7 +1511,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);
}
@@ -1544,21 +1536,7 @@ test_crypto_formats(void *arg)
tt_mem_op(data1,OP_EQ, data3, DIGEST_LEN);
tt_int_op(99,OP_EQ, data3[DIGEST_LEN+1]);
- 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));
- }
+ tt_int_op(digest_from_base64(data3, "###"), OP_LT, 0);
/* Encoding SHA256 */
crypto_rand(data2, DIGEST256_LEN);
@@ -1969,7 +1947,7 @@ test_crypto_curve25519_impl(void *arg)
"e0544770bc7de853b38f9100489e3e79";
const char e1e2k_expected[] = "cd6e8269104eb5aaee886bd2071fba88"
"bd13861475516bc2cd2b6e005e805064";
-#else
+#else /* !(defined(SLOW_CURVE25519_TEST)) */
const int loop_max=200;
const char e1_expected[] = "bc7112cde03f97ef7008cad1bdc56be3"
"c6a1037d74cceb3712e9206871dcf654";
@@ -1977,7 +1955,7 @@ test_crypto_curve25519_impl(void *arg)
"8e3ee1a63c7d14274ea5d4c67f065467";
const char e1e2k_expected[] = "7ddb98bd89025d2347776b33901b3e7e"
"c0ee98cb2257a4545c0cfb2ca3e1812b";
-#endif
+#endif /* defined(SLOW_CURVE25519_TEST) */
unsigned char e1k[32];
unsigned char e2k[32];
@@ -2233,6 +2211,9 @@ test_crypto_ed25519_simple(void *arg)
tt_int_op(0, OP_EQ, ed25519_public_key_generate(&pub1, &sec1));
tt_int_op(0, OP_EQ, ed25519_public_key_generate(&pub2, &sec1));
+ tt_int_op(ed25519_validate_pubkey(&pub1), OP_EQ, 0);
+ tt_int_op(ed25519_validate_pubkey(&pub2), OP_EQ, 0);
+
tt_mem_op(pub1.pubkey, OP_EQ, pub2.pubkey, sizeof(pub1.pubkey));
tt_assert(ed25519_pubkey_eq(&pub1, &pub2));
tt_assert(ed25519_pubkey_eq(&pub1, &pub1));
@@ -2604,6 +2585,39 @@ test_crypto_ed25519_blinding(void *arg)
;
}
+/** Test that our blinding functions will fail if we pass them bad pubkeys */
+static void
+test_crypto_ed25519_blinding_fail(void *arg)
+{
+ int retval;
+ uint8_t param[32] = {2};
+ ed25519_public_key_t pub;
+ ed25519_public_key_t pub_blinded;
+
+ (void)arg;
+
+ /* This point is not on the curve: the blind routines should fail */
+ const char badkey[] =
+ "e19c65de75c68cf3b7643ea732ba9eb1a3d20d6d57ba223c2ece1df66feb5af0";
+ retval = base16_decode((char*)pub.pubkey, sizeof(pub.pubkey),
+ badkey, strlen(badkey));
+ tt_int_op(retval, OP_EQ, sizeof(pub.pubkey));
+ retval = ed25519_public_blind(&pub_blinded, &pub, param);
+ tt_int_op(retval, OP_EQ, -1);
+
+ /* This point is legit: blind routines should be happy */
+ const char goodkey[] =
+ "4ba2e44760dff4c559ef3c38768c1c14a8a54740c782c8d70803e9d6e3ad8794";
+ retval = base16_decode((char*)pub.pubkey, sizeof(pub.pubkey),
+ goodkey, strlen(goodkey));
+ tt_int_op(retval, OP_EQ, sizeof(pub.pubkey));
+ retval = ed25519_public_blind(&pub_blinded, &pub, param);
+ tt_int_op(retval, OP_EQ, 0);
+
+ done:
+ ;
+}
+
static void
test_crypto_ed25519_testvectors(void *arg)
{
@@ -2621,6 +2635,8 @@ test_crypto_ed25519_testvectors(void *arg)
ed25519_signature_t sig;
int sign;
+ memset(&curvekp, 0xd0, sizeof(curvekp));
+
#define DECODE(p,s) base16_decode((char*)(p),sizeof(p),(s),strlen(s))
#define EQ(a,h) test_memeq_hex((const char*)(a), (h))
@@ -2702,8 +2718,8 @@ test_crypto_ed25519_storage(void *arg)
tor_free(tag);
/* whitebox test: truncated keys. */
- tt_int_op(0, ==, do_truncate(fname_1, 40));
- tt_int_op(0, ==, do_truncate(fname_2, 40));
+ tt_int_op(0, OP_EQ, do_truncate(fname_1, 40));
+ tt_int_op(0, OP_EQ, do_truncate(fname_2, 40));
tt_int_op(-1, OP_EQ, ed25519_pubkey_read_from_file(&pub, &tag, fname_2));
tt_ptr_op(tag, OP_EQ, NULL);
tor_free(tag);
@@ -2895,6 +2911,67 @@ crypto_rand_check_failure_mode_predict(void)
#undef FAILURE_MODE_BUFFER_SIZE
+/** Test that our ed25519 validation function rejects evil public keys and
+ * accepts good ones. */
+static void
+test_crypto_ed25519_validation(void *arg)
+{
+ (void) arg;
+
+ int retval;
+ ed25519_public_key_t pub1;
+
+ /* See https://lists.torproject.org/pipermail/tor-dev/2017-April/012230.html
+ for a list of points with torsion components in ed25519. */
+
+ { /* Point with torsion component (order 8l) */
+ const char badkey[] =
+ "300ef2e64e588e1df55b48e4da0416ffb64cc85d5b00af6463d5cc6c2b1c185e";
+ retval = base16_decode((char*)pub1.pubkey, sizeof(pub1.pubkey),
+ badkey, strlen(badkey));
+ tt_int_op(retval, OP_EQ, sizeof(pub1.pubkey));
+ tt_int_op(ed25519_validate_pubkey(&pub1), OP_EQ, -1);
+ }
+
+ { /* Point with torsion component (order 4l) */
+ const char badkey[] =
+ "f43e3a046db8749164c6e69b193f1e942c7452e7d888736f40b98093d814d5e7";
+ retval = base16_decode((char*)pub1.pubkey, sizeof(pub1.pubkey),
+ badkey, strlen(badkey));
+ tt_int_op(retval, OP_EQ, sizeof(pub1.pubkey));
+ tt_int_op(ed25519_validate_pubkey(&pub1), OP_EQ, -1);
+ }
+
+ { /* Point with torsion component (order 2l) */
+ const char badkey[] =
+ "c9fff3af0471c28e33e98c2043e44f779d0427b1e37c521a6bddc011ed1869af";
+ retval = base16_decode((char*)pub1.pubkey, sizeof(pub1.pubkey),
+ badkey, strlen(badkey));
+ tt_int_op(retval, OP_EQ, sizeof(pub1.pubkey));
+ tt_int_op(ed25519_validate_pubkey(&pub1), OP_EQ, -1);
+ }
+
+ { /* This point is not even on the curve */
+ const char badkey[] =
+ "e19c65de75c68cf3b7643ea732ba9eb1a3d20d6d57ba223c2ece1df66feb5af0";
+ retval = base16_decode((char*)pub1.pubkey, sizeof(pub1.pubkey),
+ badkey, strlen(badkey));
+ tt_int_op(retval, OP_EQ, sizeof(pub1.pubkey));
+ tt_int_op(ed25519_validate_pubkey(&pub1), OP_EQ, -1);
+ }
+
+ { /* This one is a good key */
+ const char goodkey[] =
+ "4ba2e44760dff4c559ef3c38768c1c14a8a54740c782c8d70803e9d6e3ad8794";
+ retval = base16_decode((char*)pub1.pubkey, sizeof(pub1.pubkey),
+ goodkey, strlen(goodkey));
+ tt_int_op(retval, OP_EQ, sizeof(pub1.pubkey));
+ tt_int_op(ed25519_validate_pubkey(&pub1), OP_EQ, 0);
+ }
+
+ done: ;
+}
+
static void
test_crypto_failure_modes(void *arg)
{
@@ -2902,17 +2979,17 @@ test_crypto_failure_modes(void *arg)
(void)arg;
rv = crypto_early_init();
- tt_assert(rv == 0);
+ tt_int_op(rv, OP_EQ, 0);
/* Check random works */
rv = crypto_rand_check_failure_mode_zero();
- tt_assert(rv == 0);
+ tt_int_op(rv, OP_EQ, 0);
rv = crypto_rand_check_failure_mode_identical();
- tt_assert(rv == 0);
+ tt_int_op(rv, OP_EQ, 0);
rv = crypto_rand_check_failure_mode_predict();
- tt_assert(rv == 0);
+ tt_int_op(rv, OP_EQ, 0);
done:
;
@@ -2933,7 +3010,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" },
@@ -2959,6 +3035,7 @@ struct testcase_t crypto_tests[] = {
{ "digest_names", test_crypto_digest_names, 0, NULL, NULL },
{ "sha3", test_crypto_sha3, TT_FORK, NULL, NULL},
{ "sha3_xof", test_crypto_sha3_xof, TT_FORK, NULL, NULL},
+ { "mac_sha3", test_crypto_mac_sha3, TT_FORK, NULL, NULL},
CRYPTO_LEGACY(dh),
{ "aes_iv_AES", test_crypto_aes_iv, TT_FORK, &passthrough_setup,
(void*)"aes" },
@@ -2981,7 +3058,9 @@ struct testcase_t crypto_tests[] = {
ED25519_TEST(encode, 0),
ED25519_TEST(convert, 0),
ED25519_TEST(blinding, 0),
+ ED25519_TEST(blinding_fail, 0),
ED25519_TEST(testvectors, 0),
+ ED25519_TEST(validation, 0),
{ "ed25519_storage", test_crypto_ed25519_storage, 0, NULL, NULL },
{ "siphash", test_crypto_siphash, 0, NULL, NULL },
{ "failure_modes", test_crypto_failure_modes, TT_FORK, NULL, NULL },
diff --git a/src/test/test_crypto_openssl.c b/src/test/test_crypto_openssl.c
new file mode 100644
index 0000000000..090cb4242b
--- /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, OP_EQ, 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, OP_EQ, crypto_force_rand_ssleay());
+#else
+ tt_assert(RAND_get_rand_method() == &dummy_method);
+ tt_int_op(1, OP_EQ, crypto_force_rand_ssleay());
+#endif /* defined(LIBRESSL_VERSION_NUMBER) */
+ 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 0be58c9389..2afb71ff5a 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"
@@ -164,10 +164,10 @@ test_libscrypt_eq_openssl(void *arg)
EVP_PBE_scrypt((const char *)"", 0, (const unsigned char *)"", 0,
N, r, p, maxmem, buf2, dk_len);
- tt_int_op(libscrypt_retval, ==, 0);
- tt_int_op(openssl_retval, ==, 1);
+ tt_int_op(libscrypt_retval, OP_EQ, 0);
+ tt_int_op(openssl_retval, OP_EQ, 1);
- tt_mem_op(buf1, ==, buf2, 64);
+ tt_mem_op(buf1, OP_EQ, buf2, 64);
memset(buf1,0,64);
memset(buf2,0,64);
@@ -185,10 +185,10 @@ test_libscrypt_eq_openssl(void *arg)
(const unsigned char *)"NaCl", strlen("NaCl"),
N, r, p, maxmem, buf2, dk_len);
- tt_int_op(libscrypt_retval, ==, 0);
- tt_int_op(openssl_retval, ==, 1);
+ tt_int_op(libscrypt_retval, OP_EQ, 0);
+ tt_int_op(openssl_retval, OP_EQ, 1);
- tt_mem_op(buf1, ==, buf2, 64);
+ tt_mem_op(buf1, OP_EQ, buf2, 64);
memset(buf1,0,64);
memset(buf2,0,64);
@@ -210,10 +210,10 @@ test_libscrypt_eq_openssl(void *arg)
strlen("SodiumChloride"),
N, r, p, maxmem, buf2, dk_len);
- tt_int_op(libscrypt_retval, ==, 0);
- tt_int_op(openssl_retval, ==, 1);
+ tt_int_op(libscrypt_retval, OP_EQ, 0);
+ tt_int_op(openssl_retval, OP_EQ, 1);
- tt_mem_op(buf1, ==, buf2, 64);
+ tt_mem_op(buf1, OP_EQ, buf2, 64);
memset(buf1,0,64);
memset(buf2,0,64);
@@ -234,15 +234,15 @@ test_libscrypt_eq_openssl(void *arg)
strlen("SodiumChloride"),
N, r, p, maxmem, buf2, dk_len);
- tt_int_op(libscrypt_retval, ==, 0);
- tt_int_op(openssl_retval, ==, 1);
+ tt_int_op(libscrypt_retval, OP_EQ, 0);
+ tt_int_op(openssl_retval, OP_EQ, 1);
- tt_mem_op(buf1, ==, buf2, 64);
+ tt_mem_op(buf1, OP_EQ, buf2, 64);
done:
return;
}
-#endif
+#endif /* defined(HAVE_LIBSCRYPT) && defined(HAVE_EVP_PBE_SCRYPT) */
static void
test_crypto_s2k_errors(void *arg)
@@ -283,7 +283,7 @@ test_crypto_s2k_errors(void *arg)
"ABC", 3, 0));
tt_int_op(S2K_TRUNCATED, OP_EQ, secret_to_key_new(buf, 50, &sz,
"ABC", 3, S2K_FLAG_LOW_MEM));
-#endif
+#endif /* defined(HAVE_LIBSCRYPT) */
tt_int_op(S2K_TRUNCATED, OP_EQ, secret_to_key_new(buf, 37, &sz,
"ABC", 3, S2K_FLAG_USE_PBKDF2));
tt_int_op(S2K_TRUNCATED, OP_EQ, secret_to_key_new(buf, 29, &sz,
@@ -318,7 +318,7 @@ test_crypto_s2k_errors(void *arg)
tt_int_op(S2K_BAD_PARAMS, OP_EQ,
secret_to_key_derivekey(buf2, sizeof(buf2),
buf, 19, "ABC", 3));
-#endif
+#endif /* defined(HAVE_LIBSCRYPT) */
done:
;
@@ -516,7 +516,7 @@ test_crypto_ed25519_fuzz_donna(void *arg)
unsigned i;
(void)arg;
- tt_assert(sizeof(msg) == iters);
+ tt_uint_op(iters, OP_EQ, sizeof(msg));
crypto_rand((char*) msg, sizeof(msg));
/* Fuzz Ed25519-donna vs ref10, alternating the implementation used to
@@ -600,7 +600,7 @@ struct testcase_t slow_crypto_tests[] = {
#ifdef HAVE_EVP_PBE_SCRYPT
{ "libscrypt_eq_openssl", test_libscrypt_eq_openssl, 0, NULL, NULL },
#endif
-#endif
+#endif /* defined(HAVE_LIBSCRYPT) */
{ "s2k_pbkdf2", test_crypto_s2k_general, 0, &passthrough_setup,
(void*)"pbkdf2" },
{ "s2k_rfc2440_general", test_crypto_s2k_general, 0, &passthrough_setup,
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 4cdbfb4f84..28489d9392 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
@@ -17,12 +18,15 @@
#define RELAY_PRIVATE
#include "or.h"
+#include "bridges.h"
#include "confparse.h"
#include "config.h"
+#include "control.h"
#include "crypto_ed25519.h"
#include "directory.h"
#include "dirserv.h"
#include "dirvote.h"
+#include "entrynodes.h"
#include "hibernate.h"
#include "memarea.h"
#include "networkstatus.h"
@@ -272,8 +276,8 @@ test_dir_formats(void *arg)
tt_int_op(rp1->bandwidthrate,OP_EQ, r1->bandwidthrate);
tt_int_op(rp1->bandwidthburst,OP_EQ, r1->bandwidthburst);
tt_int_op(rp1->bandwidthcapacity,OP_EQ, r1->bandwidthcapacity);
- tt_assert(crypto_pk_cmp_keys(rp1->onion_pkey, pk1) == 0);
- tt_assert(crypto_pk_cmp_keys(rp1->identity_pkey, pk2) == 0);
+ tt_int_op(crypto_pk_cmp_keys(rp1->onion_pkey, pk1), OP_EQ, 0);
+ tt_int_op(crypto_pk_cmp_keys(rp1->identity_pkey, pk2), OP_EQ, 0);
tt_assert(rp1->supports_tunnelled_dir_requests);
//tt_assert(rp1->exit_policy == NULL);
tor_free(buf);
@@ -291,9 +295,9 @@ test_dir_formats(void *arg)
strlcat(buf2, "master-key-ed25519 ", sizeof(buf2));
{
char k[ED25519_BASE64_LEN+1];
- tt_assert(ed25519_public_to_base64(k,
- &r2->cache_info.signing_key_cert->signing_key)
- >= 0);
+ tt_int_op(ed25519_public_to_base64(k,
+ &r2->cache_info.signing_key_cert->signing_key),
+ OP_GE, 0);
strlcat(buf2, k, sizeof(buf2));
strlcat(buf2, "\n", sizeof(buf2));
}
@@ -328,7 +332,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),
@@ -389,8 +393,8 @@ test_dir_formats(void *arg)
tt_mem_op(rp2->onion_curve25519_pkey->public_key,OP_EQ,
r2->onion_curve25519_pkey->public_key,
CURVE25519_PUBKEY_LEN);
- tt_assert(crypto_pk_cmp_keys(rp2->onion_pkey, pk2) == 0);
- tt_assert(crypto_pk_cmp_keys(rp2->identity_pkey, pk1) == 0);
+ tt_int_op(crypto_pk_cmp_keys(rp2->onion_pkey, pk2), OP_EQ, 0);
+ tt_int_op(crypto_pk_cmp_keys(rp2->identity_pkey, pk1), OP_EQ, 0);
tt_assert(rp2->supports_tunnelled_dir_requests);
tt_int_op(smartlist_len(rp2->exit_policy),OP_EQ, 2);
@@ -419,7 +423,7 @@ test_dir_formats(void *arg)
add_fingerprint_to_dir(buf, fingerprint_list, 0);
}
-#endif
+#endif /* 0 */
dirserv_free_fingerprint_list();
done:
@@ -475,34 +479,34 @@ test_dir_routerinfo_parsing(void *arg)
routerinfo_free(ri);
ri = router_parse_entry_from_string(EX_RI_MINIMAL, NULL, 0, 0,
"@purpose bridge\n", NULL);
- tt_assert(ri != NULL);
+ tt_ptr_op(ri, OP_NE, NULL);
tt_assert(ri->purpose == ROUTER_PURPOSE_BRIDGE);
routerinfo_free(ri);
/* bad annotations prepended. */
ri = router_parse_entry_from_string(EX_RI_MINIMAL,
NULL, 0, 0, "@purpose\n", NULL);
- tt_assert(ri == NULL);
+ tt_ptr_op(ri, OP_EQ, NULL);
/* bad annotations on router. */
ri = router_parse_entry_from_string("@purpose\nrouter x\n", NULL, 0, 1,
NULL, NULL);
- tt_assert(ri == NULL);
+ tt_ptr_op(ri, OP_EQ, NULL);
/* unwanted annotations on router. */
ri = router_parse_entry_from_string("@purpose foo\nrouter x\n", NULL, 0, 0,
NULL, NULL);
- tt_assert(ri == NULL);
+ tt_ptr_op(ri, OP_EQ, NULL);
/* No signature. */
ri = router_parse_entry_from_string("router x\n", NULL, 0, 0,
NULL, NULL);
- tt_assert(ri == NULL);
+ tt_ptr_op(ri, OP_EQ, NULL);
/* Not a router */
routerinfo_free(ri);
ri = router_parse_entry_from_string("hello\n", NULL, 0, 0, NULL, NULL);
- tt_assert(ri == NULL);
+ tt_ptr_op(ri, OP_EQ, NULL);
CHECK_FAIL(EX_RI_BAD_SIG1, 1);
CHECK_FAIL(EX_RI_BAD_SIG2, 1);
@@ -629,11 +633,11 @@ test_dir_extrainfo_parsing(void *arg)
ADD(EX_EI_ED_MISPLACED_SIG);
CHECK_OK(EX_EI_MINIMAL);
- tt_assert(!ei->pending_sig);
+ tt_ptr_op(ei->pending_sig, OP_EQ, NULL);
CHECK_OK(EX_EI_MAXIMAL);
- tt_assert(!ei->pending_sig);
+ tt_ptr_op(ei->pending_sig, OP_EQ, NULL);
CHECK_OK(EX_EI_GOOD_ED_EI);
- tt_assert(!ei->pending_sig);
+ tt_ptr_op(ei->pending_sig, OP_EQ, NULL);
CHECK_FAIL(EX_EI_BAD_SIG1,1);
CHECK_FAIL(EX_EI_BAD_SIG2,1);
@@ -678,16 +682,16 @@ test_dir_parse_router_list(void *arg)
routerinfo_t *ri = NULL;
char d[DIGEST_LEN];
- smartlist_add(chunks, tor_strdup(EX_RI_MINIMAL)); // ri 0
- smartlist_add(chunks, tor_strdup(EX_RI_BAD_PORTS)); // bad ri 0
- smartlist_add(chunks, tor_strdup(EX_EI_MAXIMAL)); // ei 0
- smartlist_add(chunks, tor_strdup(EX_EI_BAD_SIG2)); // bad ei --
- smartlist_add(chunks, tor_strdup(EX_EI_BAD_NICKNAME));// bad ei 0
- smartlist_add(chunks, tor_strdup(EX_RI_BAD_SIG1)); // bad ri --
- smartlist_add(chunks, tor_strdup(EX_EI_BAD_PUBLISHED)); // bad ei 1
- smartlist_add(chunks, tor_strdup(EX_RI_MAXIMAL)); // ri 1
- smartlist_add(chunks, tor_strdup(EX_RI_BAD_FAMILY)); // bad ri 1
- smartlist_add(chunks, tor_strdup(EX_EI_MINIMAL)); // ei 1
+ smartlist_add_strdup(chunks, EX_RI_MINIMAL); // ri 0
+ smartlist_add_strdup(chunks, EX_RI_BAD_PORTS); // bad ri 0
+ smartlist_add_strdup(chunks, EX_EI_MAXIMAL); // ei 0
+ smartlist_add_strdup(chunks, EX_EI_BAD_SIG2); // bad ei --
+ smartlist_add_strdup(chunks, EX_EI_BAD_NICKNAME);// bad ei 0
+ smartlist_add_strdup(chunks, EX_RI_BAD_SIG1); // bad ri --
+ smartlist_add_strdup(chunks, EX_EI_BAD_PUBLISHED); // bad ei 1
+ smartlist_add_strdup(chunks, EX_RI_MAXIMAL); // ri 1
+ smartlist_add_strdup(chunks, EX_RI_BAD_FAMILY); // bad ri 1
+ smartlist_add_strdup(chunks, EX_EI_MINIMAL); // ei 1
list = smartlist_join_strings(chunks, "", 0, NULL);
@@ -812,19 +816,19 @@ test_dir_load_routers(void *arg)
#define ADD(str) \
do { \
tt_int_op(0,OP_EQ,router_get_router_hash(str, strlen(str), buf)); \
- smartlist_add(wanted, tor_strdup(hex_str(buf, DIGEST_LEN))); \
+ smartlist_add_strdup(wanted, hex_str(buf, DIGEST_LEN)); \
} while (0)
MOCK(router_get_dl_status_by_descriptor_digest, mock_router_get_dl_status);
update_approx_time(1412510400);
- smartlist_add(chunks, tor_strdup(EX_RI_MINIMAL));
- smartlist_add(chunks, tor_strdup(EX_RI_BAD_FINGERPRINT));
- smartlist_add(chunks, tor_strdup(EX_RI_BAD_SIG2));
- smartlist_add(chunks, tor_strdup(EX_RI_MAXIMAL));
- smartlist_add(chunks, tor_strdup(EX_RI_BAD_PORTS));
- smartlist_add(chunks, tor_strdup(EX_RI_BAD_TOKENS));
+ smartlist_add_strdup(chunks, EX_RI_MINIMAL);
+ smartlist_add_strdup(chunks, EX_RI_BAD_FINGERPRINT);
+ smartlist_add_strdup(chunks, EX_RI_BAD_SIG2);
+ smartlist_add_strdup(chunks, EX_RI_MAXIMAL);
+ smartlist_add_strdup(chunks, EX_RI_BAD_PORTS);
+ smartlist_add_strdup(chunks, EX_RI_BAD_TOKENS);
/* not ADDing MINIMIAL */
ADD(EX_RI_MAXIMAL);
@@ -909,6 +913,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)
@@ -932,18 +953,18 @@ test_dir_load_extrainfo(void *arg)
#define ADD(str) \
do { \
tt_int_op(0,OP_EQ,router_get_extrainfo_hash(str, strlen(str), buf)); \
- smartlist_add(wanted, tor_strdup(hex_str(buf, DIGEST_LEN))); \
+ smartlist_add_strdup(wanted, hex_str(buf, DIGEST_LEN)); \
} while (0)
mock_ei_insert_list = smartlist_new();
MOCK(router_get_by_extrainfo_digest, mock_get_by_ei_desc_digest);
MOCK(extrainfo_insert, mock_ei_insert);
- smartlist_add(chunks, tor_strdup(EX_EI_MINIMAL));
- smartlist_add(chunks, tor_strdup(EX_EI_BAD_NICKNAME));
- smartlist_add(chunks, tor_strdup(EX_EI_MAXIMAL));
- smartlist_add(chunks, tor_strdup(EX_EI_BAD_PUBLISHED));
- smartlist_add(chunks, tor_strdup(EX_EI_BAD_TOKENS));
+ smartlist_add_strdup(chunks, EX_EI_MINIMAL);
+ smartlist_add_strdup(chunks, EX_EI_BAD_NICKNAME);
+ smartlist_add_strdup(chunks, EX_EI_MAXIMAL);
+ smartlist_add_strdup(chunks, EX_EI_BAD_PUBLISHED);
+ smartlist_add_strdup(chunks, EX_EI_BAD_TOKENS);
/* not ADDing MINIMIAL */
ADD(EX_EI_MAXIMAL);
@@ -998,6 +1019,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;
@@ -1064,6 +1116,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);
@@ -1078,6 +1131,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, \
@@ -1097,6 +1204,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");
@@ -1135,6 +1243,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));
@@ -1144,11 +1316,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. */
@@ -1353,12 +1538,12 @@ test_dir_measured_bw_kb(void *arg)
(void)arg;
for (i = 0; strcmp(lines_fail[i], "end"); i++) {
//fprintf(stderr, "Testing: %s\n", lines_fail[i]);
- tt_assert(measured_bw_line_parse(&mbwl, lines_fail[i]) == -1);
+ tt_int_op(measured_bw_line_parse(&mbwl, lines_fail[i]), OP_EQ, -1);
}
for (i = 0; strcmp(lines_pass[i], "end"); i++) {
//fprintf(stderr, "Testing: %s %d\n", lines_pass[i], TOR_ISSPACE('\n'));
- tt_assert(measured_bw_line_parse(&mbwl, lines_pass[i]) == 0);
+ tt_int_op(measured_bw_line_parse(&mbwl, lines_pass[i]), OP_EQ, 0);
tt_assert(mbwl.bw_kb == 1024);
tt_assert(strcmp(mbwl.node_hex,
"557365204145532d32353620696e73746561642e") == 0);
@@ -1512,6 +1697,15 @@ test_dir_param_voting(void *arg)
tt_int_op(-8,OP_EQ, networkstatus_get_param(&vote4, "ab", -12, -100, -8));
tt_int_op(0,OP_EQ, networkstatus_get_param(&vote4, "foobar", 0, -100, 8));
+ tt_int_op(100,OP_EQ, networkstatus_get_overridable_param(
+ &vote4, -1, "x-yz", 50, 0, 300));
+ tt_int_op(30,OP_EQ, networkstatus_get_overridable_param(
+ &vote4, 30, "x-yz", 50, 0, 300));
+ tt_int_op(0,OP_EQ, networkstatus_get_overridable_param(
+ &vote4, -101, "foobar", 0, -100, 8));
+ tt_int_op(-99,OP_EQ, networkstatus_get_overridable_param(
+ &vote4, -99, "foobar", 0, -100, 8));
+
smartlist_add(votes, &vote1);
/* Do the first tests without adding all the other votes, for
@@ -1611,7 +1805,7 @@ test_dir_param_voting_lookup(void *arg)
dirvote_get_intermediate_param_value(lst, "moomin", -100));
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,
- "!(n_found > 1)");
+ "n_found == 0");
tor_end_capture_bugs_();
/* There is no 'fred=', so that is treated as not existing. */
tt_int_op(-100, OP_EQ,
@@ -1699,8 +1893,7 @@ vote_tweaks_for_v3ns(networkstatus_t *v, int voter, time_t now)
measured_bw_line_t mbw;
memset(mbw.node_id, 33, sizeof(mbw.node_id));
mbw.bw_kb = 1024;
- tt_assert(measured_bw_line_apply(&mbw,
- v->routerstatus_list) == 1);
+ tt_int_op(measured_bw_line_apply(&mbw, v->routerstatus_list), OP_EQ, 1);
} else if (voter == 2 || voter == 3) {
/* Monkey around with the list a bit */
vrs = smartlist_get(v->routerstatus_list, 2);
@@ -1816,7 +2009,7 @@ test_consensus_for_v3ns(networkstatus_t *con, time_t now)
(void)now;
tt_assert(con);
- tt_assert(!con->cert);
+ tt_ptr_op(con->cert, OP_EQ, NULL);
tt_int_op(2,OP_EQ, smartlist_len(con->routerstatus_list));
/* There should be two listed routers: one with identity 3, one with
* identity 5. */
@@ -1886,13 +2079,260 @@ test_routerstatus_for_v3ns(routerstatus_t *rs, time_t now)
/* XXXX check version */
} else {
/* Weren't expecting this... */
- tt_assert(0);
+ tt_abort();
}
done:
return;
}
+static void
+test_dir_networkstatus_compute_bw_weights_v10(void *arg)
+{
+ (void) arg;
+ smartlist_t *chunks = smartlist_new();
+ int64_t G, M, E, D, T, weight_scale;
+ int ret;
+ weight_scale = 10000;
+
+ /* no case. one or more of the values is 0 */
+ G = M = E = D = 0;
+ T = G + M + E + D;
+ ret = networkstatus_compute_bw_weights_v10(chunks, G, M, E, D, T,
+ weight_scale);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_int_op(smartlist_len(chunks), OP_EQ, 0);
+
+ /* case 1 */
+ /* XXX dir-spec not followed? See #20272. If it isn't closed, then this is
+ * testing current behavior, not spec. */
+ G = E = 10;
+ M = D = 1;
+ T = G + M + E + D;
+ ret = networkstatus_compute_bw_weights_v10(chunks, G, M, E, D, T,
+ weight_scale);
+ tt_int_op(ret, OP_EQ, 1);
+ tt_int_op(smartlist_len(chunks), OP_EQ, 1);
+ tt_str_op(smartlist_get(chunks, 0), OP_EQ, "bandwidth-weights Wbd=3333 "
+ "Wbe=3000 Wbg=3000 Wbm=10000 Wdb=10000 Web=10000 Wed=3333 Wee=7000 "
+ "Weg=3333 Wem=7000 Wgb=10000 Wgd=3333 Wgg=7000 Wgm=7000 Wmb=10000 "
+ "Wmd=3333 Wme=3000 Wmg=3000 Wmm=10000\n");
+ SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
+ smartlist_clear(chunks);
+
+ /* case 2a E scarce */
+ M = 100;
+ G = 20;
+ E = D = 5;
+ T = G + M + E + D;
+ ret = networkstatus_compute_bw_weights_v10(chunks, G, M, E, D, T,
+ weight_scale);
+ tt_int_op(ret, OP_EQ, 1);
+ tt_str_op(smartlist_get(chunks, 0), OP_EQ, "bandwidth-weights Wbd=0 Wbe=0 "
+ "Wbg=0 Wbm=10000 Wdb=10000 Web=10000 Wed=10000 Wee=10000 Weg=10000 "
+ "Wem=10000 Wgb=10000 Wgd=0 Wgg=10000 Wgm=10000 Wmb=10000 Wmd=0 Wme=0 "
+ "Wmg=0 Wmm=10000\n");
+ SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
+ smartlist_clear(chunks);
+
+ /* case 2a G scarce */
+ M = 100;
+ E = 20;
+ G = D = 5;
+ T = G + M + E + D;
+ ret = networkstatus_compute_bw_weights_v10(chunks, G, M, E, D, T,
+ weight_scale);
+ tt_int_op(ret, OP_EQ, 1);
+ tt_str_op(smartlist_get(chunks, 0), OP_EQ, "bandwidth-weights Wbd=0 Wbe=0 "
+ "Wbg=0 Wbm=10000 Wdb=10000 Web=10000 Wed=0 Wee=10000 Weg=0 Wem=10000 "
+ "Wgb=10000 Wgd=10000 Wgg=10000 Wgm=10000 Wmb=10000 Wmd=0 Wme=0 Wmg=0 "
+ "Wmm=10000\n");
+ SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
+ smartlist_clear(chunks);
+
+ /* case 2b1 (Wgg=1, Wmd=Wgd) */
+ M = 10;
+ E = 30;
+ G = 10;
+ D = 100;
+ T = G + M + E + D;
+ ret = networkstatus_compute_bw_weights_v10(chunks, G, M, E, D, T,
+ weight_scale);
+ tt_int_op(ret, OP_EQ, 1);
+ tt_str_op(smartlist_get(chunks, 0), OP_EQ, "bandwidth-weights Wbd=4000 "
+ "Wbe=0 Wbg=0 Wbm=10000 Wdb=10000 Web=10000 Wed=2000 Wee=10000 Weg=2000 "
+ "Wem=10000 Wgb=10000 Wgd=4000 Wgg=10000 Wgm=10000 Wmb=10000 Wmd=4000 "
+ "Wme=0 Wmg=0 Wmm=10000\n");
+ SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
+ smartlist_clear(chunks);
+
+ /* case 2b2 */
+ M = 60;
+ E = 30;
+ G = 10;
+ D = 100;
+ T = G + M + E + D;
+ ret = networkstatus_compute_bw_weights_v10(chunks, G, M, E, D, T,
+ weight_scale);
+ tt_int_op(ret, OP_EQ, 1);
+ tt_str_op(smartlist_get(chunks, 0), OP_EQ, "bandwidth-weights Wbd=666 Wbe=0 "
+ "Wbg=0 Wbm=10000 Wdb=10000 Web=10000 Wed=3666 Wee=10000 Weg=3666 "
+ "Wem=10000 Wgb=10000 Wgd=5668 Wgg=10000 Wgm=10000 Wmb=10000 Wmd=666 "
+ "Wme=0 Wmg=0 Wmm=10000\n");
+ SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
+ smartlist_clear(chunks);
+
+ /* case 2b3 */
+ /* XXX I can't get a combination of values that hits this case without error,
+ * so this just tests that it fails. See #20285. Also see #20284 as 2b3 does
+ * not follow dir-spec. */
+ /* (E < T/3 && G < T/3) && (E+D>=G || G+D>=E) && (M > T/3) */
+ M = 80;
+ E = 30;
+ G = 30;
+ D = 30;
+ T = G + M + E + D;
+ ret = networkstatus_compute_bw_weights_v10(chunks, G, M, E, D, T,
+ weight_scale);
+ tt_int_op(ret, OP_EQ, 0);
+ SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
+ smartlist_clear(chunks);
+
+ /* case 3a G scarce */
+ M = 10;
+ E = 30;
+ G = 10;
+ D = 5;
+ T = G + M + E + D;
+ ret = networkstatus_compute_bw_weights_v10(chunks, G, M, E, D, T,
+ weight_scale);
+ tt_int_op(ret, OP_EQ, 1);
+ tt_str_op(smartlist_get(chunks, 0), OP_EQ, "bandwidth-weights Wbd=0 "
+ "Wbe=3333 Wbg=0 Wbm=10000 Wdb=10000 Web=10000 Wed=0 Wee=6667 Weg=0 "
+ "Wem=6667 Wgb=10000 Wgd=10000 Wgg=10000 Wgm=10000 Wmb=10000 Wmd=0 "
+ "Wme=3333 Wmg=0 Wmm=10000\n");
+ SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
+ smartlist_clear(chunks);
+
+ /* case 3a E scarce */
+ M = 10;
+ E = 10;
+ G = 30;
+ D = 5;
+ T = G + M + E + D;
+ ret = networkstatus_compute_bw_weights_v10(chunks, G, M, E, D, T,
+ weight_scale);
+ tt_int_op(ret, OP_EQ, 1);
+ tt_str_op(smartlist_get(chunks, 0), OP_EQ, "bandwidth-weights Wbd=0 Wbe=0 "
+ "Wbg=3333 Wbm=10000 Wdb=10000 Web=10000 Wed=10000 Wee=10000 Weg=10000 "
+ "Wem=10000 Wgb=10000 Wgd=0 Wgg=6667 Wgm=6667 Wmb=10000 Wmd=0 Wme=0 "
+ "Wmg=3333 Wmm=10000\n");
+ SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
+ smartlist_clear(chunks);
+
+ /* case 3bg */
+ M = 10;
+ E = 30;
+ G = 10;
+ D = 10;
+ T = G + M + E + D;
+ ret = networkstatus_compute_bw_weights_v10(chunks, G, M, E, D, T,
+ weight_scale);
+ tt_int_op(ret, OP_EQ, 1);
+ tt_str_op(smartlist_get(chunks, 0), OP_EQ, "bandwidth-weights Wbd=0 "
+ "Wbe=3334 Wbg=0 Wbm=10000 Wdb=10000 Web=10000 Wed=0 Wee=6666 Weg=0 "
+ "Wem=6666 Wgb=10000 Wgd=10000 Wgg=10000 Wgm=10000 Wmb=10000 Wmd=0 "
+ "Wme=3334 Wmg=0 Wmm=10000\n");
+ SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
+ smartlist_clear(chunks);
+
+ /* case 3be */
+ M = 10;
+ E = 10;
+ G = 30;
+ D = 10;
+ T = G + M + E + D;
+ ret = networkstatus_compute_bw_weights_v10(chunks, G, M, E, D, T,
+ weight_scale);
+ tt_int_op(ret, OP_EQ, 1);
+ tt_str_op(smartlist_get(chunks, 0), OP_EQ, "bandwidth-weights Wbd=0 Wbe=0 "
+ "Wbg=3334 Wbm=10000 Wdb=10000 Web=10000 Wed=10000 Wee=10000 Weg=10000 "
+ "Wem=10000 Wgb=10000 Wgd=0 Wgg=6666 Wgm=6666 Wmb=10000 Wmd=0 Wme=0 "
+ "Wmg=3334 Wmm=10000\n");
+ SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
+ smartlist_clear(chunks);
+
+ /* case from 21 Jul 2013 (3be) */
+ G = 5483409;
+ M = 1455379;
+ E = 980834;
+ D = 3385803;
+ T = 11305425;
+ tt_i64_op(G+M+E+D, OP_EQ, T);
+ ret = networkstatus_compute_bw_weights_v10(chunks, G, M, E, D, T,
+ weight_scale);
+ tt_assert(ret);
+ tt_str_op(smartlist_get(chunks, 0), OP_EQ, "bandwidth-weights Wbd=883 Wbe=0 "
+ "Wbg=3673 Wbm=10000 Wdb=10000 Web=10000 Wed=8233 Wee=10000 Weg=8233 "
+ "Wem=10000 Wgb=10000 Wgd=883 Wgg=6327 Wgm=6327 Wmb=10000 Wmd=883 Wme=0 "
+ "Wmg=3673 Wmm=10000\n");
+ SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
+ smartlist_clear(chunks);
+
+ /* case from 04 Oct 2016 (3a E scarce) */
+ G=29322240;
+ M=4721546;
+ E=1522058;
+ D=9273571;
+ T=44839415;
+ tt_i64_op(G+M+E+D, OP_EQ, T);
+ ret = networkstatus_compute_bw_weights_v10(chunks, G, M, E, D, T,
+ weight_scale);
+ tt_assert(ret);
+ tt_str_op(smartlist_get(chunks, 0), OP_EQ, "bandwidth-weights Wbd=0 Wbe=0 "
+ "Wbg=4194 Wbm=10000 Wdb=10000 Web=10000 Wed=10000 Wee=10000 Weg=10000 "
+ "Wem=10000 Wgb=10000 Wgd=0 Wgg=5806 Wgm=5806 Wmb=10000 Wmd=0 Wme=0 "
+ "Wmg=4194 Wmm=10000\n");
+ SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
+ smartlist_clear(chunks);
+
+ /* case from 04 Sep 2013 (2b1) */
+ G=3091352;
+ M=1838837;
+ E=2109300;
+ D=2469369;
+ T=9508858;
+ tt_i64_op(G+M+E+D, OP_EQ, T);
+ ret = networkstatus_compute_bw_weights_v10(chunks, G, M, E, D, T,
+ weight_scale);
+ tt_assert(ret);
+ tt_str_op(smartlist_get(chunks, 0), OP_EQ, "bandwidth-weights Wbd=317 "
+ "Wbe=5938 Wbg=0 Wbm=10000 Wdb=10000 Web=10000 Wed=9366 Wee=4061 "
+ "Weg=9366 Wem=4061 Wgb=10000 Wgd=317 Wgg=10000 Wgm=10000 Wmb=10000 "
+ "Wmd=317 Wme=5938 Wmg=0 Wmm=10000\n");
+ SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
+ smartlist_clear(chunks);
+
+ /* explicitly test initializing weights to 1*/
+ G=1;
+ M=1;
+ E=1;
+ D=1;
+ T=4;
+ tt_i64_op(G+M+E+D, OP_EQ, T);
+ ret = networkstatus_compute_bw_weights_v10(chunks, G, M, E, D, T,
+ weight_scale);
+ tt_str_op(smartlist_get(chunks, 0), OP_EQ, "bandwidth-weights Wbd=3333 "
+ "Wbe=0 Wbg=0 Wbm=10000 Wdb=10000 Web=10000 Wed=3333 Wee=10000 Weg=3333 "
+ "Wem=10000 Wgb=10000 Wgd=3333 Wgg=10000 Wgm=10000 Wmb=10000 Wmd=3333 "
+ "Wme=0 Wmg=0 Wmm=10000\n");
+ tt_assert(ret);
+
+ done:
+ SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
+ smartlist_free(chunks);
+}
+
static authority_cert_t *mock_cert;
static authority_cert_t *
@@ -1958,6 +2398,7 @@ test_a_networkstatus(
sign_skey_2 = crypto_pk_new();
sign_skey_3 = crypto_pk_new();
sign_skey_leg1 = pk_generate(4);
+ dirvote_recalculate_timing(get_options(), now);
sr_state_init(0, 0);
tt_assert(!crypto_pk_read_private_key_from_string(sign_skey_1,
@@ -2587,7 +3028,7 @@ gen_routerstatus_for_umbw(int idx, time_t now)
break;
default:
/* Shouldn't happen */
- tt_assert(0);
+ tt_abort();
}
if (vrs) {
vrs->microdesc = tor_malloc_zero(sizeof(vote_microdesc_hash_t));
@@ -2727,7 +3168,7 @@ test_vrs_for_umbw(vote_routerstatus_t *vrs, int voter, time_t now)
tt_int_op(rs->bandwidth_kb,OP_EQ, max_unmeasured_bw_kb / 2);
tt_int_op(vrs->measured_bw_kb,OP_EQ, 0);
} else {
- tt_assert(0);
+ tt_abort();
}
done:
@@ -2743,9 +3184,9 @@ test_consensus_for_umbw(networkstatus_t *con, time_t now)
(void)now;
tt_assert(con);
- tt_assert(!con->cert);
+ tt_ptr_op(con->cert, OP_EQ, NULL);
// tt_assert(con->consensus_method >= MIN_METHOD_TO_CLIP_UNMEASURED_BW_KB);
- tt_assert(con->consensus_method >= 16);
+ tt_int_op(con->consensus_method, OP_GE, 16);
tt_int_op(4,OP_EQ, smartlist_len(con->routerstatus_list));
/* There should be four listed routers; all voters saw the same in this */
@@ -2842,7 +3283,7 @@ test_routerstatus_for_umbw(routerstatus_t *rs, time_t now)
tt_assert(rs->bw_is_unmeasured);
} else {
/* Weren't expecting this... */
- tt_assert(0);
+ tt_abort();
}
done:
@@ -2949,7 +3390,7 @@ mock_get_options(void)
static void
reset_routerstatus(routerstatus_t *rs,
const char *hex_identity_digest,
- int32_t ipv4_addr)
+ uint32_t ipv4_addr)
{
memset(rs, 0, sizeof(routerstatus_t));
base16_decode(rs->identity_digest, sizeof(rs->identity_digest),
@@ -3010,15 +3451,17 @@ test_dir_dirserv_set_routerstatus_testing(void *arg)
* Return values are {2, 3, 4} */
/* We want 3 ("*" means match all addresses) */
- tt_assert(routerset_contains_routerstatus(routerset_all, rs_a, 0) == 3);
- tt_assert(routerset_contains_routerstatus(routerset_all, rs_b, 0) == 3);
+ tt_int_op(routerset_contains_routerstatus(routerset_all, rs_a, 0), OP_EQ, 3);
+ tt_int_op(routerset_contains_routerstatus(routerset_all, rs_b, 0), OP_EQ, 3);
/* We want 4 (match id_digest [or nickname]) */
- tt_assert(routerset_contains_routerstatus(routerset_a, rs_a, 0) == 4);
- tt_assert(routerset_contains_routerstatus(routerset_a, rs_b, 0) == 0);
+ tt_int_op(routerset_contains_routerstatus(routerset_a, rs_a, 0), OP_EQ, 4);
+ tt_int_op(routerset_contains_routerstatus(routerset_a, rs_b, 0), OP_EQ, 0);
- tt_assert(routerset_contains_routerstatus(routerset_none, rs_a, 0) == 0);
- tt_assert(routerset_contains_routerstatus(routerset_none, rs_b, 0) == 0);
+ tt_int_op(routerset_contains_routerstatus(routerset_none, rs_a, 0), OP_EQ,
+ 0);
+ tt_int_op(routerset_contains_routerstatus(routerset_none, rs_b, 0), OP_EQ,
+ 0);
/* Check that "*" sets flags on all routers: Exit
* Check the flags aren't being confused with each other */
@@ -3030,17 +3473,17 @@ test_dir_dirserv_set_routerstatus_testing(void *arg)
mock_options->TestingDirAuthVoteExitIsStrict = 0;
dirserv_set_routerstatus_testing(rs_a);
- tt_assert(mock_get_options_calls == 1);
+ tt_int_op(mock_get_options_calls, OP_EQ, 1);
dirserv_set_routerstatus_testing(rs_b);
- tt_assert(mock_get_options_calls == 2);
+ tt_int_op(mock_get_options_calls, OP_EQ, 2);
- tt_assert(rs_a->is_exit == 1);
- tt_assert(rs_b->is_exit == 1);
+ tt_uint_op(rs_a->is_exit, OP_EQ, 1);
+ tt_uint_op(rs_b->is_exit, OP_EQ, 1);
/* Be paranoid - check no other flags are set */
- tt_assert(rs_a->is_possible_guard == 0);
- tt_assert(rs_b->is_possible_guard == 0);
- tt_assert(rs_a->is_hs_dir == 0);
- tt_assert(rs_b->is_hs_dir == 0);
+ tt_uint_op(rs_a->is_possible_guard, OP_EQ, 0);
+ tt_uint_op(rs_b->is_possible_guard, OP_EQ, 0);
+ tt_uint_op(rs_a->is_hs_dir, OP_EQ, 0);
+ tt_uint_op(rs_b->is_hs_dir, OP_EQ, 0);
/* Check that "*" sets flags on all routers: Guard & HSDir
* Cover the remaining flags in one test */
@@ -3054,17 +3497,17 @@ test_dir_dirserv_set_routerstatus_testing(void *arg)
mock_options->TestingDirAuthVoteHSDirIsStrict = 0;
dirserv_set_routerstatus_testing(rs_a);
- tt_assert(mock_get_options_calls == 1);
+ tt_int_op(mock_get_options_calls, OP_EQ, 1);
dirserv_set_routerstatus_testing(rs_b);
- tt_assert(mock_get_options_calls == 2);
+ tt_int_op(mock_get_options_calls, OP_EQ, 2);
- tt_assert(rs_a->is_possible_guard == 1);
- tt_assert(rs_b->is_possible_guard == 1);
- tt_assert(rs_a->is_hs_dir == 1);
- tt_assert(rs_b->is_hs_dir == 1);
+ tt_uint_op(rs_a->is_possible_guard, OP_EQ, 1);
+ tt_uint_op(rs_b->is_possible_guard, OP_EQ, 1);
+ tt_uint_op(rs_a->is_hs_dir, OP_EQ, 1);
+ tt_uint_op(rs_b->is_hs_dir, OP_EQ, 1);
/* Be paranoid - check exit isn't set */
- tt_assert(rs_a->is_exit == 0);
- tt_assert(rs_b->is_exit == 0);
+ tt_uint_op(rs_a->is_exit, OP_EQ, 0);
+ tt_uint_op(rs_b->is_exit, OP_EQ, 0);
/* Check routerset A sets all flags on router A,
* but leaves router B unmodified */
@@ -3080,16 +3523,16 @@ test_dir_dirserv_set_routerstatus_testing(void *arg)
mock_options->TestingDirAuthVoteHSDirIsStrict = 0;
dirserv_set_routerstatus_testing(rs_a);
- tt_assert(mock_get_options_calls == 1);
+ tt_int_op(mock_get_options_calls, OP_EQ, 1);
dirserv_set_routerstatus_testing(rs_b);
- tt_assert(mock_get_options_calls == 2);
+ tt_int_op(mock_get_options_calls, OP_EQ, 2);
- tt_assert(rs_a->is_exit == 1);
- tt_assert(rs_b->is_exit == 0);
- tt_assert(rs_a->is_possible_guard == 1);
- tt_assert(rs_b->is_possible_guard == 0);
- tt_assert(rs_a->is_hs_dir == 1);
- tt_assert(rs_b->is_hs_dir == 0);
+ tt_uint_op(rs_a->is_exit, OP_EQ, 1);
+ tt_uint_op(rs_b->is_exit, OP_EQ, 0);
+ tt_uint_op(rs_a->is_possible_guard, OP_EQ, 1);
+ tt_uint_op(rs_b->is_possible_guard, OP_EQ, 0);
+ tt_uint_op(rs_a->is_hs_dir, OP_EQ, 1);
+ tt_uint_op(rs_b->is_hs_dir, OP_EQ, 0);
/* Check routerset A unsets all flags on router B when Strict is set */
reset_options(mock_options, &mock_get_options_calls);
@@ -3107,11 +3550,11 @@ test_dir_dirserv_set_routerstatus_testing(void *arg)
rs_b->is_hs_dir = 1;
dirserv_set_routerstatus_testing(rs_b);
- tt_assert(mock_get_options_calls == 1);
+ tt_int_op(mock_get_options_calls, OP_EQ, 1);
- tt_assert(rs_b->is_exit == 0);
- tt_assert(rs_b->is_possible_guard == 0);
- tt_assert(rs_b->is_hs_dir == 0);
+ tt_uint_op(rs_b->is_exit, OP_EQ, 0);
+ tt_uint_op(rs_b->is_possible_guard, OP_EQ, 0);
+ tt_uint_op(rs_b->is_hs_dir, OP_EQ, 0);
/* Check routerset A doesn't modify flags on router B without Strict set */
reset_options(mock_options, &mock_get_options_calls);
@@ -3129,11 +3572,11 @@ test_dir_dirserv_set_routerstatus_testing(void *arg)
rs_b->is_hs_dir = 1;
dirserv_set_routerstatus_testing(rs_b);
- tt_assert(mock_get_options_calls == 1);
+ tt_int_op(mock_get_options_calls, OP_EQ, 1);
- tt_assert(rs_b->is_exit == 1);
- tt_assert(rs_b->is_possible_guard == 1);
- tt_assert(rs_b->is_hs_dir == 1);
+ tt_uint_op(rs_b->is_exit, OP_EQ, 1);
+ tt_uint_op(rs_b->is_possible_guard, OP_EQ, 1);
+ tt_uint_op(rs_b->is_hs_dir, OP_EQ, 1);
/* Check the empty routerset zeroes all flags
* on routers A & B with Strict set */
@@ -3152,11 +3595,11 @@ test_dir_dirserv_set_routerstatus_testing(void *arg)
rs_b->is_hs_dir = 1;
dirserv_set_routerstatus_testing(rs_b);
- tt_assert(mock_get_options_calls == 1);
+ tt_int_op(mock_get_options_calls, OP_EQ, 1);
- tt_assert(rs_b->is_exit == 0);
- tt_assert(rs_b->is_possible_guard == 0);
- tt_assert(rs_b->is_hs_dir == 0);
+ tt_uint_op(rs_b->is_exit, OP_EQ, 0);
+ tt_uint_op(rs_b->is_possible_guard, OP_EQ, 0);
+ tt_uint_op(rs_b->is_hs_dir, OP_EQ, 0);
/* Check the empty routerset doesn't modify any flags
* on A or B without Strict set */
@@ -3176,16 +3619,16 @@ test_dir_dirserv_set_routerstatus_testing(void *arg)
rs_b->is_hs_dir = 1;
dirserv_set_routerstatus_testing(rs_a);
- tt_assert(mock_get_options_calls == 1);
+ tt_int_op(mock_get_options_calls, OP_EQ, 1);
dirserv_set_routerstatus_testing(rs_b);
- tt_assert(mock_get_options_calls == 2);
+ tt_int_op(mock_get_options_calls, OP_EQ, 2);
- tt_assert(rs_a->is_exit == 0);
- tt_assert(rs_a->is_possible_guard == 0);
- tt_assert(rs_a->is_hs_dir == 0);
- tt_assert(rs_b->is_exit == 1);
- tt_assert(rs_b->is_possible_guard == 1);
- tt_assert(rs_b->is_hs_dir == 1);
+ tt_uint_op(rs_a->is_exit, OP_EQ, 0);
+ tt_uint_op(rs_a->is_possible_guard, OP_EQ, 0);
+ tt_uint_op(rs_a->is_hs_dir, OP_EQ, 0);
+ tt_uint_op(rs_b->is_exit, OP_EQ, 1);
+ tt_uint_op(rs_b->is_possible_guard, OP_EQ, 1);
+ tt_uint_op(rs_b->is_hs_dir, OP_EQ, 1);
done:
tor_free(mock_options);
@@ -3241,7 +3684,7 @@ test_dir_http_handling(void *args)
"User-Agent: Mozilla/5.0 (Windows;"
" U; Windows NT 6.1; en-US; rv:1.9.1.5)\r\n",
&url),OP_EQ, -1);
- tt_assert(!url);
+ tt_ptr_op(url, OP_EQ, NULL);
/* Bad headers */
tt_int_op(parse_http_url("GET /a/b/c.txt\r\n"
@@ -3249,40 +3692,113 @@ test_dir_http_handling(void *args)
"User-Agent: Mozilla/5.0 (Windows;"
" U; Windows NT 6.1; en-US; rv:1.9.1.5)\r\n",
&url),OP_EQ, -1);
- tt_assert(!url);
+ tt_ptr_op(url, OP_EQ, NULL);
tt_int_op(parse_http_url("GET /tor/a/b/c.txt", &url),OP_EQ, -1);
- tt_assert(!url);
+ tt_ptr_op(url, OP_EQ, NULL);
tt_int_op(parse_http_url("GET /tor/a/b/c.txt HTTP/1.1", &url),OP_EQ, -1);
- tt_assert(!url);
+ tt_ptr_op(url, OP_EQ, NULL);
tt_int_op(parse_http_url("GET /tor/a/b/c.txt HTTP/1.1x\r\n", &url),
OP_EQ, -1);
- tt_assert(!url);
+ tt_ptr_op(url, OP_EQ, NULL);
tt_int_op(parse_http_url("GET /tor/a/b/c.txt HTTP/1.", &url),OP_EQ, -1);
- tt_assert(!url);
+ tt_ptr_op(url, OP_EQ, NULL);
tt_int_op(parse_http_url("GET /tor/a/b/c.txt HTTP/1.\r", &url),OP_EQ, -1);
- tt_assert(!url);
+ tt_ptr_op(url, OP_EQ, NULL);
done:
tor_free(url);
}
static void
-test_dir_purpose_needs_anonymity(void *arg)
+test_dir_purpose_needs_anonymity_returns_true_by_default(void *arg)
{
(void)arg;
- tt_int_op(1, ==, purpose_needs_anonymity(0, ROUTER_PURPOSE_BRIDGE));
- tt_int_op(1, ==, purpose_needs_anonymity(0, ROUTER_PURPOSE_GENERAL));
- tt_int_op(0, ==, purpose_needs_anonymity(DIR_PURPOSE_FETCH_MICRODESC,
- ROUTER_PURPOSE_GENERAL));
+
+ tor_capture_bugs_(1);
+ setup_full_capture_of_logs(LOG_WARN);
+ tt_int_op(1, OP_EQ, purpose_needs_anonymity(0, 0, NULL));
+ tt_int_op(1, OP_EQ, smartlist_len(tor_get_captured_bug_log_()));
+ expect_single_log_msg_containing("Called with dir_purpose=0");
+
+ tor_end_capture_bugs_();
+ done:
+ tor_end_capture_bugs_();
+ teardown_capture_of_logs();
+}
+
+static void
+test_dir_purpose_needs_anonymity_returns_true_for_bridges(void *arg)
+{
+ (void)arg;
+
+ tt_int_op(1, OP_EQ, purpose_needs_anonymity(0, ROUTER_PURPOSE_BRIDGE, NULL));
+ tt_int_op(1, OP_EQ, purpose_needs_anonymity(0, ROUTER_PURPOSE_BRIDGE,
+ "foobar"));
+ tt_int_op(1, OP_EQ,
+ purpose_needs_anonymity(DIR_PURPOSE_HAS_FETCHED_RENDDESC_V2,
+ ROUTER_PURPOSE_BRIDGE, NULL));
+ done: ;
+}
+
+static void
+test_dir_purpose_needs_anonymity_returns_false_for_own_bridge_desc(void *arg)
+{
+ (void)arg;
+ tt_int_op(0, OP_EQ, purpose_needs_anonymity(DIR_PURPOSE_FETCH_SERVERDESC,
+ ROUTER_PURPOSE_BRIDGE,
+ "authority.z"));
done: ;
}
static void
+test_dir_purpose_needs_anonymity_returns_true_for_sensitive_purpose(void *arg)
+{
+ (void)arg;
+
+ tt_int_op(1, OP_EQ, purpose_needs_anonymity(
+ DIR_PURPOSE_HAS_FETCHED_RENDDESC_V2,
+ ROUTER_PURPOSE_GENERAL, NULL));
+ tt_int_op(1, OP_EQ, purpose_needs_anonymity(
+ DIR_PURPOSE_UPLOAD_RENDDESC_V2, 0, NULL));
+ tt_int_op(1, OP_EQ, purpose_needs_anonymity(
+ DIR_PURPOSE_FETCH_RENDDESC_V2, 0, NULL));
+ done: ;
+}
+
+static void
+test_dir_purpose_needs_anonymity_ret_false_for_non_sensitive_conn(void *arg)
+{
+ (void)arg;
+
+ tt_int_op(0, OP_EQ, purpose_needs_anonymity(DIR_PURPOSE_UPLOAD_DIR,
+ ROUTER_PURPOSE_GENERAL, NULL));
+ tt_int_op(0, OP_EQ,
+ purpose_needs_anonymity(DIR_PURPOSE_UPLOAD_VOTE, 0, NULL));
+ tt_int_op(0, OP_EQ,
+ purpose_needs_anonymity(DIR_PURPOSE_UPLOAD_SIGNATURES, 0, NULL));
+ tt_int_op(0, OP_EQ,
+ purpose_needs_anonymity(DIR_PURPOSE_FETCH_STATUS_VOTE, 0, NULL));
+ tt_int_op(0, OP_EQ, purpose_needs_anonymity(
+ DIR_PURPOSE_FETCH_DETACHED_SIGNATURES, 0, NULL));
+ tt_int_op(0, OP_EQ,
+ purpose_needs_anonymity(DIR_PURPOSE_FETCH_CONSENSUS, 0, NULL));
+ tt_int_op(0, OP_EQ,
+ purpose_needs_anonymity(DIR_PURPOSE_FETCH_CERTIFICATE, 0, NULL));
+ tt_int_op(0, OP_EQ,
+ purpose_needs_anonymity(DIR_PURPOSE_FETCH_SERVERDESC, 0, NULL));
+ tt_int_op(0, OP_EQ,
+ purpose_needs_anonymity(DIR_PURPOSE_FETCH_EXTRAINFO, 0, NULL));
+ tt_int_op(0, OP_EQ,
+ purpose_needs_anonymity(DIR_PURPOSE_FETCH_MICRODESC, 0, NULL));
+ done: ;
+}
+
+static void
test_dir_fetch_type(void *arg)
{
(void)arg;
@@ -3330,9 +3846,9 @@ test_dir_packages(void *arg)
(void)arg;
#define BAD(s) \
- tt_int_op(0, ==, validate_recommended_package_line(s));
+ tt_int_op(0, OP_EQ, validate_recommended_package_line(s));
#define GOOD(s) \
- tt_int_op(1, ==, validate_recommended_package_line(s));
+ tt_int_op(1, OP_EQ, validate_recommended_package_line(s));
GOOD("tor 0.2.6.3-alpha "
"http://torproject.example.com/dist/tor-0.2.6.3-alpha.tar.gz "
"sha256=sssdlkfjdsklfjdskfljasdklfj");
@@ -3449,7 +3965,7 @@ test_dir_packages(void *arg)
res = compute_consensus_package_lines(votes);
tt_assert(res);
- tt_str_op(res, ==,
+ tt_str_op(res, OP_EQ,
"package cbc 99.1.11.1.1 http://example.com/cbc/ cubehash=ahooy sha512=m\n"
"package clownshoes 22alpha3 http://quumble.example.com/ blake2=fooz\n"
"package clownshoes 22alpha4 http://quumble.example.cam/ blake2=fooa\n"
@@ -3621,47 +4137,105 @@ test_dir_download_status_schedule(void *arg)
}
static void
-test_dir_download_status_random_backoff(void *arg)
+download_status_random_backoff_helper(int min_delay, int max_delay)
{
download_status_t dls_random =
{ 0, 0, 0, DL_SCHED_GENERIC, DL_WANT_AUTHORITY,
DL_SCHED_INCREMENT_FAILURE, DL_SCHED_RANDOM_EXPONENTIAL, 0, 0 };
int increment = -1;
- int old_increment;
+ int old_increment = -1;
time_t current_time = time(NULL);
- const int min_delay = 0;
- const int max_delay = 1000000;
-
- (void)arg;
/* Check the random backoff cases */
- old_increment = 0;
+ int n_attempts = 0;
do {
increment = download_status_schedule_get_delay(&dls_random,
NULL,
min_delay, max_delay,
current_time);
+
+ log_debug(LD_DIR, "Min: %d, Max: %d, Inc: %d, Old Inc: %d",
+ min_delay, max_delay, increment, old_increment);
+
+ /* Regression test for 20534 and friends
+ * increment must always increase after the first */
+ if (dls_random.last_backoff_position > 0 && max_delay > 0) {
+ /* Always increment the exponential backoff */
+ tt_int_op(increment, OP_GE, 1);
+ }
+
/* Test */
tt_int_op(increment, OP_GE, min_delay);
tt_int_op(increment, OP_LE, max_delay);
- tt_int_op(increment, OP_GE, old_increment);
- /* We at most quadruple, and maybe add one */
- tt_int_op(increment, OP_LE, 4 * old_increment + 1);
/* Advance */
- current_time += increment;
- ++(dls_random.n_download_attempts);
- ++(dls_random.n_download_failures);
+ if (dls_random.n_download_attempts < IMPOSSIBLE_TO_DOWNLOAD - 1) {
+ ++(dls_random.n_download_attempts);
+ ++(dls_random.n_download_failures);
+ }
/* Try another maybe */
old_increment = increment;
- } while (increment < max_delay);
+ } while (increment < max_delay && ++n_attempts < 1000);
done:
return;
}
static void
+test_dir_download_status_random_backoff(void *arg)
+{
+ (void)arg;
+
+ /* Do a standard test */
+ download_status_random_backoff_helper(0, 1000000);
+ /* Regression test for 20534 and friends:
+ * try tighter bounds */
+ download_status_random_backoff_helper(0, 100);
+ /* regression tests for 17750: initial delay */
+ download_status_random_backoff_helper(10, 1000);
+ download_status_random_backoff_helper(20, 30);
+
+ /* Pathological cases */
+ download_status_random_backoff_helper(0, 0);
+ download_status_random_backoff_helper(1, 1);
+ download_status_random_backoff_helper(0, INT_MAX);
+ download_status_random_backoff_helper(INT_MAX/2, INT_MAX);
+}
+
+static void
+test_dir_download_status_random_backoff_ranges(void *arg)
+{
+ (void)arg;
+ int lo, hi;
+ next_random_exponential_delay_range(&lo, &hi, 0, 10);
+ tt_int_op(lo, OP_EQ, 10);
+ tt_int_op(hi, OP_EQ, 11);
+
+ next_random_exponential_delay_range(&lo, &hi, 6, 10);
+ tt_int_op(lo, OP_EQ, 10);
+ tt_int_op(hi, OP_EQ, 6*3);
+
+ next_random_exponential_delay_range(&lo, &hi, 13, 10);
+ tt_int_op(lo, OP_EQ, 10);
+ tt_int_op(hi, OP_EQ, 13 * 3);
+
+ next_random_exponential_delay_range(&lo, &hi, 37, 10);
+ tt_int_op(lo, OP_EQ, 10);
+ tt_int_op(hi, OP_EQ, 111);
+
+ next_random_exponential_delay_range(&lo, &hi, 123, 10);
+ tt_int_op(lo, OP_EQ, 10);
+ tt_int_op(hi, OP_EQ, 369);
+
+ next_random_exponential_delay_range(&lo, &hi, INT_MAX-5, 10);
+ tt_int_op(lo, OP_EQ, 10);
+ tt_int_op(hi, OP_EQ, INT_MAX);
+ done:
+ ;
+}
+
+static void
test_dir_download_status_increment(void *arg)
{
(void)arg;
@@ -3673,32 +4247,97 @@ test_dir_download_status_increment(void *arg)
DL_WANT_ANY_DIRSERVER,
DL_SCHED_INCREMENT_ATTEMPT,
DL_SCHED_DETERMINISTIC, 0, 0 };
+ download_status_t dls_exp = { 0, 0, 0, DL_SCHED_GENERIC,
+ DL_WANT_ANY_DIRSERVER,
+ DL_SCHED_INCREMENT_ATTEMPT,
+ DL_SCHED_RANDOM_EXPONENTIAL, 0, 0 };
+ int no_delay = 0;
int delay0 = -1;
int delay1 = -1;
int delay2 = -1;
smartlist_t *schedule = smartlist_new();
+ smartlist_t *schedule_no_initial_delay = smartlist_new();
or_options_t test_options;
time_t next_at = TIME_MAX;
time_t current_time = time(NULL);
- /* Provide some values for the schedule */
+ /* Provide some values for the schedules */
delay0 = 10;
delay1 = 99;
delay2 = 20;
- /* Make the schedule */
+ /* Make the schedules */
smartlist_add(schedule, (void *)&delay0);
smartlist_add(schedule, (void *)&delay1);
smartlist_add(schedule, (void *)&delay2);
+ smartlist_add(schedule_no_initial_delay, (void *)&no_delay);
+ smartlist_add(schedule_no_initial_delay, (void *)&delay1);
+ smartlist_add(schedule_no_initial_delay, (void *)&delay2);
+
/* Put it in the options */
mock_options = &test_options;
reset_options(mock_options, &mock_get_options_calls);
+ mock_options->TestingBridgeBootstrapDownloadSchedule = schedule;
mock_options->TestingClientDownloadSchedule = schedule;
- mock_options->TestingBridgeDownloadSchedule = schedule;
MOCK(get_options, mock_get_options);
+ /* Check that the initial value of the schedule is the first value used,
+ * whether or not it was reset before being used */
+
+ /* regression test for 17750: no initial delay */
+ mock_options->TestingClientDownloadSchedule = schedule_no_initial_delay;
+ mock_get_options_calls = 0;
+ /* we really want to test that it's equal to time(NULL) + delay0, but that's
+ * an unrealiable test, because time(NULL) might change. */
+ tt_assert(download_status_get_next_attempt_at(&dls_failure)
+ >= current_time + no_delay);
+ tt_assert(download_status_get_next_attempt_at(&dls_failure)
+ != TIME_MAX);
+ tt_int_op(download_status_get_n_failures(&dls_failure), OP_EQ, 0);
+ tt_int_op(download_status_get_n_attempts(&dls_failure), OP_EQ, 0);
+ tt_int_op(mock_get_options_calls, OP_GE, 1);
+
+ /* regression test for 17750: initial delay */
+ mock_options->TestingClientDownloadSchedule = schedule;
+ mock_get_options_calls = 0;
+ /* we really want to test that it's equal to time(NULL) + delay0, but that's
+ * an unrealiable test, because time(NULL) might change. */
+ tt_assert(download_status_get_next_attempt_at(&dls_failure)
+ >= current_time + delay0);
+ tt_assert(download_status_get_next_attempt_at(&dls_failure)
+ != TIME_MAX);
+ tt_int_op(download_status_get_n_failures(&dls_failure), OP_EQ, 0);
+ tt_int_op(download_status_get_n_attempts(&dls_failure), OP_EQ, 0);
+ tt_int_op(mock_get_options_calls, OP_GE, 1);
+
+ /* regression test for 17750: exponential, no initial delay */
+ mock_options->TestingClientDownloadSchedule = schedule_no_initial_delay;
+ mock_get_options_calls = 0;
+ /* we really want to test that it's equal to time(NULL) + delay0, but that's
+ * an unrealiable test, because time(NULL) might change. */
+ tt_assert(download_status_get_next_attempt_at(&dls_exp)
+ >= current_time + no_delay);
+ tt_assert(download_status_get_next_attempt_at(&dls_exp)
+ != TIME_MAX);
+ tt_int_op(download_status_get_n_failures(&dls_exp), OP_EQ, 0);
+ tt_int_op(download_status_get_n_attempts(&dls_exp), OP_EQ, 0);
+ tt_int_op(mock_get_options_calls, OP_GE, 1);
+
+ /* regression test for 17750: exponential, initial delay */
+ mock_options->TestingClientDownloadSchedule = schedule;
+ mock_get_options_calls = 0;
+ /* we really want to test that it's equal to time(NULL) + delay0, but that's
+ * an unrealiable test, because time(NULL) might change. */
+ tt_assert(download_status_get_next_attempt_at(&dls_exp)
+ >= current_time + delay0);
+ tt_assert(download_status_get_next_attempt_at(&dls_exp)
+ != TIME_MAX);
+ tt_int_op(download_status_get_n_failures(&dls_exp), OP_EQ, 0);
+ tt_int_op(download_status_get_n_attempts(&dls_exp), OP_EQ, 0);
+ tt_int_op(mock_get_options_calls, OP_GE, 1);
+
/* Check that a failure reset works */
mock_get_options_calls = 0;
download_status_reset(&dls_failure);
@@ -3708,76 +4347,76 @@ test_dir_download_status_increment(void *arg)
>= current_time + delay0);
tt_assert(download_status_get_next_attempt_at(&dls_failure)
!= TIME_MAX);
- tt_assert(download_status_get_n_failures(&dls_failure) == 0);
- tt_assert(download_status_get_n_attempts(&dls_failure) == 0);
- tt_assert(mock_get_options_calls >= 1);
+ tt_int_op(download_status_get_n_failures(&dls_failure), OP_EQ, 0);
+ tt_int_op(download_status_get_n_attempts(&dls_failure), OP_EQ, 0);
+ tt_int_op(mock_get_options_calls, OP_GE, 1);
/* avoid timing inconsistencies */
dls_failure.next_attempt_at = current_time + delay0;
/* check that a reset schedule becomes ready at the right time */
- tt_assert(download_status_is_ready(&dls_failure,
- current_time + delay0 - 1,
- 1) == 0);
- tt_assert(download_status_is_ready(&dls_failure,
- current_time + delay0,
- 1) == 1);
- tt_assert(download_status_is_ready(&dls_failure,
- current_time + delay0 + 1,
- 1) == 1);
+ tt_int_op(download_status_is_ready(&dls_failure,
+ current_time + delay0 - 1, 1),
+ OP_EQ, 0);
+ tt_int_op(download_status_is_ready(&dls_failure,
+ current_time + delay0, 1),
+ OP_EQ, 1);
+ tt_int_op(download_status_is_ready(&dls_failure,
+ current_time + delay0 + 1, 1),
+ OP_EQ, 1);
/* Check that a failure increment works */
mock_get_options_calls = 0;
next_at = download_status_increment_failure(&dls_failure, 404, "test", 0,
current_time);
tt_assert(next_at == current_time + delay1);
- tt_assert(download_status_get_n_failures(&dls_failure) == 1);
- tt_assert(download_status_get_n_attempts(&dls_failure) == 1);
- tt_assert(mock_get_options_calls >= 1);
+ tt_int_op(download_status_get_n_failures(&dls_failure), OP_EQ, 1);
+ tt_int_op(download_status_get_n_attempts(&dls_failure), OP_EQ, 1);
+ tt_int_op(mock_get_options_calls, OP_GE, 1);
/* check that an incremented schedule becomes ready at the right time */
- tt_assert(download_status_is_ready(&dls_failure,
- current_time + delay1 - 1,
- 1) == 0);
- tt_assert(download_status_is_ready(&dls_failure,
- current_time + delay1,
- 1) == 1);
- tt_assert(download_status_is_ready(&dls_failure,
- current_time + delay1 + 1,
- 1) == 1);
+ tt_int_op(download_status_is_ready(&dls_failure,
+ current_time + delay1 - 1, 1),
+ OP_EQ, 0);
+ tt_int_op(download_status_is_ready(&dls_failure,
+ current_time + delay1, 1),
+ OP_EQ, 1);
+ tt_int_op(download_status_is_ready(&dls_failure,
+ current_time + delay1 + 1, 1),
+ OP_EQ, 1);
/* check that a schedule isn't ready if it's had too many failures */
- tt_assert(download_status_is_ready(&dls_failure,
- current_time + delay1 + 10,
- 0) == 0);
+ tt_int_op(download_status_is_ready(&dls_failure,
+ current_time + delay1 + 10, 0),
+ OP_EQ, 0);
/* Check that failure increments do happen on 503 for clients, and
* attempt increments do too. */
mock_get_options_calls = 0;
next_at = download_status_increment_failure(&dls_failure, 503, "test", 0,
current_time);
- tt_i64_op(next_at, ==, current_time + delay2);
- tt_int_op(download_status_get_n_failures(&dls_failure), ==, 2);
- tt_int_op(download_status_get_n_attempts(&dls_failure), ==, 2);
- tt_assert(mock_get_options_calls >= 1);
+ tt_i64_op(next_at, OP_EQ, current_time + delay2);
+ tt_int_op(download_status_get_n_failures(&dls_failure), OP_EQ, 2);
+ tt_int_op(download_status_get_n_attempts(&dls_failure), OP_EQ, 2);
+ tt_int_op(mock_get_options_calls, OP_GE, 1);
/* Check that failure increments do happen on 503 for servers */
mock_get_options_calls = 0;
next_at = download_status_increment_failure(&dls_failure, 503, "test", 1,
current_time);
tt_assert(next_at == current_time + delay2);
- tt_assert(download_status_get_n_failures(&dls_failure) == 3);
- tt_assert(download_status_get_n_attempts(&dls_failure) == 3);
- tt_assert(mock_get_options_calls >= 1);
+ tt_int_op(download_status_get_n_failures(&dls_failure), OP_EQ, 3);
+ tt_int_op(download_status_get_n_attempts(&dls_failure), OP_EQ, 3);
+ tt_int_op(mock_get_options_calls, OP_GE, 1);
/* Check what happens when we run off the end of the schedule */
mock_get_options_calls = 0;
next_at = download_status_increment_failure(&dls_failure, 404, "test", 0,
current_time);
tt_assert(next_at == current_time + delay2);
- tt_assert(download_status_get_n_failures(&dls_failure) == 4);
- tt_assert(download_status_get_n_attempts(&dls_failure) == 4);
- tt_assert(mock_get_options_calls >= 1);
+ tt_int_op(download_status_get_n_failures(&dls_failure), OP_EQ, 4);
+ tt_int_op(download_status_get_n_attempts(&dls_failure), OP_EQ, 4);
+ tt_int_op(mock_get_options_calls, OP_GE, 1);
/* Check what happens when we hit the failure limit */
mock_get_options_calls = 0;
@@ -3785,22 +4424,22 @@ test_dir_download_status_increment(void *arg)
next_at = download_status_increment_failure(&dls_failure, 404, "test", 0,
current_time);
tt_assert(next_at == TIME_MAX);
- tt_assert(download_status_get_n_failures(&dls_failure)
- == IMPOSSIBLE_TO_DOWNLOAD);
- tt_assert(download_status_get_n_attempts(&dls_failure)
- == IMPOSSIBLE_TO_DOWNLOAD);
- tt_assert(mock_get_options_calls >= 1);
+ tt_int_op(download_status_get_n_failures(&dls_failure), OP_EQ,
+ IMPOSSIBLE_TO_DOWNLOAD);
+ tt_int_op(download_status_get_n_attempts(&dls_failure), OP_EQ,
+ IMPOSSIBLE_TO_DOWNLOAD);
+ tt_int_op(mock_get_options_calls, OP_GE, 1);
/* Check that a failure reset doesn't reset at the limit */
mock_get_options_calls = 0;
download_status_reset(&dls_failure);
tt_assert(download_status_get_next_attempt_at(&dls_failure)
== TIME_MAX);
- tt_assert(download_status_get_n_failures(&dls_failure)
- == IMPOSSIBLE_TO_DOWNLOAD);
- tt_assert(download_status_get_n_attempts(&dls_failure)
- == IMPOSSIBLE_TO_DOWNLOAD);
- tt_assert(mock_get_options_calls == 0);
+ tt_int_op(download_status_get_n_failures(&dls_failure), OP_EQ,
+ IMPOSSIBLE_TO_DOWNLOAD);
+ tt_int_op(download_status_get_n_attempts(&dls_failure), OP_EQ,
+ IMPOSSIBLE_TO_DOWNLOAD);
+ tt_int_op(mock_get_options_calls, OP_EQ, 0);
/* Check that a failure reset resets just before the limit */
mock_get_options_calls = 0;
@@ -3813,19 +4452,20 @@ test_dir_download_status_increment(void *arg)
>= current_time + delay0);
tt_assert(download_status_get_next_attempt_at(&dls_failure)
!= TIME_MAX);
- tt_assert(download_status_get_n_failures(&dls_failure) == 0);
- tt_assert(download_status_get_n_attempts(&dls_failure) == 0);
- tt_assert(mock_get_options_calls >= 1);
+ tt_int_op(download_status_get_n_failures(&dls_failure), OP_EQ, 0);
+ tt_int_op(download_status_get_n_attempts(&dls_failure), OP_EQ, 0);
+ tt_int_op(mock_get_options_calls, OP_GE, 1);
/* Check that failure increments do happen on attempt-based schedules,
* but that the retry is set at the end of time */
+ mock_options->UseBridges = 1;
mock_get_options_calls = 0;
next_at = download_status_increment_failure(&dls_attempt, 404, "test", 0,
current_time);
tt_assert(next_at == TIME_MAX);
- tt_assert(download_status_get_n_failures(&dls_attempt) == 1);
- tt_assert(download_status_get_n_attempts(&dls_attempt) == 0);
- tt_assert(mock_get_options_calls == 0);
+ tt_int_op(download_status_get_n_failures(&dls_attempt), OP_EQ, 1);
+ tt_int_op(download_status_get_n_attempts(&dls_attempt), OP_EQ, 0);
+ tt_int_op(mock_get_options_calls, OP_GE, 1);
/* Check that an attempt reset works */
mock_get_options_calls = 0;
@@ -3836,65 +4476,65 @@ test_dir_download_status_increment(void *arg)
>= current_time + delay0);
tt_assert(download_status_get_next_attempt_at(&dls_attempt)
!= TIME_MAX);
- tt_assert(download_status_get_n_failures(&dls_attempt) == 0);
- tt_assert(download_status_get_n_attempts(&dls_attempt) == 0);
- tt_assert(mock_get_options_calls >= 1);
+ tt_int_op(download_status_get_n_failures(&dls_attempt), OP_EQ, 0);
+ tt_int_op(download_status_get_n_attempts(&dls_attempt), OP_EQ, 0);
+ tt_int_op(mock_get_options_calls, OP_GE, 1);
/* avoid timing inconsistencies */
dls_attempt.next_attempt_at = current_time + delay0;
/* check that a reset schedule becomes ready at the right time */
- tt_assert(download_status_is_ready(&dls_attempt,
- current_time + delay0 - 1,
- 1) == 0);
- tt_assert(download_status_is_ready(&dls_attempt,
- current_time + delay0,
- 1) == 1);
- tt_assert(download_status_is_ready(&dls_attempt,
- current_time + delay0 + 1,
- 1) == 1);
+ tt_int_op(download_status_is_ready(&dls_attempt,
+ current_time + delay0 - 1, 1),
+ OP_EQ, 0);
+ tt_int_op(download_status_is_ready(&dls_attempt,
+ current_time + delay0, 1),
+ OP_EQ, 1);
+ tt_int_op(download_status_is_ready(&dls_attempt,
+ current_time + delay0 + 1, 1),
+ OP_EQ, 1);
/* Check that an attempt increment works */
mock_get_options_calls = 0;
next_at = download_status_increment_attempt(&dls_attempt, "test",
current_time);
tt_assert(next_at == current_time + delay1);
- tt_assert(download_status_get_n_failures(&dls_attempt) == 0);
- tt_assert(download_status_get_n_attempts(&dls_attempt) == 1);
- tt_assert(mock_get_options_calls >= 1);
+ tt_int_op(download_status_get_n_failures(&dls_attempt), OP_EQ, 0);
+ tt_int_op(download_status_get_n_attempts(&dls_attempt), OP_EQ, 1);
+ tt_int_op(mock_get_options_calls, OP_GE, 1);
/* check that an incremented schedule becomes ready at the right time */
- tt_assert(download_status_is_ready(&dls_attempt,
- current_time + delay1 - 1,
- 1) == 0);
- tt_assert(download_status_is_ready(&dls_attempt,
- current_time + delay1,
- 1) == 1);
- tt_assert(download_status_is_ready(&dls_attempt,
- current_time + delay1 + 1,
- 1) == 1);
+ tt_int_op(download_status_is_ready(&dls_attempt,
+ current_time + delay1 - 1, 1),
+ OP_EQ, 0);
+ tt_int_op(download_status_is_ready(&dls_attempt,
+ current_time + delay1, 1),
+ OP_EQ, 1);
+ tt_int_op(download_status_is_ready(&dls_attempt,
+ current_time + delay1 + 1, 1),
+ OP_EQ, 1);
/* check that a schedule isn't ready if it's had too many attempts */
- tt_assert(download_status_is_ready(&dls_attempt,
- current_time + delay1 + 10,
- 0) == 0);
+ tt_int_op(download_status_is_ready(&dls_attempt,
+ current_time + delay1 + 10, 0),
+ OP_EQ, 0);
/* Check what happens when we reach then run off the end of the schedule */
mock_get_options_calls = 0;
next_at = download_status_increment_attempt(&dls_attempt, "test",
current_time);
tt_assert(next_at == current_time + delay2);
- tt_assert(download_status_get_n_failures(&dls_attempt) == 0);
- tt_assert(download_status_get_n_attempts(&dls_attempt) == 2);
- tt_assert(mock_get_options_calls >= 1);
+ tt_int_op(download_status_get_n_failures(&dls_attempt), OP_EQ, 0);
+ tt_int_op(download_status_get_n_attempts(&dls_attempt), OP_EQ, 2);
+ tt_int_op(mock_get_options_calls, OP_GE, 1);
mock_get_options_calls = 0;
next_at = download_status_increment_attempt(&dls_attempt, "test",
current_time);
tt_assert(next_at == current_time + delay2);
- tt_assert(download_status_get_n_failures(&dls_attempt) == 0);
- tt_assert(download_status_get_n_attempts(&dls_attempt) == 3);
- tt_assert(mock_get_options_calls >= 1);
+ tt_int_op(download_status_get_n_failures(&dls_attempt), OP_EQ, 0);
+ tt_int_op(download_status_get_n_attempts(&dls_attempt), OP_EQ, 3);
+ tt_int_op(mock_get_options_calls, OP_GE, 1);
/* Check what happens when we hit the attempt limit */
mock_get_options_calls = 0;
@@ -3902,22 +4542,22 @@ test_dir_download_status_increment(void *arg)
next_at = download_status_increment_attempt(&dls_attempt, "test",
current_time);
tt_assert(next_at == TIME_MAX);
- tt_assert(download_status_get_n_failures(&dls_attempt)
- == IMPOSSIBLE_TO_DOWNLOAD);
- tt_assert(download_status_get_n_attempts(&dls_attempt)
- == IMPOSSIBLE_TO_DOWNLOAD);
- tt_assert(mock_get_options_calls >= 1);
+ tt_int_op(download_status_get_n_failures(&dls_attempt), OP_EQ,
+ IMPOSSIBLE_TO_DOWNLOAD);
+ tt_int_op(download_status_get_n_attempts(&dls_attempt), OP_EQ,
+ IMPOSSIBLE_TO_DOWNLOAD);
+ tt_int_op(mock_get_options_calls, OP_GE, 1);
/* Check that an attempt reset doesn't reset at the limit */
mock_get_options_calls = 0;
download_status_reset(&dls_attempt);
tt_assert(download_status_get_next_attempt_at(&dls_attempt)
== TIME_MAX);
- tt_assert(download_status_get_n_failures(&dls_attempt)
- == IMPOSSIBLE_TO_DOWNLOAD);
- tt_assert(download_status_get_n_attempts(&dls_attempt)
- == IMPOSSIBLE_TO_DOWNLOAD);
- tt_assert(mock_get_options_calls == 0);
+ tt_int_op(download_status_get_n_failures(&dls_attempt), OP_EQ,
+ IMPOSSIBLE_TO_DOWNLOAD);
+ tt_int_op(download_status_get_n_attempts(&dls_attempt), OP_EQ,
+ IMPOSSIBLE_TO_DOWNLOAD);
+ tt_int_op(mock_get_options_calls, OP_EQ, 0);
/* Check that an attempt reset resets just before the limit */
mock_get_options_calls = 0;
@@ -3930,9 +4570,10 @@ test_dir_download_status_increment(void *arg)
>= current_time + delay0);
tt_assert(download_status_get_next_attempt_at(&dls_attempt)
!= TIME_MAX);
- tt_assert(download_status_get_n_failures(&dls_attempt) == 0);
- tt_assert(download_status_get_n_attempts(&dls_attempt) == 0);
- tt_assert(mock_get_options_calls >= 1);
+ tt_int_op(download_status_get_n_failures(&dls_attempt), OP_EQ, 0);
+ tt_int_op(download_status_get_n_attempts(&dls_attempt), OP_EQ, 0);
+ tt_int_op(mock_get_options_calls, OP_GE, 1);
+ mock_options->UseBridges = 0;
/* Check that attempt increments don't happen on failure-based schedules,
* and that the attempt is set at the end of time */
@@ -3945,13 +4586,14 @@ test_dir_download_status_increment(void *arg)
"schedule.");
teardown_capture_of_logs();
tt_assert(next_at == TIME_MAX);
- tt_assert(download_status_get_n_failures(&dls_failure) == 0);
- tt_assert(download_status_get_n_attempts(&dls_failure) == 0);
- tt_assert(mock_get_options_calls == 0);
+ tt_int_op(download_status_get_n_failures(&dls_failure), OP_EQ, 0);
+ tt_int_op(download_status_get_n_attempts(&dls_failure), OP_EQ, 0);
+ tt_int_op(mock_get_options_calls, OP_EQ, 0);
done:
/* the pointers in schedule are allocated on the stack */
smartlist_free(schedule);
+ smartlist_free(schedule_no_initial_delay);
UNMOCK(get_options);
mock_options = NULL;
mock_get_options_calls = 0;
@@ -4054,7 +4696,6 @@ test_dir_should_use_directory_guards(void *data)
tt_int_op(should_use_directory_guards(options), OP_EQ, 0);
tt_int_op(CALLED(public_server_mode), OP_EQ, 1);
- options->UseEntryGuardsAsDirGuards = 1;
options->UseEntryGuards = 1;
options->DownloadExtraInfo = 0;
options->FetchDirInfoEarly = 0;
@@ -4068,29 +4709,24 @@ test_dir_should_use_directory_guards(void *data)
tt_int_op(CALLED(public_server_mode), OP_EQ, 3);
options->UseEntryGuards = 1;
- options->UseEntryGuardsAsDirGuards = 0;
- tt_int_op(should_use_directory_guards(options), OP_EQ, 0);
- tt_int_op(CALLED(public_server_mode), OP_EQ, 4);
- options->UseEntryGuardsAsDirGuards = 1;
-
options->DownloadExtraInfo = 1;
tt_int_op(should_use_directory_guards(options), OP_EQ, 0);
- tt_int_op(CALLED(public_server_mode), OP_EQ, 5);
+ tt_int_op(CALLED(public_server_mode), OP_EQ, 4);
options->DownloadExtraInfo = 0;
options->FetchDirInfoEarly = 1;
tt_int_op(should_use_directory_guards(options), OP_EQ, 0);
- tt_int_op(CALLED(public_server_mode), OP_EQ, 6);
+ tt_int_op(CALLED(public_server_mode), OP_EQ, 5);
options->FetchDirInfoEarly = 0;
options->FetchDirInfoExtraEarly = 1;
tt_int_op(should_use_directory_guards(options), OP_EQ, 0);
- tt_int_op(CALLED(public_server_mode), OP_EQ, 7);
+ tt_int_op(CALLED(public_server_mode), OP_EQ, 6);
options->FetchDirInfoExtraEarly = 0;
options->FetchUselessDescriptors = 1;
tt_int_op(should_use_directory_guards(options), OP_EQ, 0);
- tt_int_op(CALLED(public_server_mode), OP_EQ, 8);
+ tt_int_op(CALLED(public_server_mode), OP_EQ, 7);
options->FetchUselessDescriptors = 0;
done:
@@ -4100,14 +4736,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));
+directory_initiate_request, (directory_request_t *req));
static void
test_dir_should_not_init_request_to_ourselves(void *data)
@@ -4117,7 +4746,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();
@@ -4132,15 +4761,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);
@@ -4154,7 +4783,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();
@@ -4165,14 +4794,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();
}
@@ -4183,7 +4812,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();
@@ -4194,37 +4823,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)
+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;
- CALLED(directory_initiate_command_routerstatus)++;
+ (void)req;
+ CALLED(directory_initiate_request)++;
}
static void
@@ -4287,13 +4902,13 @@ mock_get_datadir_fname(const or_options_t *options,
* Assert we were called like get_datadir_fname2() or get_datadir_fname(),
* since that's all we implement here.
*/
- tt_assert(options != NULL);
- tt_assert(sub1 != NULL);
+ tt_ptr_op(options, OP_NE, NULL);
+ tt_ptr_op(sub1, OP_NE, NULL);
/*
* No particular assertions about sub2, since we could be in the
* get_datadir_fname() or get_datadir_fname2() case.
*/
- tt_assert(suffix == NULL);
+ tt_ptr_op(suffix, OP_EQ, NULL);
/* Just duplicate the basename and return it for this mock */
if (sub2) {
@@ -4320,7 +4935,7 @@ mock_unlink_reset(void)
static int
mock_unlink(const char *path)
{
- tt_assert(path != NULL);
+ tt_ptr_op(path, OP_NE, NULL);
tor_free(last_unlinked_path);
last_unlinked_path = tor_strdup(path);
@@ -4349,8 +4964,8 @@ mock_write_str_to_file(const char *path, const char *str, int bin)
(void)bin;
- tt_assert(path != NULL);
- tt_assert(str != NULL);
+ tt_ptr_op(path, OP_NE, NULL);
+ tt_ptr_op(str, OP_NE, NULL);
len = strlen(str);
crypto_digest256((char *)hash, str, len, DIGEST_SHA256);
@@ -4476,7 +5091,7 @@ test_dir_dump_unparseable_descriptors(void *data)
* Reset the FIFO and check its state
*/
dump_desc_fifo_cleanup();
- tt_u64_op(len_descs_dumped, ==, 0);
+ tt_u64_op(len_descs_dumped, OP_EQ, 0);
tt_assert(descs_dumped == NULL || smartlist_len(descs_dumped) == 0);
/*
@@ -4489,21 +5104,21 @@ test_dir_dump_unparseable_descriptors(void *data)
/*
* Assert things about the FIFO state
*/
- tt_u64_op(len_descs_dumped, ==, strlen(test_desc_1));
+ tt_u64_op(len_descs_dumped, OP_EQ, strlen(test_desc_1));
tt_assert(descs_dumped != NULL && smartlist_len(descs_dumped) == 1);
/*
* Assert things about the mocks
*/
- tt_int_op(unlinked_count, ==, 0);
- tt_int_op(write_str_count, ==, 1);
+ tt_int_op(unlinked_count, OP_EQ, 0);
+ tt_int_op(write_str_count, OP_EQ, 1);
tt_mem_op(last_write_str_hash, OP_EQ, test_desc_1_hash, DIGEST_SHA256);
/*
* Reset the FIFO and check its state
*/
dump_desc_fifo_cleanup();
- tt_u64_op(len_descs_dumped, ==, 0);
+ tt_u64_op(len_descs_dumped, OP_EQ, 0);
tt_assert(descs_dumped == NULL || smartlist_len(descs_dumped) == 0);
/*
@@ -4511,8 +5126,8 @@ test_dir_dump_unparseable_descriptors(void *data)
*/
mock_unlink_reset();
mock_write_str_to_file_reset();
- tt_int_op(unlinked_count, ==, 0);
- tt_int_op(write_str_count, ==, 0);
+ tt_int_op(unlinked_count, OP_EQ, 0);
+ tt_int_op(write_str_count, OP_EQ, 0);
/*
* (2) Fire off dump_desc() twice; this still should trigger no cleanup.
@@ -4524,14 +5139,14 @@ test_dir_dump_unparseable_descriptors(void *data)
/*
* Assert things about the FIFO state
*/
- tt_u64_op(len_descs_dumped, ==, strlen(test_desc_2));
+ tt_u64_op(len_descs_dumped, OP_EQ, strlen(test_desc_2));
tt_assert(descs_dumped != NULL && smartlist_len(descs_dumped) == 1);
/*
* Assert things about the mocks
*/
- tt_int_op(unlinked_count, ==, 0);
- tt_int_op(write_str_count, ==, 1);
+ tt_int_op(unlinked_count, OP_EQ, 0);
+ tt_int_op(write_str_count, OP_EQ, 1);
tt_mem_op(last_write_str_hash, OP_EQ, test_desc_2_hash, DIGEST_SHA256);
/* Second time */
@@ -4540,21 +5155,22 @@ test_dir_dump_unparseable_descriptors(void *data)
/*
* Assert things about the FIFO state
*/
- tt_u64_op(len_descs_dumped, ==, strlen(test_desc_2) + strlen(test_desc_3));
+ tt_u64_op(len_descs_dumped, OP_EQ,
+ strlen(test_desc_2) + strlen(test_desc_3));
tt_assert(descs_dumped != NULL && smartlist_len(descs_dumped) == 2);
/*
* Assert things about the mocks
*/
- tt_int_op(unlinked_count, ==, 0);
- tt_int_op(write_str_count, ==, 2);
+ tt_int_op(unlinked_count, OP_EQ, 0);
+ tt_int_op(write_str_count, OP_EQ, 2);
tt_mem_op(last_write_str_hash, OP_EQ, test_desc_3_hash, DIGEST_SHA256);
/*
* Reset the FIFO and check its state
*/
dump_desc_fifo_cleanup();
- tt_u64_op(len_descs_dumped, ==, 0);
+ tt_u64_op(len_descs_dumped, OP_EQ, 0);
tt_assert(descs_dumped == NULL || smartlist_len(descs_dumped) == 0);
/*
@@ -4562,8 +5178,8 @@ test_dir_dump_unparseable_descriptors(void *data)
*/
mock_unlink_reset();
mock_write_str_to_file_reset();
- tt_int_op(unlinked_count, ==, 0);
- tt_int_op(write_str_count, ==, 0);
+ tt_int_op(unlinked_count, OP_EQ, 0);
+ tt_int_op(write_str_count, OP_EQ, 0);
/*
* (3) Three calls to dump_desc cause a FIFO cleanup
@@ -4575,14 +5191,14 @@ test_dir_dump_unparseable_descriptors(void *data)
/*
* Assert things about the FIFO state
*/
- tt_u64_op(len_descs_dumped, ==, strlen(test_desc_4));
+ tt_u64_op(len_descs_dumped, OP_EQ, strlen(test_desc_4));
tt_assert(descs_dumped != NULL && smartlist_len(descs_dumped) == 1);
/*
* Assert things about the mocks
*/
- tt_int_op(unlinked_count, ==, 0);
- tt_int_op(write_str_count, ==, 1);
+ tt_int_op(unlinked_count, OP_EQ, 0);
+ tt_int_op(write_str_count, OP_EQ, 1);
tt_mem_op(last_write_str_hash, OP_EQ, test_desc_4_hash, DIGEST_SHA256);
/* Second time */
@@ -4591,14 +5207,15 @@ test_dir_dump_unparseable_descriptors(void *data)
/*
* Assert things about the FIFO state
*/
- tt_u64_op(len_descs_dumped, ==, strlen(test_desc_4) + strlen(test_desc_1));
+ tt_u64_op(len_descs_dumped, OP_EQ,
+ strlen(test_desc_4) + strlen(test_desc_1));
tt_assert(descs_dumped != NULL && smartlist_len(descs_dumped) == 2);
/*
* Assert things about the mocks
*/
- tt_int_op(unlinked_count, ==, 0);
- tt_int_op(write_str_count, ==, 2);
+ tt_int_op(unlinked_count, OP_EQ, 0);
+ tt_int_op(write_str_count, OP_EQ, 2);
tt_mem_op(last_write_str_hash, OP_EQ, test_desc_1_hash, DIGEST_SHA256);
/* Third time - we should unlink the dump of test_desc_4 here */
@@ -4607,21 +5224,22 @@ test_dir_dump_unparseable_descriptors(void *data)
/*
* Assert things about the FIFO state
*/
- tt_u64_op(len_descs_dumped, ==, strlen(test_desc_1) + strlen(test_desc_2));
+ tt_u64_op(len_descs_dumped, OP_EQ,
+ strlen(test_desc_1) + strlen(test_desc_2));
tt_assert(descs_dumped != NULL && smartlist_len(descs_dumped) == 2);
/*
* Assert things about the mocks
*/
- tt_int_op(unlinked_count, ==, 1);
- tt_int_op(write_str_count, ==, 3);
+ tt_int_op(unlinked_count, OP_EQ, 1);
+ tt_int_op(write_str_count, OP_EQ, 3);
tt_mem_op(last_write_str_hash, OP_EQ, test_desc_2_hash, DIGEST_SHA256);
/*
* Reset the FIFO and check its state
*/
dump_desc_fifo_cleanup();
- tt_u64_op(len_descs_dumped, ==, 0);
+ tt_u64_op(len_descs_dumped, OP_EQ, 0);
tt_assert(descs_dumped == NULL || smartlist_len(descs_dumped) == 0);
/*
@@ -4629,8 +5247,8 @@ test_dir_dump_unparseable_descriptors(void *data)
*/
mock_unlink_reset();
mock_write_str_to_file_reset();
- tt_int_op(unlinked_count, ==, 0);
- tt_int_op(write_str_count, ==, 0);
+ tt_int_op(unlinked_count, OP_EQ, 0);
+ tt_int_op(write_str_count, OP_EQ, 0);
/*
* (4) But repeating one (A B B) doesn't overflow and cleanup
@@ -4642,14 +5260,14 @@ test_dir_dump_unparseable_descriptors(void *data)
/*
* Assert things about the FIFO state
*/
- tt_u64_op(len_descs_dumped, ==, strlen(test_desc_3));
+ tt_u64_op(len_descs_dumped, OP_EQ, strlen(test_desc_3));
tt_assert(descs_dumped != NULL && smartlist_len(descs_dumped) == 1);
/*
* Assert things about the mocks
*/
- tt_int_op(unlinked_count, ==, 0);
- tt_int_op(write_str_count, ==, 1);
+ tt_int_op(unlinked_count, OP_EQ, 0);
+ tt_int_op(write_str_count, OP_EQ, 1);
tt_mem_op(last_write_str_hash, OP_EQ, test_desc_3_hash, DIGEST_SHA256);
/* Second time */
@@ -4658,14 +5276,15 @@ test_dir_dump_unparseable_descriptors(void *data)
/*
* Assert things about the FIFO state
*/
- tt_u64_op(len_descs_dumped, ==, strlen(test_desc_3) + strlen(test_desc_4));
+ tt_u64_op(len_descs_dumped, OP_EQ,
+ strlen(test_desc_3) + strlen(test_desc_4));
tt_assert(descs_dumped != NULL && smartlist_len(descs_dumped) == 2);
/*
* Assert things about the mocks
*/
- tt_int_op(unlinked_count, ==, 0);
- tt_int_op(write_str_count, ==, 2);
+ tt_int_op(unlinked_count, OP_EQ, 0);
+ tt_int_op(write_str_count, OP_EQ, 2);
tt_mem_op(last_write_str_hash, OP_EQ, test_desc_4_hash, DIGEST_SHA256);
/* Third time */
@@ -4674,21 +5293,22 @@ test_dir_dump_unparseable_descriptors(void *data)
/*
* Assert things about the FIFO state
*/
- tt_u64_op(len_descs_dumped, ==, strlen(test_desc_3) + strlen(test_desc_4));
+ tt_u64_op(len_descs_dumped, OP_EQ,
+ strlen(test_desc_3) + strlen(test_desc_4));
tt_assert(descs_dumped != NULL && smartlist_len(descs_dumped) == 2);
/*
* Assert things about the mocks
*/
- tt_int_op(unlinked_count, ==, 0);
- tt_int_op(write_str_count, ==, 2);
+ tt_int_op(unlinked_count, OP_EQ, 0);
+ tt_int_op(write_str_count, OP_EQ, 2);
tt_mem_op(last_write_str_hash, OP_EQ, test_desc_4_hash, DIGEST_SHA256);
/*
* Reset the FIFO and check its state
*/
dump_desc_fifo_cleanup();
- tt_u64_op(len_descs_dumped, ==, 0);
+ tt_u64_op(len_descs_dumped, OP_EQ, 0);
tt_assert(descs_dumped == NULL || smartlist_len(descs_dumped) == 0);
/*
@@ -4696,8 +5316,8 @@ test_dir_dump_unparseable_descriptors(void *data)
*/
mock_unlink_reset();
mock_write_str_to_file_reset();
- tt_int_op(unlinked_count, ==, 0);
- tt_int_op(write_str_count, ==, 0);
+ tt_int_op(unlinked_count, OP_EQ, 0);
+ tt_int_op(write_str_count, OP_EQ, 0);
/*
* (5) Same for the (A B A) repetition
@@ -4709,14 +5329,14 @@ test_dir_dump_unparseable_descriptors(void *data)
/*
* Assert things about the FIFO state
*/
- tt_u64_op(len_descs_dumped, ==, strlen(test_desc_1));
+ tt_u64_op(len_descs_dumped, OP_EQ, strlen(test_desc_1));
tt_assert(descs_dumped != NULL && smartlist_len(descs_dumped) == 1);
/*
* Assert things about the mocks
*/
- tt_int_op(unlinked_count, ==, 0);
- tt_int_op(write_str_count, ==, 1);
+ tt_int_op(unlinked_count, OP_EQ, 0);
+ tt_int_op(write_str_count, OP_EQ, 1);
tt_mem_op(last_write_str_hash, OP_EQ, test_desc_1_hash, DIGEST_SHA256);
/* Second time */
@@ -4725,14 +5345,15 @@ test_dir_dump_unparseable_descriptors(void *data)
/*
* Assert things about the FIFO state
*/
- tt_u64_op(len_descs_dumped, ==, strlen(test_desc_1) + strlen(test_desc_2));
+ tt_u64_op(len_descs_dumped, OP_EQ,
+ strlen(test_desc_1) + strlen(test_desc_2));
tt_assert(descs_dumped != NULL && smartlist_len(descs_dumped) == 2);
/*
* Assert things about the mocks
*/
- tt_int_op(unlinked_count, ==, 0);
- tt_int_op(write_str_count, ==, 2);
+ tt_int_op(unlinked_count, OP_EQ, 0);
+ tt_int_op(write_str_count, OP_EQ, 2);
tt_mem_op(last_write_str_hash, OP_EQ, test_desc_2_hash, DIGEST_SHA256);
/* Third time */
@@ -4741,21 +5362,22 @@ test_dir_dump_unparseable_descriptors(void *data)
/*
* Assert things about the FIFO state
*/
- tt_u64_op(len_descs_dumped, ==, strlen(test_desc_1) + strlen(test_desc_2));
+ tt_u64_op(len_descs_dumped, OP_EQ,
+ strlen(test_desc_1) + strlen(test_desc_2));
tt_assert(descs_dumped != NULL && smartlist_len(descs_dumped) == 2);
/*
* Assert things about the mocks
*/
- tt_int_op(unlinked_count, ==, 0);
- tt_int_op(write_str_count, ==, 2);
+ tt_int_op(unlinked_count, OP_EQ, 0);
+ tt_int_op(write_str_count, OP_EQ, 2);
tt_mem_op(last_write_str_hash, OP_EQ, test_desc_2_hash, DIGEST_SHA256);
/*
* Reset the FIFO and check its state
*/
dump_desc_fifo_cleanup();
- tt_u64_op(len_descs_dumped, ==, 0);
+ tt_u64_op(len_descs_dumped, OP_EQ, 0);
tt_assert(descs_dumped == NULL || smartlist_len(descs_dumped) == 0);
/*
@@ -4763,8 +5385,8 @@ test_dir_dump_unparseable_descriptors(void *data)
*/
mock_unlink_reset();
mock_write_str_to_file_reset();
- tt_int_op(unlinked_count, ==, 0);
- tt_int_op(write_str_count, ==, 0);
+ tt_int_op(unlinked_count, OP_EQ, 0);
+ tt_int_op(write_str_count, OP_EQ, 0);
/*
* (6) (A B B C) triggering overflow on C causes A, not B to be unlinked
@@ -4776,14 +5398,14 @@ test_dir_dump_unparseable_descriptors(void *data)
/*
* Assert things about the FIFO state
*/
- tt_u64_op(len_descs_dumped, ==, strlen(test_desc_3));
+ tt_u64_op(len_descs_dumped, OP_EQ, strlen(test_desc_3));
tt_assert(descs_dumped != NULL && smartlist_len(descs_dumped) == 1);
/*
* Assert things about the mocks
*/
- tt_int_op(unlinked_count, ==, 0);
- tt_int_op(write_str_count, ==, 1);
+ tt_int_op(unlinked_count, OP_EQ, 0);
+ tt_int_op(write_str_count, OP_EQ, 1);
tt_mem_op(last_write_str_hash, OP_EQ, test_desc_3_hash, DIGEST_SHA256);
/* Second time */
@@ -4792,14 +5414,15 @@ test_dir_dump_unparseable_descriptors(void *data)
/*
* Assert things about the FIFO state
*/
- tt_u64_op(len_descs_dumped, ==, strlen(test_desc_3) + strlen(test_desc_4));
+ tt_u64_op(len_descs_dumped, OP_EQ,
+ strlen(test_desc_3) + strlen(test_desc_4));
tt_assert(descs_dumped != NULL && smartlist_len(descs_dumped) == 2);
/*
* Assert things about the mocks
*/
- tt_int_op(unlinked_count, ==, 0);
- tt_int_op(write_str_count, ==, 2);
+ tt_int_op(unlinked_count, OP_EQ, 0);
+ tt_int_op(write_str_count, OP_EQ, 2);
tt_mem_op(last_write_str_hash, OP_EQ, test_desc_4_hash, DIGEST_SHA256);
/* Third time */
@@ -4808,14 +5431,15 @@ test_dir_dump_unparseable_descriptors(void *data)
/*
* Assert things about the FIFO state
*/
- tt_u64_op(len_descs_dumped, ==, strlen(test_desc_3) + strlen(test_desc_4));
+ tt_u64_op(len_descs_dumped, OP_EQ,
+ strlen(test_desc_3) + strlen(test_desc_4));
tt_assert(descs_dumped != NULL && smartlist_len(descs_dumped) == 2);
/*
* Assert things about the mocks
*/
- tt_int_op(unlinked_count, ==, 0);
- tt_int_op(write_str_count, ==, 2);
+ tt_int_op(unlinked_count, OP_EQ, 0);
+ tt_int_op(write_str_count, OP_EQ, 2);
tt_mem_op(last_write_str_hash, OP_EQ, test_desc_4_hash, DIGEST_SHA256);
/* Fourth time - we should unlink the dump of test_desc_3 here */
@@ -4824,21 +5448,22 @@ test_dir_dump_unparseable_descriptors(void *data)
/*
* Assert things about the FIFO state
*/
- tt_u64_op(len_descs_dumped, ==, strlen(test_desc_4) + strlen(test_desc_1));
+ tt_u64_op(len_descs_dumped, OP_EQ,
+ strlen(test_desc_4) + strlen(test_desc_1));
tt_assert(descs_dumped != NULL && smartlist_len(descs_dumped) == 2);
/*
* Assert things about the mocks
*/
- tt_int_op(unlinked_count, ==, 1);
- tt_int_op(write_str_count, ==, 3);
+ tt_int_op(unlinked_count, OP_EQ, 1);
+ tt_int_op(write_str_count, OP_EQ, 3);
tt_mem_op(last_write_str_hash, OP_EQ, test_desc_1_hash, DIGEST_SHA256);
/*
* Reset the FIFO and check its state
*/
dump_desc_fifo_cleanup();
- tt_u64_op(len_descs_dumped, ==, 0);
+ tt_u64_op(len_descs_dumped, OP_EQ, 0);
tt_assert(descs_dumped == NULL || smartlist_len(descs_dumped) == 0);
/*
@@ -4846,8 +5471,8 @@ test_dir_dump_unparseable_descriptors(void *data)
*/
mock_unlink_reset();
mock_write_str_to_file_reset();
- tt_int_op(unlinked_count, ==, 0);
- tt_int_op(write_str_count, ==, 0);
+ tt_int_op(unlinked_count, OP_EQ, 0);
+ tt_int_op(write_str_count, OP_EQ, 0);
/*
* (7) (A B A C) triggering overflow on C causes B, not A to be unlinked
@@ -4859,14 +5484,14 @@ test_dir_dump_unparseable_descriptors(void *data)
/*
* Assert things about the FIFO state
*/
- tt_u64_op(len_descs_dumped, ==, strlen(test_desc_2));
+ tt_u64_op(len_descs_dumped, OP_EQ, strlen(test_desc_2));
tt_assert(descs_dumped != NULL && smartlist_len(descs_dumped) == 1);
/*
* Assert things about the mocks
*/
- tt_int_op(unlinked_count, ==, 0);
- tt_int_op(write_str_count, ==, 1);
+ tt_int_op(unlinked_count, OP_EQ, 0);
+ tt_int_op(write_str_count, OP_EQ, 1);
tt_mem_op(last_write_str_hash, OP_EQ, test_desc_2_hash, DIGEST_SHA256);
/* Second time */
@@ -4875,14 +5500,15 @@ test_dir_dump_unparseable_descriptors(void *data)
/*
* Assert things about the FIFO state
*/
- tt_u64_op(len_descs_dumped, ==, strlen(test_desc_2) + strlen(test_desc_3));
+ tt_u64_op(len_descs_dumped, OP_EQ,
+ strlen(test_desc_2) + strlen(test_desc_3));
tt_assert(descs_dumped != NULL && smartlist_len(descs_dumped) == 2);
/*
* Assert things about the mocks
*/
- tt_int_op(unlinked_count, ==, 0);
- tt_int_op(write_str_count, ==, 2);
+ tt_int_op(unlinked_count, OP_EQ, 0);
+ tt_int_op(write_str_count, OP_EQ, 2);
tt_mem_op(last_write_str_hash, OP_EQ, test_desc_3_hash, DIGEST_SHA256);
/* Third time */
@@ -4891,14 +5517,15 @@ test_dir_dump_unparseable_descriptors(void *data)
/*
* Assert things about the FIFO state
*/
- tt_u64_op(len_descs_dumped, ==, strlen(test_desc_2) + strlen(test_desc_3));
+ tt_u64_op(len_descs_dumped, OP_EQ,
+ strlen(test_desc_2) + strlen(test_desc_3));
tt_assert(descs_dumped != NULL && smartlist_len(descs_dumped) == 2);
/*
* Assert things about the mocks
*/
- tt_int_op(unlinked_count, ==, 0);
- tt_int_op(write_str_count, ==, 2);
+ tt_int_op(unlinked_count, OP_EQ, 0);
+ tt_int_op(write_str_count, OP_EQ, 2);
tt_mem_op(last_write_str_hash, OP_EQ, test_desc_3_hash, DIGEST_SHA256);
/* Fourth time - we should unlink the dump of test_desc_3 here */
@@ -4907,21 +5534,22 @@ test_dir_dump_unparseable_descriptors(void *data)
/*
* Assert things about the FIFO state
*/
- tt_u64_op(len_descs_dumped, ==, strlen(test_desc_2) + strlen(test_desc_4));
+ tt_u64_op(len_descs_dumped, OP_EQ,
+ strlen(test_desc_2) + strlen(test_desc_4));
tt_assert(descs_dumped != NULL && smartlist_len(descs_dumped) == 2);
/*
* Assert things about the mocks
*/
- tt_int_op(unlinked_count, ==, 1);
- tt_int_op(write_str_count, ==, 3);
+ tt_int_op(unlinked_count, OP_EQ, 1);
+ tt_int_op(write_str_count, OP_EQ, 3);
tt_mem_op(last_write_str_hash, OP_EQ, test_desc_4_hash, DIGEST_SHA256);
/*
* Reset the FIFO and check its state
*/
dump_desc_fifo_cleanup();
- tt_u64_op(len_descs_dumped, ==, 0);
+ tt_u64_op(len_descs_dumped, OP_EQ, 0);
tt_assert(descs_dumped == NULL || smartlist_len(descs_dumped) == 0);
/*
@@ -4929,8 +5557,8 @@ test_dir_dump_unparseable_descriptors(void *data)
*/
mock_unlink_reset();
mock_write_str_to_file_reset();
- tt_int_op(unlinked_count, ==, 0);
- tt_int_op(write_str_count, ==, 0);
+ tt_int_op(unlinked_count, OP_EQ, 0);
+ tt_int_op(write_str_count, OP_EQ, 0);
done:
@@ -4977,7 +5605,7 @@ read_file_to_str_mock(const char *filename, int flags,
char *result = NULL;
/* Insist we got a filename */
- tt_assert(filename != NULL);
+ tt_ptr_op(filename, OP_NE, NULL);
/* We ignore flags */
(void)flags;
@@ -5040,53 +5668,53 @@ test_dir_populate_dump_desc_fifo(void *data)
reset_read_file_to_str_mock();
/* Check state of unlink mock */
- tt_int_op(unlinked_count, ==, 0);
+ tt_int_op(unlinked_count, OP_EQ, 0);
/* Some cases that should fail before trying to read the file */
ent = dump_desc_populate_one_file(dirname, "bar");
- tt_assert(ent == NULL);
- tt_int_op(unlinked_count, ==, 1);
- tt_int_op(read_count, ==, 0);
- tt_int_op(read_call_count, ==, 0);
+ tt_ptr_op(ent, OP_EQ, NULL);
+ tt_int_op(unlinked_count, OP_EQ, 1);
+ tt_int_op(read_count, OP_EQ, 0);
+ tt_int_op(read_call_count, OP_EQ, 0);
ent = dump_desc_populate_one_file(dirname, "unparseable-desc");
- tt_assert(ent == NULL);
- tt_int_op(unlinked_count, ==, 2);
- tt_int_op(read_count, ==, 0);
- tt_int_op(read_call_count, ==, 0);
+ tt_ptr_op(ent, OP_EQ, NULL);
+ tt_int_op(unlinked_count, OP_EQ, 2);
+ tt_int_op(read_count, OP_EQ, 0);
+ tt_int_op(read_call_count, OP_EQ, 0);
ent = dump_desc_populate_one_file(dirname, "unparseable-desc.baz");
- tt_assert(ent == NULL);
- tt_int_op(unlinked_count, ==, 3);
- tt_int_op(read_count, ==, 0);
- tt_int_op(read_call_count, ==, 0);
+ tt_ptr_op(ent, OP_EQ, NULL);
+ tt_int_op(unlinked_count, OP_EQ, 3);
+ tt_int_op(read_count, OP_EQ, 0);
+ tt_int_op(read_call_count, OP_EQ, 0);
ent = dump_desc_populate_one_file(
dirname,
"unparseable-desc.08AE85E90461F59E");
- tt_assert(ent == NULL);
- tt_int_op(unlinked_count, ==, 4);
- tt_int_op(read_count, ==, 0);
- tt_int_op(read_call_count, ==, 0);
+ tt_ptr_op(ent, OP_EQ, NULL);
+ tt_int_op(unlinked_count, OP_EQ, 4);
+ tt_int_op(read_count, OP_EQ, 0);
+ tt_int_op(read_call_count, OP_EQ, 0);
ent = dump_desc_populate_one_file(
dirname,
"unparseable-desc.08AE85E90461F59EDF0981323F3A70D02B55AB54B44B04F"
"287D72F7B72F242E85C8CB0EDA8854A99");
- tt_assert(ent == NULL);
- tt_int_op(unlinked_count, ==, 5);
- tt_int_op(read_count, ==, 0);
- tt_int_op(read_call_count, ==, 0);
+ tt_ptr_op(ent, OP_EQ, NULL);
+ tt_int_op(unlinked_count, OP_EQ, 5);
+ tt_int_op(read_count, OP_EQ, 0);
+ tt_int_op(read_call_count, OP_EQ, 0);
/* This is a correct-length digest but base16_decode() will fail */
ent = dump_desc_populate_one_file(
dirname,
"unparseable-desc.68219B8BGE64B705A6FFC728C069DC596216D60A7D7520C"
"D5ECE250D912E686B");
- tt_assert(ent == NULL);
- tt_int_op(unlinked_count, ==, 6);
- tt_int_op(read_count, ==, 0);
- tt_int_op(read_call_count, ==, 0);
+ tt_ptr_op(ent, OP_EQ, NULL);
+ tt_int_op(unlinked_count, OP_EQ, 6);
+ tt_int_op(read_count, OP_EQ, 0);
+ tt_int_op(read_call_count, OP_EQ, 0);
/* This one has a correctly formed filename and should try reading */
@@ -5095,10 +5723,10 @@ test_dir_populate_dump_desc_fifo(void *data)
dirname,
"unparseable-desc.DF0981323F3A70D02B55AB54B44B04F287D72F7B72F242E"
"85C8CB0EDA8854A99");
- tt_assert(ent == NULL);
- tt_int_op(unlinked_count, ==, 7);
- tt_int_op(read_count, ==, 0);
- tt_int_op(read_call_count, ==, 1);
+ tt_ptr_op(ent, OP_EQ, NULL);
+ tt_int_op(unlinked_count, OP_EQ, 7);
+ tt_int_op(read_count, OP_EQ, 0);
+ tt_int_op(read_call_count, OP_EQ, 1);
/* This read will succeed but the digest won't match the file content */
fname =
@@ -5111,10 +5739,10 @@ test_dir_populate_dump_desc_fifo(void *data)
file_stat.st_mtime = 123456;
ent = dump_desc_populate_one_file(dirname, fname);
enforce_expected_filename = 0;
- tt_assert(ent == NULL);
- tt_int_op(unlinked_count, ==, 8);
- tt_int_op(read_count, ==, 1);
- tt_int_op(read_call_count, ==, 2);
+ tt_ptr_op(ent, OP_EQ, NULL);
+ tt_int_op(unlinked_count, OP_EQ, 8);
+ tt_int_op(read_count, OP_EQ, 1);
+ tt_int_op(read_call_count, OP_EQ, 2);
tor_free(expected_filename);
tor_free(file_content);
@@ -5127,13 +5755,13 @@ test_dir_populate_dump_desc_fifo(void *data)
file_content_len = strlen(file_content);
file_stat.st_mtime = 789012;
ent = dump_desc_populate_one_file(dirname, fname);
- tt_assert(ent != NULL);
- tt_int_op(unlinked_count, ==, 8);
- tt_int_op(read_count, ==, 2);
- tt_int_op(read_call_count, ==, 3);
+ tt_ptr_op(ent, OP_NE, NULL);
+ tt_int_op(unlinked_count, OP_EQ, 8);
+ tt_int_op(read_count, OP_EQ, 2);
+ tt_int_op(read_call_count, OP_EQ, 3);
tt_str_op(ent->filename, OP_EQ, expected_filename);
- tt_int_op(ent->len, ==, file_content_len);
- tt_int_op(ent->when, ==, file_stat.st_mtime);
+ tt_int_op(ent->len, OP_EQ, file_content_len);
+ tt_int_op(ent->when, OP_EQ, file_stat.st_mtime);
tor_free(ent->filename);
tor_free(ent);
tor_free(expected_filename);
@@ -5142,9 +5770,9 @@ test_dir_populate_dump_desc_fifo(void *data)
* Reset the mocks and check their state
*/
mock_unlink_reset();
- tt_int_op(unlinked_count, ==, 0);
+ tt_int_op(unlinked_count, OP_EQ, 0);
reset_read_file_to_str_mock();
- tt_int_op(read_count, ==, 0);
+ tt_int_op(read_count, OP_EQ, 0);
done:
@@ -5167,9 +5795,9 @@ listdir_mock(const char *dname)
(void)dname;
l = smartlist_new();
- smartlist_add(l, tor_strdup("foo"));
- smartlist_add(l, tor_strdup("bar"));
- smartlist_add(l, tor_strdup("baz"));
+ smartlist_add_strdup(l, "foo");
+ smartlist_add_strdup(l, "bar");
+ smartlist_add_strdup(l, "baz");
return l;
}
@@ -5266,9 +5894,18 @@ mock_networkstatus_consensus_can_use_extra_fallbacks(
return mock_networkstatus_consensus_can_use_extra_fallbacks_value;
}
-/* data is a 2 character nul-terminated string.
+static int mock_num_bridges_usable_value = 0;
+static int
+mock_num_bridges_usable(int use_maybe_reachable)
+{
+ (void)use_maybe_reachable;
+ return mock_num_bridges_usable_value;
+}
+
+/* data is a 3 character nul-terminated string.
* If data[0] is 'b', set bootstrapping, anything else means not bootstrapping
* If data[1] is 'f', set extra fallbacks, anything else means no extra
+ * If data[2] is 'f', set running bridges, anything else means no extra
* fallbacks.
*/
static void
@@ -5276,7 +5913,7 @@ test_dir_find_dl_schedule(void* data)
{
const char *str = (const char *)data;
- tt_assert(strlen(data) == 2);
+ tt_assert(strlen(data) == 3);
if (str[0] == 'b') {
mock_networkstatus_consensus_is_bootstrapping_value = 1;
@@ -5290,15 +5927,24 @@ test_dir_find_dl_schedule(void* data)
mock_networkstatus_consensus_can_use_extra_fallbacks_value = 0;
}
+ if (str[2] == 'r') {
+ /* Any positive, non-zero value should work */
+ mock_num_bridges_usable_value = 2;
+ } else {
+ mock_num_bridges_usable_value = 0;
+ }
+
MOCK(networkstatus_consensus_is_bootstrapping,
mock_networkstatus_consensus_is_bootstrapping);
MOCK(networkstatus_consensus_can_use_extra_fallbacks,
mock_networkstatus_consensus_can_use_extra_fallbacks);
+ MOCK(num_bridges_usable,
+ mock_num_bridges_usable);
download_status_t dls;
smartlist_t server, client, server_cons, client_cons;
smartlist_t client_boot_auth_only_cons, client_boot_auth_cons;
- smartlist_t client_boot_fallback_cons, bridge;
+ smartlist_t client_boot_fallback_cons, bridge, bridge_bootstrap;
mock_options = tor_malloc(sizeof(or_options_t));
reset_options(mock_options, &mock_get_options_calls);
@@ -5315,6 +5961,7 @@ test_dir_find_dl_schedule(void* data)
mock_options->ClientBootstrapConsensusFallbackDownloadSchedule =
&client_boot_fallback_cons;
mock_options->TestingBridgeDownloadSchedule = &bridge;
+ mock_options->TestingBridgeBootstrapDownloadSchedule = &bridge_bootstrap;
dls.schedule = DL_SCHED_GENERIC;
/* client */
@@ -5403,11 +6050,17 @@ test_dir_find_dl_schedule(void* data)
dls.schedule = DL_SCHED_BRIDGE;
/* client */
mock_options->ClientOnly = 1;
- tt_ptr_op(find_dl_schedule(&dls, mock_options), OP_EQ, &bridge);
+ mock_options->UseBridges = 1;
+ if (num_bridges_usable(0) > 0) {
+ tt_ptr_op(find_dl_schedule(&dls, mock_options), OP_EQ, &bridge);
+ } else {
+ tt_ptr_op(find_dl_schedule(&dls, mock_options), OP_EQ, &bridge_bootstrap);
+ }
done:
UNMOCK(networkstatus_consensus_is_bootstrapping);
UNMOCK(networkstatus_consensus_can_use_extra_fallbacks);
+ UNMOCK(num_bridges_usable);
UNMOCK(get_options);
tor_free(mock_options);
mock_options = NULL;
@@ -5457,6 +6110,90 @@ test_dir_assumed_flags(void *arg)
}
static void
+test_dir_post_parsing(void *arg)
+{
+ (void) arg;
+
+ /* Test the version parsing from an HS descriptor publish request. */
+ {
+ const char *end;
+ const char *prefix = "/tor/hs/";
+ int version = parse_hs_version_from_post("/tor/hs//publish", prefix, &end);
+ tt_int_op(version, OP_EQ, -1);
+ tt_ptr_op(end, OP_EQ, NULL);
+ version = parse_hs_version_from_post("/tor/hs/a/publish", prefix, &end);
+ tt_int_op(version, OP_EQ, -1);
+ tt_ptr_op(end, OP_EQ, NULL);
+ version = parse_hs_version_from_post("/tor/hs/3/publish", prefix, &end);
+ tt_int_op(version, OP_EQ, 3);
+ tt_str_op(end, OP_EQ, "/publish");
+ version = parse_hs_version_from_post("/tor/hs/42/publish", prefix, &end);
+ tt_int_op(version, OP_EQ, 42);
+ tt_str_op(end, OP_EQ, "/publish");
+ version = parse_hs_version_from_post("/tor/hs/18163/publish",prefix, &end);
+ tt_int_op(version, OP_EQ, 18163);
+ tt_str_op(end, OP_EQ, "/publish");
+ version = parse_hs_version_from_post("JUNKJUNKJUNK", prefix, &end);
+ tt_int_op(version, OP_EQ, -1);
+ tt_ptr_op(end, OP_EQ, NULL);
+ version = parse_hs_version_from_post("/tor/hs/3/publish", "blah", &end);
+ tt_int_op(version, OP_EQ, -1);
+ tt_ptr_op(end, OP_EQ, NULL);
+ /* Missing the '/' at the end of the prefix. */
+ version = parse_hs_version_from_post("/tor/hs/3/publish", "/tor/hs", &end);
+ tt_int_op(version, OP_EQ, -1);
+ tt_ptr_op(end, OP_EQ, NULL);
+ version = parse_hs_version_from_post("/random/blah/tor/hs/3/publish",
+ prefix, &end);
+ tt_int_op(version, OP_EQ, -1);
+ tt_ptr_op(end, OP_EQ, NULL);
+ version = parse_hs_version_from_post("/tor/hs/3/publish/random/junk",
+ prefix, &end);
+ tt_int_op(version, OP_EQ, 3);
+ tt_str_op(end, OP_EQ, "/publish/random/junk");
+ version = parse_hs_version_from_post("/tor/hs/-1/publish", prefix, &end);
+ tt_int_op(version, OP_EQ, -1);
+ tt_ptr_op(end, OP_EQ, NULL);
+ /* INT_MAX */
+ version = parse_hs_version_from_post("/tor/hs/2147483647/publish",
+ prefix, &end);
+ tt_int_op(version, OP_EQ, INT_MAX);
+ tt_str_op(end, OP_EQ, "/publish");
+ /* INT_MAX + 1*/
+ version = parse_hs_version_from_post("/tor/hs/2147483648/publish",
+ prefix, &end);
+ tt_int_op(version, OP_EQ, -1);
+ tt_ptr_op(end, OP_EQ, NULL);
+ }
+
+ done:
+ ;
+}
+
+static void
+test_dir_platform_str(void *arg)
+{
+ char platform[256];
+ (void)arg;
+ platform[0] = 0;
+ get_platform_str(platform, sizeof(platform));
+ tt_int_op((int)strlen(platform), OP_GT, 0);
+ tt_assert(!strcmpstart(platform, "Tor "));
+
+ tor_version_t ver;
+ // make sure this is a tor version, a real actual tor version.
+ tt_int_op(tor_version_parse_platform(platform, &ver, 1), OP_EQ, 1);
+
+ TT_BLATHER(("%d.%d.%d.%d", ver.major, ver.minor, ver.micro, ver.patchlevel));
+
+ // Handle an example version.
+ tt_int_op(tor_version_parse_platform(
+ "Tor 0.3.3.3 (foo) (git-xyzzy) on a potato", &ver, 1), OP_EQ, 1);
+ done:
+ ;
+}
+
+static void
test_dir_format_versions_list(void *arg)
{
(void)arg;
@@ -5525,6 +6262,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),
@@ -5541,12 +6279,18 @@ struct testcase_t dir_tests[] = {
DIR(fmt_control_ns, 0),
DIR(dirserv_set_routerstatus_testing, 0),
DIR(http_handling, 0),
- DIR(purpose_needs_anonymity, 0),
+ DIR(purpose_needs_anonymity_returns_true_for_bridges, 0),
+ DIR(purpose_needs_anonymity_returns_false_for_own_bridge_desc, 0),
+ DIR(purpose_needs_anonymity_returns_true_by_default, 0),
+ DIR(purpose_needs_anonymity_returns_true_for_sensitive_purpose, 0),
+ DIR(purpose_needs_anonymity_ret_false_for_non_sensitive_conn, 0),
+ DIR(post_parsing, 0),
DIR(fetch_type, 0),
DIR(packages, 0),
DIR(download_status_schedule, 0),
DIR(download_status_random_backoff, 0),
- DIR(download_status_increment, 0),
+ DIR(download_status_random_backoff_ranges, 0),
+ DIR(download_status_increment, TT_FORK),
DIR(authdir_type_to_string, 0),
DIR(conn_purpose_to_string, 0),
DIR(should_use_directory_guards, 0),
@@ -5557,11 +6301,17 @@ struct testcase_t dir_tests[] = {
DIR(dump_unparseable_descriptors, 0),
DIR(populate_dump_desc_fifo, 0),
DIR(populate_dump_desc_fifo_2, 0),
- DIR_ARG(find_dl_schedule, TT_FORK, "bf"),
- DIR_ARG(find_dl_schedule, TT_FORK, "ba"),
- DIR_ARG(find_dl_schedule, TT_FORK, "cf"),
- DIR_ARG(find_dl_schedule, TT_FORK, "ca"),
+ DIR_ARG(find_dl_schedule, TT_FORK, "bfd"),
+ DIR_ARG(find_dl_schedule, TT_FORK, "bad"),
+ DIR_ARG(find_dl_schedule, TT_FORK, "cfd"),
+ DIR_ARG(find_dl_schedule, TT_FORK, "cad"),
+ DIR_ARG(find_dl_schedule, TT_FORK, "bfr"),
+ DIR_ARG(find_dl_schedule, TT_FORK, "bar"),
+ DIR_ARG(find_dl_schedule, TT_FORK, "cfr"),
+ DIR_ARG(find_dl_schedule, TT_FORK, "car"),
DIR(assumed_flags, 0),
+ DIR(networkstatus_compute_bw_weights_v10, 0),
+ DIR(platform_str, 0),
DIR(format_versions_list, TT_FORK),
END_OF_TESTCASES
};
diff --git a/src/test/test_dir_common.c b/src/test/test_dir_common.c
index ca43dd4c04..fdf43533a8 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"
@@ -146,7 +146,7 @@ dir_common_gen_routerstatus_for_v3ns(int idx, time_t now)
break;
default:
/* Shouldn't happen */
- tt_assert(0);
+ tt_abort();
}
if (vrs) {
vrs->microdesc = tor_malloc_zero(sizeof(vote_microdesc_hash_t));
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 a0f22f1f0c..fe26657ad8 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
@@ -12,8 +12,10 @@
#include "or.h"
#include "config.h"
#include "connection.h"
+#include "consdiffmgr.h"
#include "directory.h"
#include "test.h"
+#include "compress.h"
#include "connection.h"
#include "rendcommon.h"
#include "rendcache.h"
@@ -26,17 +28,18 @@
#include "entrynodes.h"
#include "routerparse.h"
#include "networkstatus.h"
+#include "proto_http.h"
#include "geoip.h"
#include "dirserv.h"
-#include "torgzip.h"
#include "dirvote.h"
+#include "log_test_helpers.h"
#ifdef _WIN32
/* For mkdir() */
#include <direct.h>
#else
#include <dirent.h>
-#endif
+#endif /* defined(_WIN32) */
#ifdef HAVE_CFLAG_WOVERLENGTH_STRINGS
DISABLE_GCC_WARNING(overlength-strings)
@@ -50,22 +53,10 @@ ENABLE_GCC_WARNING(overlength-strings)
#define NS_MODULE dir_handle_get
-static void
-connection_write_to_buf_mock(const char *string, size_t len,
- connection_t *conn, int zlib)
-{
- (void) zlib;
-
- tor_assert(string);
- tor_assert(conn);
-
- write_to_buf(string, len, conn->outbuf);
-}
-
-#define GET(path) "GET " path " HTTP/1.0\r\n\r\n"
#define NOT_FOUND "HTTP/1.0 404 Not found\r\n\r\n"
#define BAD_REQUEST "HTTP/1.0 400 Bad request\r\n\r\n"
#define SERVER_BUSY "HTTP/1.0 503 Directory busy, try again later\r\n\r\n"
+#define TOO_OLD "HTTP/1.0 404 Consensus is too old\r\n\r\n"
#define NOT_ENOUGH_CONSENSUS_SIGNATURES "HTTP/1.0 404 " \
"Consensus not signed by sufficient number of requested authorities\r\n\r\n"
@@ -74,6 +65,7 @@ new_dir_conn(void)
{
dir_connection_t *conn = dir_connection_new(AF_INET);
tor_addr_from_ipv4h(&conn->base_.addr, 0x7f000001);
+ TO_CONN(conn)->address = tor_strdup("127.0.0.1");
return conn;
}
@@ -476,6 +468,8 @@ init_mock_options(void)
mock_options = tor_malloc(sizeof(or_options_t));
memset(mock_options, 0, sizeof(or_options_t));
mock_options->TestingTorNetwork = 1;
+ mock_options->DataDirectory = tor_strdup(get_fname_rnd("datadir_tmp"));
+ check_private_dir(mock_options->DataDirectory, CPD_CREATE, NULL);
}
static const or_options_t *
@@ -512,14 +506,6 @@ test_dir_handle_get_micro_d(void *data)
/* SETUP */
init_mock_options();
- const char *fn = get_fname("dir_handle_datadir_test1");
- mock_options->DataDirectory = tor_strdup(fn);
-
-#ifdef _WIN32
- tt_int_op(0, OP_EQ, mkdir(mock_options->DataDirectory));
-#else
- tt_int_op(0, OP_EQ, mkdir(mock_options->DataDirectory, 0700));
-#endif
/* Add microdesc to cache */
crypto_digest256(digest, microdesc, strlen(microdesc), DIGEST_SHA256);
@@ -579,14 +565,6 @@ test_dir_handle_get_micro_d_server_busy(void *data)
/* SETUP */
init_mock_options();
- const char *fn = get_fname("dir_handle_datadir_test2");
- mock_options->DataDirectory = tor_strdup(fn);
-
-#ifdef _WIN32
- tt_int_op(0, OP_EQ, mkdir(mock_options->DataDirectory));
-#else
- tt_int_op(0, OP_EQ, mkdir(mock_options->DataDirectory, 0700));
-#endif
/* Add microdesc to cache */
crypto_digest256(digest, microdesc, strlen(microdesc), DIGEST_SHA256);
@@ -754,7 +732,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_);
@@ -784,6 +762,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;
@@ -798,7 +777,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);
@@ -814,7 +793,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);
@@ -891,8 +870,9 @@ test_dir_handle_get_server_descriptors_authority(void* data)
mock_routerinfo->cache_info.signed_descriptor_body =
tor_strdup(TEST_DESCRIPTOR);
mock_routerinfo->cache_info.signed_descriptor_len =
- strlen(TEST_DESCRIPTOR) - annotation_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();
@@ -915,7 +895,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);
@@ -957,6 +937,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();
@@ -986,7 +967,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);
@@ -1052,7 +1033,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_);
@@ -1107,7 +1088,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);
@@ -1629,7 +1610,13 @@ test_dir_handle_get_status_vote_current_consensus_ns_not_enough_sigs(void* d)
/* init mock */
mock_ns_val = tor_malloc_zero(sizeof(networkstatus_t));
mock_ns_val->flavor = FLAV_NS;
+ mock_ns_val->type = NS_TYPE_CONSENSUS;
mock_ns_val->voters = smartlist_new();
+ mock_ns_val->valid_after = time(NULL) - 1800;
+ mock_ns_val->valid_until = time(NULL) - 60;
+
+ #define NETWORK_STATUS "some network status string"
+ consdiffmgr_add_consensus(NETWORK_STATUS, mock_ns_val);
/* init mock */
init_mock_options();
@@ -1709,6 +1696,80 @@ test_dir_handle_get_status_vote_current_consensus_ns_not_found(void* data)
or_options_free(mock_options); mock_options = NULL;
}
+static void
+test_dir_handle_get_status_vote_current_consensus_too_old(void *data)
+{
+ dir_connection_t *conn = NULL;
+ char *header = NULL;
+ (void)data;
+
+ mock_ns_val = tor_malloc_zero(sizeof(networkstatus_t));
+ mock_ns_val->type = NS_TYPE_CONSENSUS;
+ mock_ns_val->flavor = FLAV_MICRODESC;
+ mock_ns_val->valid_after = time(NULL) - (24 * 60 * 60 + 1800);
+ mock_ns_val->fresh_until = time(NULL) - (24 * 60 * 60 + 900);
+ mock_ns_val->valid_until = time(NULL) - (24 * 60 * 60 + 20);
+
+ #define NETWORK_STATUS "some network status string"
+ consdiffmgr_add_consensus(NETWORK_STATUS, mock_ns_val);
+
+ init_mock_options();
+
+ MOCK(get_options, mock_get_options);
+ MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock);
+ MOCK(networkstatus_get_latest_consensus_by_flavor, mock_ns_get_by_flavor);
+
+ conn = new_dir_conn();
+
+ setup_capture_of_logs(LOG_WARN);
+
+ tt_int_op(0, OP_EQ, directory_handle_command_get(conn,
+ GET("/tor/status-vote/current/consensus-microdesc"), NULL, 0));
+
+ fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE,
+ NULL, NULL, 1, 0);
+ tt_assert(header);
+ tt_str_op(TOO_OLD, OP_EQ, header);
+
+ expect_log_msg_containing("too old");
+
+ tor_free(header);
+ teardown_capture_of_logs();
+ tor_free(mock_ns_val);
+
+ mock_ns_val = tor_malloc_zero(sizeof(networkstatus_t));
+ mock_ns_val->type = NS_TYPE_CONSENSUS;
+ mock_ns_val->flavor = FLAV_NS;
+ mock_ns_val->valid_after = time(NULL) - (24 * 60 * 60 + 1800);
+ mock_ns_val->fresh_until = time(NULL) - (24 * 60 * 60 + 900);
+ mock_ns_val->valid_until = time(NULL) - (24 * 60 * 60 + 20);
+
+ #define NETWORK_STATUS "some network status string"
+ consdiffmgr_add_consensus(NETWORK_STATUS, mock_ns_val);
+
+ setup_capture_of_logs(LOG_WARN);
+
+ tt_int_op(0, OP_EQ, directory_handle_command_get(conn,
+ GET("/tor/status-vote/current/consensus"), NULL, 0));
+
+ fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE,
+ NULL, NULL, 1, 0);
+ tt_assert(header);
+ tt_str_op(TOO_OLD, OP_EQ, header);
+
+ expect_no_log_entry();
+
+ done:
+ teardown_capture_of_logs();
+ UNMOCK(networkstatus_get_latest_consensus_by_flavor);
+ UNMOCK(connection_write_to_buf_impl_);
+ UNMOCK(get_options);
+ connection_free_(TO_CONN(conn));
+ tor_free(header);
+ tor_free(mock_ns_val);
+ or_options_free(mock_options); mock_options = NULL;
+}
+
NS_DECL(int, geoip_get_country_by_addr, (const tor_addr_t *addr));
int
@@ -1723,12 +1784,26 @@ static void
status_vote_current_consensus_ns_test(char **header, char **body,
size_t *body_len)
{
- common_digests_t digests;
dir_connection_t *conn = NULL;
#define NETWORK_STATUS "some network status string"
+#if 0
+ common_digests_t digests;
+ uint8_t sha3[DIGEST256_LEN];
+ memset(&digests, 0x60, sizeof(digests));
+ memset(sha3, 0x06, sizeof(sha3));
dirserv_set_cached_consensus_networkstatus(NETWORK_STATUS, "ns", &digests,
+ sha3,
time(NULL));
+#endif /* 0 */
+ networkstatus_t *ns = tor_malloc_zero(sizeof(networkstatus_t));
+ ns->type = NS_TYPE_CONSENSUS;
+ ns->flavor = FLAV_NS;
+ ns->valid_after = time(NULL) - 1800;
+ ns->fresh_until = time(NULL) - 900;
+ ns->valid_until = time(NULL) - 60;
+ consdiffmgr_add_consensus(NETWORK_STATUS, ns);
+ networkstatus_vote_free(ns);
MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock);
@@ -1741,7 +1816,6 @@ status_vote_current_consensus_ns_test(char **header, char **body,
tt_str_op("ab", OP_EQ, geoip_get_country_name(1));
conn = new_dir_conn();
- TO_CONN(conn)->address = tor_strdup("127.0.0.1");
tt_int_op(0, OP_EQ, directory_handle_command_get(conn,
GET("/tor/status-vote/current/consensus-ns"), NULL, 0));
@@ -1783,8 +1857,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);
@@ -2448,6 +2522,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 }
@@ -2492,10 +2613,11 @@ struct testcase_t dir_handle_get_tests[] = {
DIR_HANDLE_CMD(status_vote_current_authority, 0),
DIR_HANDLE_CMD(status_vote_next_authority_not_found, 0),
DIR_HANDLE_CMD(status_vote_next_authority, 0),
- DIR_HANDLE_CMD(status_vote_current_consensus_ns_not_enough_sigs, 0),
- DIR_HANDLE_CMD(status_vote_current_consensus_ns_not_found, 0),
- DIR_HANDLE_CMD(status_vote_current_consensus_ns_busy, 0),
- DIR_HANDLE_CMD(status_vote_current_consensus_ns, 0),
+ DIR_HANDLE_CMD(status_vote_current_consensus_ns_not_enough_sigs, TT_FORK),
+ DIR_HANDLE_CMD(status_vote_current_consensus_ns_not_found, TT_FORK),
+ DIR_HANDLE_CMD(status_vote_current_consensus_too_old, TT_FORK),
+ DIR_HANDLE_CMD(status_vote_current_consensus_ns_busy, TT_FORK),
+ DIR_HANDLE_CMD(status_vote_current_consensus_ns, TT_FORK),
DIR_HANDLE_CMD(status_vote_current_d_not_found, 0),
DIR_HANDLE_CMD(status_vote_next_d_not_found, 0),
DIR_HANDLE_CMD(status_vote_d, 0),
@@ -2505,6 +2627,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_dns.c b/src/test/test_dns.c
index 6a8e92cb47..19dcb02931 100644
--- a/src/test/test_dns.c
+++ b/src/test/test_dns.c
@@ -18,9 +18,9 @@ NS(test_main)(void *arg)
uint32_t ttl_mid = MIN_DNS_TTL_AT_EXIT / 2 + MAX_DNS_TTL_AT_EXIT / 2;
- tt_int_op(dns_clip_ttl(MIN_DNS_TTL_AT_EXIT - 1),==,MIN_DNS_TTL_AT_EXIT);
- tt_int_op(dns_clip_ttl(ttl_mid),==,MAX_DNS_TTL_AT_EXIT);
- tt_int_op(dns_clip_ttl(MAX_DNS_TTL_AT_EXIT + 1),==,MAX_DNS_TTL_AT_EXIT);
+ tt_int_op(dns_clip_ttl(MIN_DNS_TTL_AT_EXIT - 1),OP_EQ,MIN_DNS_TTL_AT_EXIT);
+ tt_int_op(dns_clip_ttl(ttl_mid),OP_EQ,MAX_DNS_TTL_AT_EXIT);
+ tt_int_op(dns_clip_ttl(MAX_DNS_TTL_AT_EXIT + 1),OP_EQ,MAX_DNS_TTL_AT_EXIT);
done:
return;
@@ -172,10 +172,10 @@ NS(test_main)(void *arg)
retval = dns_resolve(exitconn);
- tt_int_op(retval,==,1);
- tt_str_op(resolved_name,==,last_resolved_hostname);
+ tt_int_op(retval,OP_EQ,1);
+ tt_str_op(resolved_name,OP_EQ,last_resolved_hostname);
tt_assert(conn_for_resolved_cell == exitconn);
- tt_int_op(n_send_resolved_hostname_cell_replacement,==,
+ tt_int_op(n_send_resolved_hostname_cell_replacement,OP_EQ,
prev_n_send_resolved_hostname_cell_replacement + 1);
tt_assert(exitconn->on_circuit == NULL);
@@ -201,12 +201,12 @@ NS(test_main)(void *arg)
retval = dns_resolve(exitconn);
- tt_int_op(retval,==,1);
+ tt_int_op(retval,OP_EQ,1);
tt_assert(conn_for_resolved_cell == exitconn);
- tt_int_op(n_send_resolved_cell_replacement,==,
+ tt_int_op(n_send_resolved_cell_replacement,OP_EQ,
prev_n_send_resolved_cell_replacement + 1);
tt_assert(last_resolved == fake_resolved);
- tt_int_op(last_answer_type,==,0xff);
+ tt_int_op(last_answer_type,OP_EQ,0xff);
tt_assert(exitconn->on_circuit == NULL);
/* CASE 3: The purpose of exit connection is not EXIT_PURPOSE_RESOLVE
@@ -229,12 +229,12 @@ NS(test_main)(void *arg)
retval = dns_resolve(exitconn);
- tt_int_op(retval,==,1);
+ tt_int_op(retval,OP_EQ,1);
tt_assert(on_circuit->n_streams == exitconn);
tt_assert(exitconn->next_stream == nextconn);
- tt_int_op(prev_n_send_resolved_cell_replacement,==,
+ tt_int_op(prev_n_send_resolved_cell_replacement,OP_EQ,
n_send_resolved_cell_replacement);
- tt_int_op(prev_n_send_resolved_hostname_cell_replacement,==,
+ tt_int_op(prev_n_send_resolved_hostname_cell_replacement,OP_EQ,
n_send_resolved_hostname_cell_replacement);
/* CASE 4: _impl returns 0.
@@ -253,8 +253,8 @@ NS(test_main)(void *arg)
retval = dns_resolve(exitconn);
- tt_int_op(retval,==,0);
- tt_int_op(exitconn->base_.state,==,EXIT_CONN_STATE_RESOLVING);
+ tt_int_op(retval,OP_EQ,0);
+ tt_int_op(exitconn->base_.state,OP_EQ,EXIT_CONN_STATE_RESOLVING);
tt_assert(on_circuit->resolving_streams == exitconn);
tt_assert(exitconn->next_stream == nextconn);
@@ -278,12 +278,12 @@ NS(test_main)(void *arg)
retval = dns_resolve(exitconn);
- tt_int_op(retval,==,-1);
- tt_int_op(n_send_resolved_cell_replacement,==,
+ tt_int_op(retval,OP_EQ,-1);
+ tt_int_op(n_send_resolved_cell_replacement,OP_EQ,
prev_n_send_resolved_cell_replacement + 1);
- tt_int_op(last_answer_type,==,RESOLVED_TYPE_ERROR);
- tt_int_op(n_dns_cancel_pending_resolve_replacement,==,1);
- tt_int_op(n_connection_free,==,prev_n_connection_free + 1);
+ tt_int_op(last_answer_type,OP_EQ,RESOLVED_TYPE_ERROR);
+ tt_int_op(n_dns_cancel_pending_resolve_replacement,OP_EQ,1);
+ tt_int_op(n_connection_free,OP_EQ,prev_n_connection_free + 1);
tt_assert(last_freed_conn == TO_CONN(exitconn));
done:
@@ -351,9 +351,9 @@ NS(test_main)(void *arg)
resolved_addr = &(exitconn->base_.addr);
- tt_int_op(retval,==,1);
+ tt_int_op(retval,OP_EQ,1);
tt_assert(tor_addr_eq(resolved_addr, (const tor_addr_t *)&addr_to_compare));
- tt_int_op(exitconn->address_ttl,==,DEFAULT_DNS_TTL);
+ tt_int_op(exitconn->address_ttl,OP_EQ,DEFAULT_DNS_TTL);
done:
tor_free(on_circ);
@@ -393,7 +393,7 @@ NS(test_main)(void *arg)
retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending,
NULL);
- tt_int_op(retval,==,-1);
+ tt_int_op(retval,OP_EQ,-1);
done:
tor_free(TO_CONN(exitconn)->address);
@@ -436,7 +436,7 @@ NS(test_main)(void *arg)
retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending,
NULL);
- tt_int_op(retval,==,-1);
+ tt_int_op(retval,OP_EQ,-1);
done:
NS_UNMOCK(router_my_exit_policy_is_reject_star);
@@ -478,7 +478,7 @@ NS(test_main)(void *arg)
retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending,
NULL);
- tt_int_op(retval,==,-1);
+ tt_int_op(retval,OP_EQ,-1);
tor_free(TO_CONN(exitconn)->address);
@@ -488,7 +488,7 @@ NS(test_main)(void *arg)
retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending,
NULL);
- tt_int_op(retval,==,-1);
+ tt_int_op(retval,OP_EQ,-1);
done:
NS_UNMOCK(router_my_exit_policy_is_reject_star);
@@ -546,8 +546,8 @@ NS(test_main)(void *arg)
retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending,
NULL);
- tt_int_op(retval,==,0);
- tt_int_op(made_pending,==,1);
+ tt_int_op(retval,OP_EQ,0);
+ tt_int_op(made_pending,OP_EQ,1);
pending_conn = cache_entry->pending_connections;
@@ -628,8 +628,8 @@ NS(test_main)(void *arg)
retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending,
&resolve_out);
- tt_int_op(retval,==,0);
- tt_int_op(made_pending,==,0);
+ tt_int_op(retval,OP_EQ,0);
+ tt_int_op(made_pending,OP_EQ,0);
tt_assert(resolve_out == cache_entry);
tt_assert(last_exitconn == exitconn);
@@ -699,8 +699,8 @@ NS(test_main)(void *arg)
retval = dns_resolve_impl(exitconn, 1, on_circ, NULL, &made_pending,
NULL);
- tt_int_op(retval,==,0);
- tt_int_op(made_pending,==,1);
+ tt_int_op(retval,OP_EQ,0);
+ tt_int_op(made_pending,OP_EQ,1);
cache_entry = dns_get_cache_entry(&query);
@@ -712,7 +712,7 @@ NS(test_main)(void *arg)
tt_assert(pending_conn->conn == exitconn);
tt_assert(last_launched_resolve == cache_entry);
- tt_str_op(cache_entry->address,==,TO_CONN(exitconn)->address);
+ tt_str_op(cache_entry->address,OP_EQ,TO_CONN(exitconn)->address);
done:
NS_UNMOCK(router_my_exit_policy_is_reject_star);
diff --git a/src/test/test_entryconn.c b/src/test/test_entryconn.c
index 9580a1fd3f..c29b1a7126 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"
@@ -14,6 +14,10 @@
#include "confparse.h"
#include "connection.h"
#include "connection_edge.h"
+#include "nodelist.h"
+
+#include "hs_cache.h"
+#include "rendcache.h"
static void *
entryconn_rewrite_setup(const struct testcase_t *tc)
@@ -72,7 +76,6 @@ test_entryconn_rewrite_bad_dotexit(void *arg)
entry_connection_t *ec = arg;
rewrite_result_t rr;
- get_options_mutable()->AllowDotExit = 0;
tt_assert(ec->socks_request);
strlcpy(ec->socks_request->address, "www.TORproject.org.foo.exit",
sizeof(ec->socks_request->address));
@@ -100,7 +103,7 @@ test_entryconn_rewrite_automap_ipv4(void *arg)
ec3 = entry_connection_new(CONN_TYPE_AP, AF_INET);
get_options_mutable()->AutomapHostsOnResolve = 1;
- smartlist_add(get_options_mutable()->AutomapHostsSuffixes, tor_strdup("."));
+ smartlist_add_strdup(get_options_mutable()->AutomapHostsSuffixes, ".");
parse_virtual_addr_network("127.202.0.0/16", AF_INET, 0, &msg);
/* Automap this on resolve. */
@@ -173,7 +176,7 @@ test_entryconn_rewrite_automap_ipv6(void *arg)
ec3 = entry_connection_new(CONN_TYPE_AP, AF_INET6);
get_options_mutable()->AutomapHostsOnResolve = 1;
- smartlist_add(get_options_mutable()->AutomapHostsSuffixes, tor_strdup("."));
+ smartlist_add_strdup(get_options_mutable()->AutomapHostsSuffixes, ".");
parse_virtual_addr_network("FE80::/32", AF_INET6, 0, &msg);
/* Automap this on resolve. */
@@ -282,7 +285,7 @@ test_entryconn_rewrite_automap_reverse(void *arg)
done:
connection_free_(ENTRY_TO_CONN(ec2));
}
-#endif
+#endif /* 0 */
/* Rewrite because of cached DNS entry. */
static void
@@ -476,7 +479,7 @@ test_entryconn_rewrite_reject_internal_reverse(void *arg)
;
}
-/* Rewrite into .exit because of virtual address mapping */
+/* Rewrite into .exit because of virtual address mapping. */
static void
test_entryconn_rewrite_automap_exit(void *arg)
{
@@ -487,43 +490,21 @@ test_entryconn_rewrite_automap_exit(void *arg)
ec2 = entry_connection_new(CONN_TYPE_AP, AF_INET);
- get_options_mutable()->AutomapHostsOnResolve = 1;
- get_options_mutable()->AllowDotExit = 1;
- smartlist_add(get_options_mutable()->AutomapHostsSuffixes,
- tor_strdup(".EXIT"));
+ smartlist_add_strdup(get_options_mutable()->AutomapHostsSuffixes,
+ ".EXIT");
parse_virtual_addr_network("127.1.0.0/16", AF_INET, 0, &msg);
- /* Automap this on resolve. */
+ /* Try to automap this on resolve. */
strlcpy(ec->socks_request->address, "website.example.exit",
sizeof(ec->socks_request->address));
ec->socks_request->command = SOCKS_COMMAND_RESOLVE;
connection_ap_handshake_rewrite(ec, &rr);
- tt_int_op(rr.automap, OP_EQ, 1);
- tt_int_op(rr.should_close, OP_EQ, 0);
- tt_int_op(rr.end_reason, OP_EQ, 0);
- tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
- tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
- tt_str_op(rr.orig_address, OP_EQ, "website.example.exit");
- tt_str_op(ec->original_dest_address, OP_EQ, "website.example.exit");
-
- tt_assert(!strcmpstart(ec->socks_request->address,"127.1."));
-
- /* Connect to it and make sure we get the original address back. */
- strlcpy(ec2->socks_request->address, ec->socks_request->address,
- sizeof(ec2->socks_request->address));
-
- ec2->socks_request->command = SOCKS_COMMAND_CONNECT;
- connection_ap_handshake_rewrite(ec2, &rr);
-
+ /* Make sure it isn't allowed -- there is no longer an AllowDotExit
+ * option. */
tt_int_op(rr.automap, OP_EQ, 0);
- tt_int_op(rr.should_close, OP_EQ, 0);
- tt_int_op(rr.end_reason, OP_EQ, 0);
- tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
- tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_AUTOMAP);
- tt_str_op(rr.orig_address, OP_EQ, ec->socks_request->address);
- tt_str_op(ec2->original_dest_address, OP_EQ, ec->socks_request->address);
- tt_str_op(ec2->socks_request->address, OP_EQ, "website.example.exit");
+ tt_int_op(rr.should_close, OP_EQ, 1);
+ tt_int_op(rr.end_reason, OP_EQ, END_STREAM_REASON_TORPROTOCOL);
done:
connection_free_(ENTRY_TO_CONN(ec2));
@@ -573,9 +554,8 @@ test_entryconn_rewrite_mapaddress_automap_onion(void *arg)
ec4 = entry_connection_new(CONN_TYPE_AP, AF_INET);
get_options_mutable()->AutomapHostsOnResolve = 1;
- get_options_mutable()->AllowDotExit = 1;
- smartlist_add(get_options_mutable()->AutomapHostsSuffixes,
- tor_strdup(".onion"));
+ smartlist_add_strdup(get_options_mutable()->AutomapHostsSuffixes,
+ ".onion");
parse_virtual_addr_network("192.168.0.0/16", AF_INET, 0, &msg);
config_line_append(&get_options_mutable()->AddressMap,
"MapAddress", "foo.onion abcdefghijklmnop.onion");
@@ -709,8 +689,8 @@ test_entryconn_rewrite_mapaddress_automap_onion2(void *arg)
{
char *msg = NULL;
get_options_mutable()->AutomapHostsOnResolve = 1;
- smartlist_add(get_options_mutable()->AutomapHostsSuffixes,
- tor_strdup(".onion"));
+ smartlist_add_strdup(get_options_mutable()->AutomapHostsSuffixes,
+ ".onion");
parse_virtual_addr_network("192.168.0.0/16", AF_INET, 0, &msg);
config_line_append(&get_options_mutable()->AddressMap,
"MapAddress", "irc.example.com abcdefghijklmnop.onion");
@@ -736,13 +716,95 @@ test_entryconn_rewrite_mapaddress_automap_onion4(void *arg)
{
char *msg = NULL;
get_options_mutable()->AutomapHostsOnResolve = 1;
- smartlist_add(get_options_mutable()->AutomapHostsSuffixes,
- tor_strdup(".onion"));
+ smartlist_add_strdup(get_options_mutable()->AutomapHostsSuffixes,
+ ".onion");
parse_virtual_addr_network("192.168.0.0/16", AF_INET, 0, &msg);
test_entryconn_rewrite_mapaddress_automap_onion_common(arg, 0, 1);
}
+/** Test that rewrite functions can handle v2 addresses */
+static void
+test_entryconn_rewrite_onion_v2(void *arg)
+{
+ int retval;
+ entry_connection_t *conn = arg;
+
+ (void) arg;
+
+ rend_cache_init();
+
+ /* Make a SOCKS request */
+ conn->socks_request->command = SOCKS_COMMAND_CONNECT;
+ strlcpy(conn->socks_request->address,
+ "pqeed46efnwmfuid.onion",
+ sizeof(conn->socks_request->address));
+
+ /* Make an onion connection using the SOCKS request */
+ conn->entry_cfg.onion_traffic = 1;
+ ENTRY_TO_CONN(conn)->state = AP_CONN_STATE_SOCKS_WAIT;
+ tt_assert(!ENTRY_TO_EDGE_CONN(conn)->rend_data);
+
+ /* Handle SOCKS and rewrite! */
+ retval = connection_ap_handshake_rewrite_and_attach(conn, NULL, NULL);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /* Check connection state after rewrite */
+ tt_int_op(ENTRY_TO_CONN(conn)->state, OP_EQ, AP_CONN_STATE_RENDDESC_WAIT);
+ /* check that the address got rewritten */
+ tt_str_op(conn->socks_request->address, OP_EQ,
+ "pqeed46efnwmfuid");
+ /* check that HS information got attached to the connection */
+ tt_assert(ENTRY_TO_EDGE_CONN(conn)->rend_data);
+ tt_assert(!ENTRY_TO_EDGE_CONN(conn)->hs_ident);
+
+ done:
+ rend_cache_free_all();
+ /* 'conn' is cleaned by handler */
+}
+
+/** Test that rewrite functions can handle v3 onion addresses */
+static void
+test_entryconn_rewrite_onion_v3(void *arg)
+{
+ int retval;
+ entry_connection_t *conn = arg;
+
+ (void) arg;
+
+ hs_cache_init();
+
+ /* Make a SOCKS request */
+ conn->socks_request->command = SOCKS_COMMAND_CONNECT;
+ strlcpy(conn->socks_request->address,
+ "git.25njqamcweflpvkl73j4szahhihoc4xt3ktcgjnpaingr5yhkenl5sid.onion",
+ sizeof(conn->socks_request->address));
+
+ /* Make an onion connection using the SOCKS request */
+ conn->entry_cfg.onion_traffic = 1;
+ ENTRY_TO_CONN(conn)->state = AP_CONN_STATE_SOCKS_WAIT;
+ tt_assert(!ENTRY_TO_EDGE_CONN(conn)->rend_data);
+ tt_assert(!ENTRY_TO_EDGE_CONN(conn)->hs_ident);
+
+ /* Handle SOCKS and rewrite! */
+ retval = connection_ap_handshake_rewrite_and_attach(conn, NULL, NULL);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /* Check connection state after rewrite. It should be in waiting for
+ * descriptor state. */
+ tt_int_op(ENTRY_TO_CONN(conn)->state, OP_EQ, AP_CONN_STATE_RENDDESC_WAIT);
+ /* check that the address got rewritten */
+ tt_str_op(conn->socks_request->address, OP_EQ,
+ "25njqamcweflpvkl73j4szahhihoc4xt3ktcgjnpaingr5yhkenl5sid");
+ /* check that HS information got attached to the connection */
+ tt_assert(ENTRY_TO_EDGE_CONN(conn)->hs_ident);
+ tt_assert(!ENTRY_TO_EDGE_CONN(conn)->rend_data);
+
+ done:
+ hs_free_all();
+ /* 'conn' is cleaned by handler */
+}
+
#define REWRITE(name) \
{ #name, test_entryconn_##name, TT_FORK, &test_rewrite_setup, NULL }
@@ -763,6 +825,8 @@ struct testcase_t entryconn_tests[] = {
REWRITE(rewrite_mapaddress_automap_onion2),
REWRITE(rewrite_mapaddress_automap_onion3),
REWRITE(rewrite_mapaddress_automap_onion4),
+ REWRITE(rewrite_onion_v2),
+ REWRITE(rewrite_onion_v3),
END_OF_TESTCASES
};
diff --git a/src/test/test_entrynodes.c b/src/test/test_entrynodes.c
index b1c3accfab..7d85b09e03 100644
--- a/src/test/test_entrynodes.c
+++ b/src/test/test_entrynodes.c
@@ -1,18 +1,25 @@
-/* Copyright (c) 2014-2016, The Tor Project, Inc. */
+/* Copyright (c) 2014-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
+#define CIRCUITLIST_PRIVATE
#define STATEFILE_PRIVATE
#define ENTRYNODES_PRIVATE
#define ROUTERLIST_PRIVATE
+#define DIRECTORY_PRIVATE
#include "or.h"
#include "test.h"
+#include "bridges.h"
+#include "circuitlist.h"
#include "config.h"
+#include "confparse.h"
+#include "directory.h"
#include "entrynodes.h"
#include "nodelist.h"
+#include "networkstatus.h"
#include "policies.h"
#include "routerlist.h"
#include "routerparse.h"
@@ -21,6 +28,7 @@
#include "util.h"
#include "test_helpers.h"
+#include "log_test_helpers.h"
/* TODO:
* choose_random_entry() test with state set.
@@ -39,37 +47,128 @@ get_or_state_replacement(void)
return dummy_state;
}
+static networkstatus_t *dummy_consensus = NULL;
+
+static smartlist_t *big_fake_net_nodes = NULL;
+
+static smartlist_t *
+bfn_mock_nodelist_get_list(void)
+{
+ return big_fake_net_nodes;
+}
+
+static networkstatus_t *
+bfn_mock_networkstatus_get_live_consensus(time_t now)
+{
+ (void)now;
+ return dummy_consensus;
+}
+
+static const node_t *
+bfn_mock_node_get_by_id(const char *id)
+{
+ SMARTLIST_FOREACH(big_fake_net_nodes, node_t *, n,
+ if (fast_memeq(n->identity, id, 20))
+ return n);
+
+ return NULL;
+}
+
/* Unittest cleanup function: Cleanup the fake network. */
static int
-fake_network_cleanup(const struct testcase_t *testcase, void *ptr)
+big_fake_network_cleanup(const struct testcase_t *testcase, void *ptr)
{
(void) testcase;
(void) ptr;
- routerlist_free_all();
- nodelist_free_all();
- entry_guards_free_all();
+ if (big_fake_net_nodes) {
+ SMARTLIST_FOREACH(big_fake_net_nodes, node_t *, n, {
+ tor_free(n->rs);
+ tor_free(n->md);
+ tor_free(n);
+ });
+ smartlist_free(big_fake_net_nodes);
+ }
+
+ UNMOCK(nodelist_get_list);
+ UNMOCK(node_get_by_id);
+ UNMOCK(get_or_state);
+ UNMOCK(networkstatus_get_live_consensus);
or_state_free(dummy_state);
+ dummy_state = NULL;
+ tor_free(dummy_consensus);
return 1; /* NOP */
}
/* Unittest setup function: Setup a fake network. */
static void *
-fake_network_setup(const struct testcase_t *testcase)
+big_fake_network_setup(const struct testcase_t *testcase)
{
- (void) testcase;
+ int i;
+
+ /* These are minimal node_t objects that only contain the aspects of node_t
+ * that we need for entrynodes.c. */
+ const int N_NODES = 271;
+
+ big_fake_net_nodes = smartlist_new();
+ for (i = 0; i < N_NODES; ++i) {
+ node_t *n = tor_malloc_zero(sizeof(node_t));
+ n->md = tor_malloc_zero(sizeof(microdesc_t));
+
+ crypto_rand(n->identity, sizeof(n->identity));
+ n->rs = tor_malloc_zero(sizeof(routerstatus_t));
+
+ memcpy(n->rs->identity_digest, n->identity, DIGEST_LEN);
+
+ n->is_running = n->is_valid = n->is_fast = n->is_stable = 1;
+
+ /* Note: all these guards have the same address, so you'll need to
+ * disable EnforceDistinctSubnets when a restriction is applied. */
+ n->rs->addr = 0x04020202;
+ n->rs->or_port = 1234;
+ n->rs->is_v2_dir = 1;
+ n->rs->has_bandwidth = 1;
+ n->rs->bandwidth_kb = 30;
+
+ /* Make a random nickname for each node */
+ {
+ char nickname_binary[8];
+ crypto_rand(nickname_binary, sizeof(nickname_binary));
+ base64_encode(n->rs->nickname, sizeof(n->rs->nickname),
+ nickname_binary, sizeof(nickname_binary), 0);
+ }
+
+ /* Call half of the nodes a possible guard. */
+ if (i % 2 == 0) {
+ n->is_possible_guard = 1;
+ n->rs->guardfraction_percentage = 100;
+ n->rs->has_guardfraction = 1;
+ }
+
+ smartlist_add(big_fake_net_nodes, n);
+ }
- /* Setup fake state */
dummy_state = tor_malloc_zero(sizeof(or_state_t));
+ dummy_consensus = tor_malloc_zero(sizeof(networkstatus_t));
+ dummy_consensus->valid_after = approx_time() - 3600;
+ dummy_consensus->valid_until = approx_time() + 3600;
+
+ MOCK(nodelist_get_list, bfn_mock_nodelist_get_list);
+ MOCK(node_get_by_id, bfn_mock_node_get_by_id);
MOCK(get_or_state,
get_or_state_replacement);
-
- /* Setup fake routerlist. */
- helper_setup_fake_routerlist();
-
+ MOCK(networkstatus_get_live_consensus,
+ bfn_mock_networkstatus_get_live_consensus);
/* Return anything but NULL (it's interpreted as test fail) */
- return dummy_state;
+ return (void*)testcase;
+}
+
+static time_t
+mock_randomize_time_no_randomization(time_t a, time_t b)
+{
+ (void) b;
+ return a;
}
static or_options_t mocked_options;
@@ -80,796 +179,2696 @@ mock_get_options(void)
return &mocked_options;
}
-/** Test choose_random_entry() with none of our routers being guard nodes. */
+#define TEST_IPV4_ADDR "123.45.67.89"
+#define TEST_IPV6_ADDR "[1234:5678:90ab:cdef::]"
+
static void
-test_choose_random_entry_no_guards(void *arg)
+test_node_preferred_orport(void *arg)
{
- const node_t *chosen_entry = NULL;
-
- (void) arg;
+ (void)arg;
+ tor_addr_t ipv4_addr;
+ const uint16_t ipv4_port = 4444;
+ tor_addr_t ipv6_addr;
+ const uint16_t ipv6_port = 6666;
+ routerinfo_t node_ri;
+ node_t node;
+ tor_addr_port_t ap;
+ /* Setup options */
+ memset(&mocked_options, 0, sizeof(mocked_options));
+ /* We don't test ClientPreferIPv6ORPort here, because it's used in
+ * nodelist_set_consensus to setup node.ipv6_preferred, which we set
+ * directly. */
MOCK(get_options, mock_get_options);
- /* Check that we get a guard if it passes preferred
- * address settings */
- memset(&mocked_options, 0, sizeof(mocked_options));
+ /* Setup IP addresses */
+ tor_addr_parse(&ipv4_addr, TEST_IPV4_ADDR);
+ tor_addr_parse(&ipv6_addr, TEST_IPV6_ADDR);
+
+ /* Setup node_ri */
+ memset(&node_ri, 0, sizeof(node_ri));
+ node_ri.addr = tor_addr_to_ipv4h(&ipv4_addr);
+ node_ri.or_port = ipv4_port;
+ tor_addr_copy(&node_ri.ipv6_addr, &ipv6_addr);
+ node_ri.ipv6_orport = ipv6_port;
+
+ /* Setup node */
+ memset(&node, 0, sizeof(node));
+ node.ri = &node_ri;
+
+ /* Check the preferred address is IPv4 if we're only using IPv4, regardless
+ * of whether we prefer it or not */
mocked_options.ClientUseIPv4 = 1;
- mocked_options.ClientPreferIPv6ORPort = 0;
+ mocked_options.ClientUseIPv6 = 0;
+ node.ipv6_preferred = 0;
+ node_get_pref_orport(&node, &ap);
+ tt_assert(tor_addr_eq(&ap.addr, &ipv4_addr));
+ tt_assert(ap.port == ipv4_port);
- /* Try to pick an entry even though none of our routers are guards. */
- chosen_entry = choose_random_entry(NULL);
+ node.ipv6_preferred = 1;
+ node_get_pref_orport(&node, &ap);
+ tt_assert(tor_addr_eq(&ap.addr, &ipv4_addr));
+ tt_assert(ap.port == ipv4_port);
- /* Unintuitively, we actually pick a random node as our entry,
- because router_choose_random_node() relaxes its constraints if it
- can't find a proper entry guard. */
- tt_assert(chosen_entry);
+ /* Check the preferred address is IPv4 if we're using IPv4 and IPv6, but
+ * don't prefer the IPv6 address */
+ mocked_options.ClientUseIPv4 = 1;
+ mocked_options.ClientUseIPv6 = 1;
+ node.ipv6_preferred = 0;
+ node_get_pref_orport(&node, &ap);
+ tt_assert(tor_addr_eq(&ap.addr, &ipv4_addr));
+ tt_assert(ap.port == ipv4_port);
- /* And with the other IP version active */
+ /* Check the preferred address is IPv6 if we prefer it and
+ * ClientUseIPv6 is 1, regardless of ClientUseIPv4 */
+ mocked_options.ClientUseIPv4 = 1;
mocked_options.ClientUseIPv6 = 1;
- chosen_entry = choose_random_entry(NULL);
- tt_assert(chosen_entry);
+ node.ipv6_preferred = 1;
+ node_get_pref_orport(&node, &ap);
+ tt_assert(tor_addr_eq(&ap.addr, &ipv6_addr));
+ tt_assert(ap.port == ipv6_port);
- /* And with the preference on auto */
- mocked_options.ClientPreferIPv6ORPort = -1;
- chosen_entry = choose_random_entry(NULL);
- tt_assert(chosen_entry);
+ mocked_options.ClientUseIPv4 = 0;
+ node_get_pref_orport(&node, &ap);
+ tt_assert(tor_addr_eq(&ap.addr, &ipv6_addr));
+ tt_assert(ap.port == ipv6_port);
- /* Check that we don't get a guard if it doesn't pass mandatory address
- * settings */
- memset(&mocked_options, 0, sizeof(mocked_options));
+ /* Check the preferred address is IPv6 if we don't prefer it, but
+ * ClientUseIPv4 is 0 */
mocked_options.ClientUseIPv4 = 0;
- mocked_options.ClientPreferIPv6ORPort = 0;
+ mocked_options.ClientUseIPv6 = 1;
+ node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(&mocked_options);
+ node_get_pref_orport(&node, &ap);
+ tt_assert(tor_addr_eq(&ap.addr, &ipv6_addr));
+ tt_assert(ap.port == ipv6_port);
- chosen_entry = choose_random_entry(NULL);
+ done:
+ UNMOCK(get_options);
+}
- /* If we don't allow IPv4 at all, we don't get a guard*/
- tt_assert(!chosen_entry);
+static void
+test_entry_guard_describe(void *arg)
+{
+ (void)arg;
+ entry_guard_t g;
+ memset(&g, 0, sizeof(g));
+ strlcpy(g.nickname, "okefenokee", sizeof(g.nickname));
+ memcpy(g.identity, "theforestprimeval---", DIGEST_LEN);
- /* Check that we get a guard if it passes allowed but not preferred address
- * settings */
- memset(&mocked_options, 0, sizeof(mocked_options));
- mocked_options.ClientUseIPv4 = 1;
- mocked_options.ClientUseIPv6 = 1;
- mocked_options.ClientPreferIPv6ORPort = 1;
+ tt_str_op(entry_guard_describe(&g), OP_EQ,
+ "okefenokee ($746865666F726573747072696D6576616C2D2D2D)");
- chosen_entry = choose_random_entry(NULL);
- tt_assert(chosen_entry);
+ done:
+ ;
+}
- /* Check that we get a guard if it passes preferred address settings when
- * they're auto */
- memset(&mocked_options, 0, sizeof(mocked_options));
- mocked_options.ClientUseIPv4 = 1;
- mocked_options.ClientPreferIPv6ORPort = -1;
+static void
+test_entry_guard_randomize_time(void *arg)
+{
+ const time_t now = 1479153573;
+ const int delay = 86400;
+ const int N = 1000;
+ (void)arg;
- chosen_entry = choose_random_entry(NULL);
- tt_assert(chosen_entry);
+ time_t t;
+ int i;
+ for (i = 0; i < N; ++i) {
+ t = randomize_time(now, delay);
+ tt_int_op(t, OP_LE, now);
+ tt_int_op(t, OP_GE, now-delay);
+ }
- /* And with IPv6 active */
- mocked_options.ClientUseIPv6 = 1;
+ /* now try the corner cases */
+ for (i = 0; i < N; ++i) {
+ t = randomize_time(100, delay);
+ tt_int_op(t, OP_GE, 1);
+ tt_int_op(t, OP_LE, 100);
- chosen_entry = choose_random_entry(NULL);
- tt_assert(chosen_entry);
+ t = randomize_time(0, delay);
+ tt_int_op(t, OP_EQ, 1);
+ }
done:
- memset(&mocked_options, 0, sizeof(mocked_options));
- UNMOCK(get_options);
+ ;
}
-/** Test choose_random_entry() with only one of our routers being a
- guard node. */
static void
-test_choose_random_entry_one_possible_guard(void *arg)
+test_entry_guard_encode_for_state_minimal(void *arg)
{
- const node_t *chosen_entry = NULL;
- node_t *the_guard = NULL;
- smartlist_t *our_nodelist = NULL;
-
(void) arg;
+ entry_guard_t *eg = tor_malloc_zero(sizeof(entry_guard_t));
- MOCK(get_options, mock_get_options);
+ eg->selection_name = tor_strdup("wubwub");
+ memcpy(eg->identity, "plurpyflurpyslurpydo", DIGEST_LEN);
+ eg->sampled_on_date = 1479081600;
+ eg->confirmed_idx = -1;
- /* Set one of the nodes to be a guard. */
- our_nodelist = nodelist_get_list();
- the_guard = smartlist_get(our_nodelist, 4); /* chosen by fair dice roll */
- the_guard->is_possible_guard = 1;
+ char *s = NULL;
+ s = entry_guard_encode_for_state(eg);
- /* Check that we get the guard if it passes preferred
- * address settings */
- memset(&mocked_options, 0, sizeof(mocked_options));
- mocked_options.ClientUseIPv4 = 1;
- mocked_options.ClientPreferIPv6ORPort = 0;
+ tt_str_op(s, OP_EQ,
+ "in=wubwub "
+ "rsa_id=706C75727079666C75727079736C75727079646F "
+ "sampled_on=2016-11-14T00:00:00 "
+ "listed=0");
- /* Pick an entry. Make sure we pick the node we marked as guard. */
- chosen_entry = choose_random_entry(NULL);
- tt_ptr_op(chosen_entry, OP_EQ, the_guard);
+ done:
+ entry_guard_free(eg);
+ tor_free(s);
+}
- /* And with the other IP version active */
- mocked_options.ClientUseIPv6 = 1;
- chosen_entry = choose_random_entry(NULL);
- tt_ptr_op(chosen_entry, OP_EQ, the_guard);
+static void
+test_entry_guard_encode_for_state_maximal(void *arg)
+{
+ (void) arg;
+ entry_guard_t *eg = tor_malloc_zero(sizeof(entry_guard_t));
+
+ strlcpy(eg->nickname, "Fred", sizeof(eg->nickname));
+ eg->selection_name = tor_strdup("default");
+ memcpy(eg->identity, "plurpyflurpyslurpydo", DIGEST_LEN);
+ eg->bridge_addr = tor_malloc_zero(sizeof(tor_addr_port_t));
+ tor_addr_from_ipv4h(&eg->bridge_addr->addr, 0x08080404);
+ eg->bridge_addr->port = 9999;
+ eg->sampled_on_date = 1479081600;
+ eg->sampled_by_version = tor_strdup("1.2.3");
+ eg->unlisted_since_date = 1479081645;
+ eg->currently_listed = 1;
+ eg->confirmed_on_date = 1479081690;
+ eg->confirmed_idx = 333;
+ eg->extra_state_fields = tor_strdup("and the green grass grew all around");
+
+ char *s = NULL;
+ s = entry_guard_encode_for_state(eg);
+
+ tt_str_op(s, OP_EQ,
+ "in=default "
+ "rsa_id=706C75727079666C75727079736C75727079646F "
+ "bridge_addr=8.8.4.4:9999 "
+ "nickname=Fred "
+ "sampled_on=2016-11-14T00:00:00 "
+ "sampled_by=1.2.3 "
+ "unlisted_since=2016-11-14T00:00:45 "
+ "listed=1 "
+ "confirmed_on=2016-11-14T00:01:30 "
+ "confirmed_idx=333 "
+ "and the green grass grew all around");
- /* And with the preference on auto */
- mocked_options.ClientPreferIPv6ORPort = -1;
- chosen_entry = choose_random_entry(NULL);
- tt_ptr_op(chosen_entry, OP_EQ, the_guard);
+ done:
+ entry_guard_free(eg);
+ tor_free(s);
+}
- /* Check that we don't get a guard if it doesn't pass mandatory address
- * settings */
- memset(&mocked_options, 0, sizeof(mocked_options));
- mocked_options.ClientUseIPv4 = 0;
- mocked_options.ClientPreferIPv6ORPort = 0;
+static void
+test_entry_guard_parse_from_state_minimal(void *arg)
+{
+ (void)arg;
+ char *mem_op_hex_tmp = NULL;
+ entry_guard_t *eg = NULL;
+ time_t t = approx_time();
+
+ eg = entry_guard_parse_from_state(
+ "in=default_plus "
+ "rsa_id=596f75206d6179206e656564206120686f626279");
+ tt_assert(eg);
+
+ tt_str_op(eg->selection_name, OP_EQ, "default_plus");
+ test_mem_op_hex(eg->identity, OP_EQ,
+ "596f75206d6179206e656564206120686f626279");
+ tt_str_op(eg->nickname, OP_EQ, "$596F75206D6179206E656564206120686F626279");
+ tt_ptr_op(eg->bridge_addr, OP_EQ, NULL);
+ tt_i64_op(eg->sampled_on_date, OP_GE, t);
+ tt_i64_op(eg->sampled_on_date, OP_LE, t+86400);
+ tt_i64_op(eg->unlisted_since_date, OP_EQ, 0);
+ tt_ptr_op(eg->sampled_by_version, OP_EQ, NULL);
+ tt_int_op(eg->currently_listed, OP_EQ, 0);
+ tt_i64_op(eg->confirmed_on_date, OP_EQ, 0);
+ tt_int_op(eg->confirmed_idx, OP_EQ, -1);
+
+ tt_int_op(eg->last_tried_to_connect, OP_EQ, 0);
+ tt_int_op(eg->is_reachable, OP_EQ, GUARD_REACHABLE_MAYBE);
- chosen_entry = choose_random_entry(NULL);
+ done:
+ entry_guard_free(eg);
+ tor_free(mem_op_hex_tmp);
+}
+
+static void
+test_entry_guard_parse_from_state_maximal(void *arg)
+{
+ (void)arg;
+ char *mem_op_hex_tmp = NULL;
+ entry_guard_t *eg = NULL;
+
+ eg = entry_guard_parse_from_state(
+ "in=fred "
+ "rsa_id=706C75727079666C75727079736C75727079646F "
+ "bridge_addr=[1::3]:9999 "
+ "nickname=Fred "
+ "sampled_on=2016-11-14T00:00:00 "
+ "sampled_by=1.2.3 "
+ "unlisted_since=2016-11-14T00:00:45 "
+ "listed=1 "
+ "confirmed_on=2016-11-14T00:01:30 "
+ "confirmed_idx=333 "
+ "and the green grass grew all around "
+ "rsa_id=all,around");
+ tt_assert(eg);
+
+ test_mem_op_hex(eg->identity, OP_EQ,
+ "706C75727079666C75727079736C75727079646F");
+ tt_str_op(fmt_addr(&eg->bridge_addr->addr), OP_EQ, "1::3");
+ tt_int_op(eg->bridge_addr->port, OP_EQ, 9999);
+ tt_str_op(eg->nickname, OP_EQ, "Fred");
+ tt_i64_op(eg->sampled_on_date, OP_EQ, 1479081600);
+ tt_i64_op(eg->unlisted_since_date, OP_EQ, 1479081645);
+ tt_str_op(eg->sampled_by_version, OP_EQ, "1.2.3");
+ tt_int_op(eg->currently_listed, OP_EQ, 1);
+ tt_i64_op(eg->confirmed_on_date, OP_EQ, 1479081690);
+ tt_int_op(eg->confirmed_idx, OP_EQ, 333);
+ tt_str_op(eg->extra_state_fields, OP_EQ,
+ "and the green grass grew all around rsa_id=all,around");
+
+ tt_int_op(eg->last_tried_to_connect, OP_EQ, 0);
+ tt_int_op(eg->is_reachable, OP_EQ, GUARD_REACHABLE_MAYBE);
- /* If we don't allow IPv4 at all, we don't get a guard*/
- tt_assert(!chosen_entry);
+ done:
+ entry_guard_free(eg);
+ tor_free(mem_op_hex_tmp);
+}
- /* Check that we get a node if it passes allowed but not preferred
- * address settings */
- memset(&mocked_options, 0, sizeof(mocked_options));
- mocked_options.ClientUseIPv4 = 1;
- mocked_options.ClientUseIPv6 = 1;
- mocked_options.ClientPreferIPv6ORPort = 1;
+static void
+test_entry_guard_parse_from_state_failure(void *arg)
+{
+ (void)arg;
+ entry_guard_t *eg = NULL;
+
+ /* no selection */
+ eg = entry_guard_parse_from_state(
+ "rsa_id=596f75206d6179206e656564206120686f626270");
+ tt_ptr_op(eg, OP_EQ, NULL);
+
+ /* no RSA ID. */
+ eg = entry_guard_parse_from_state("in=default nickname=Fred");
+ tt_ptr_op(eg, OP_EQ, NULL);
+
+ /* Bad RSA ID: bad character. */
+ eg = entry_guard_parse_from_state(
+ "in=default "
+ "rsa_id=596f75206d6179206e656564206120686f62627q");
+ tt_ptr_op(eg, OP_EQ, NULL);
+
+ /* Bad RSA ID: too long.*/
+ eg = entry_guard_parse_from_state(
+ "in=default "
+ "rsa_id=596f75206d6179206e656564206120686f6262703");
+ tt_ptr_op(eg, OP_EQ, NULL);
+
+ /* Bad RSA ID: too short.*/
+ eg = entry_guard_parse_from_state(
+ "in=default "
+ "rsa_id=596f75206d6179206e65656420612");
+ tt_ptr_op(eg, OP_EQ, NULL);
- chosen_entry = choose_random_entry(NULL);
+ done:
+ entry_guard_free(eg);
+}
- /* We disable the guard check and the preferred address check at the same
- * time, so we can't be sure we get the guard */
- tt_assert(chosen_entry);
+static void
+test_entry_guard_parse_from_state_partial_failure(void *arg)
+{
+ (void)arg;
+ char *mem_op_hex_tmp = NULL;
+ entry_guard_t *eg = NULL;
+ time_t t = approx_time();
+
+ eg = entry_guard_parse_from_state(
+ "in=default "
+ "rsa_id=706C75727079666C75727079736C75727079646F "
+ "bridge_addr=1.2.3.3.4:5 "
+ "nickname=FredIsANodeWithAStrangeNicknameThatIsTooLong "
+ "sampled_on=2016-11-14T00:00:99 "
+ "sampled_by=1.2.3 stuff in the middle "
+ "unlisted_since=2016-xx-14T00:00:45 "
+ "listed=0 "
+ "confirmed_on=2016-11-14T00:01:30zz "
+ "confirmed_idx=idx "
+ "and the green grass grew all around "
+ "rsa_id=all,around");
+ tt_assert(eg);
+
+ test_mem_op_hex(eg->identity, OP_EQ,
+ "706C75727079666C75727079736C75727079646F");
+ tt_str_op(eg->nickname, OP_EQ, "FredIsANodeWithAStrangeNicknameThatIsTooL");
+ tt_ptr_op(eg->bridge_addr, OP_EQ, NULL);
+ tt_i64_op(eg->sampled_on_date, OP_EQ, t);
+ tt_i64_op(eg->unlisted_since_date, OP_EQ, 0);
+ tt_str_op(eg->sampled_by_version, OP_EQ, "1.2.3");
+ tt_int_op(eg->currently_listed, OP_EQ, 0);
+ tt_i64_op(eg->confirmed_on_date, OP_EQ, 0);
+ tt_int_op(eg->confirmed_idx, OP_EQ, -1);
+ tt_str_op(eg->extra_state_fields, OP_EQ,
+ "stuff in the middle and the green grass grew all around "
+ "rsa_id=all,around");
+
+ tt_int_op(eg->last_tried_to_connect, OP_EQ, 0);
+ tt_int_op(eg->is_reachable, OP_EQ, GUARD_REACHABLE_MAYBE);
- /* Check that we get a node if it is allowed but not preferred when settings
- * are auto */
- memset(&mocked_options, 0, sizeof(mocked_options));
- mocked_options.ClientUseIPv4 = 1;
- mocked_options.ClientPreferIPv6ORPort = -1;
+ done:
+ entry_guard_free(eg);
+ tor_free(mem_op_hex_tmp);
+}
- chosen_entry = choose_random_entry(NULL);
+static int
+mock_entry_guard_is_listed(guard_selection_t *gs, const entry_guard_t *guard)
+{
+ (void)gs;
+ (void)guard;
+ return 1;
+}
- /* We disable the guard check and the preferred address check at the same
- * time, so we can't be sure we get the guard */
- tt_assert(chosen_entry);
+static void
+test_entry_guard_parse_from_state_full(void *arg)
+{
+ (void)arg;
+ /* Here's a state I made while testing. The identities and locations for
+ * the bridges are redacted. */
+ const char STATE[] =
+ "Guard in=default rsa_id=214F44BD5B638E8C817D47FF7C97397790BF0345 "
+ "nickname=TotallyNinja sampled_on=2016-11-12T19:32:49 "
+ "sampled_by=0.3.0.0-alpha-dev "
+ "listed=1\n"
+ "Guard in=default rsa_id=052900AB0EA3ED54BAB84AE8A99E74E8693CE2B2 "
+ "nickname=5OfNovember sampled_on=2016-11-20T04:32:05 "
+ "sampled_by=0.3.0.0-alpha-dev "
+ "listed=1 confirmed_on=2016-11-22T08:13:28 confirmed_idx=0 "
+ "pb_circ_attempts=4.000000 pb_circ_successes=2.000000 "
+ "pb_successful_circuits_closed=2.000000\n"
+ "Guard in=default rsa_id=7B700C0C207EBD0002E00F499BE265519AC3C25A "
+ "nickname=dc6jgk11 sampled_on=2016-11-28T11:50:13 "
+ "sampled_by=0.3.0.0-alpha-dev "
+ "listed=1 confirmed_on=2016-11-24T08:45:30 confirmed_idx=4 "
+ "pb_circ_attempts=5.000000 pb_circ_successes=5.000000 "
+ "pb_successful_circuits_closed=5.000000\n"
+ "Guard in=wobblesome rsa_id=7B700C0C207EBD0002E00F499BE265519AC3C25A "
+ "nickname=dc6jgk11 sampled_on=2016-11-28T11:50:13 "
+ "sampled_by=0.3.0.0-alpha-dev "
+ "listed=1\n"
+ "Guard in=default rsa_id=E9025AD60D86875D5F11548D536CC6AF60F0EF5E "
+ "nickname=maibrunn sampled_on=2016-11-25T22:36:38 "
+ "sampled_by=0.3.0.0-alpha-dev listed=1\n"
+ "Guard in=default rsa_id=DCD30B90BA3A792DA75DC54A327EF353FB84C38E "
+ "nickname=Unnamed sampled_on=2016-11-25T14:34:00 "
+ "sampled_by=0.3.0.0-alpha-dev listed=1\n"
+ "Guard in=bridges rsa_id=8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2E "
+ "bridge_addr=24.1.1.1:443 sampled_on=2016-11-25T06:44:14 "
+ "sampled_by=0.3.0.0-alpha-dev listed=1 "
+ "confirmed_on=2016-11-29T10:36:06 confirmed_idx=0 "
+ "pb_circ_attempts=8.000000 pb_circ_successes=8.000000 "
+ "pb_successful_circuits_closed=13.000000\n"
+ "Guard in=bridges rsa_id=5800000000000000000000000000000000000000 "
+ "bridge_addr=37.218.246.143:28366 "
+ "sampled_on=2016-11-18T15:07:34 sampled_by=0.3.0.0-alpha-dev listed=1\n";
+
+ config_line_t *lines = NULL;
+ or_state_t *state = tor_malloc_zero(sizeof(or_state_t));
+ int r = config_get_lines(STATE, &lines, 0);
+ char *msg = NULL;
+ smartlist_t *text = smartlist_new();
+ char *joined = NULL;
- /* and with IPv6 active */
- mocked_options.ClientUseIPv6 = 1;
+ // 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;
+ MOCK(get_or_state,
+ get_or_state_replacement);
- chosen_entry = choose_random_entry(NULL);
- tt_assert(chosen_entry);
+ tt_int_op(r, OP_EQ, 0);
+ tt_assert(lines);
+
+ state->Guard = lines;
+
+ /* Try it first without setting the result. */
+ r = entry_guards_parse_state(state, 0, &msg);
+ tt_int_op(r, OP_EQ, 0);
+ guard_selection_t *gs_br =
+ get_guard_selection_by_name("bridges", GS_TYPE_BRIDGE, 0);
+ tt_ptr_op(gs_br, OP_EQ, NULL);
+
+ r = entry_guards_parse_state(state, 1, &msg);
+ tt_int_op(r, OP_EQ, 0);
+ gs_br = get_guard_selection_by_name("bridges", GS_TYPE_BRIDGE, 0);
+ guard_selection_t *gs_df =
+ get_guard_selection_by_name("default", GS_TYPE_NORMAL, 0);
+ guard_selection_t *gs_wb =
+ get_guard_selection_by_name("wobblesome", GS_TYPE_NORMAL, 0);
+
+ tt_assert(gs_br);
+ tt_assert(gs_df);
+ tt_assert(gs_wb);
+
+ tt_int_op(smartlist_len(gs_df->sampled_entry_guards), OP_EQ, 5);
+ tt_int_op(smartlist_len(gs_br->sampled_entry_guards), OP_EQ, 2);
+ tt_int_op(smartlist_len(gs_wb->sampled_entry_guards), OP_EQ, 1);
+
+ /* Try again; make sure it doesn't double-add the guards. */
+ r = entry_guards_parse_state(state, 1, &msg);
+ tt_int_op(r, OP_EQ, 0);
+ gs_br = get_guard_selection_by_name("bridges", GS_TYPE_BRIDGE, 0);
+ gs_df = get_guard_selection_by_name("default", GS_TYPE_NORMAL, 0);
+ tt_assert(gs_br);
+ tt_assert(gs_df);
+ tt_int_op(smartlist_len(gs_df->sampled_entry_guards), OP_EQ, 5);
+ tt_int_op(smartlist_len(gs_br->sampled_entry_guards), OP_EQ, 2);
+
+ /* Re-encode; it should be the same... almost. */
+ {
+ /* (Make a guard nonpersistent first) */
+ entry_guard_t *g = smartlist_get(gs_df->sampled_entry_guards, 0);
+ g->is_persistent = 0;
+ }
+ config_free_lines(lines);
+ lines = state->Guard = NULL; // to prevent double-free.
+ entry_guards_update_state(state);
+ tt_assert(state->Guard);
+ lines = state->Guard;
+
+ config_line_t *ln;
+ for (ln = lines; ln; ln = ln->next) {
+ smartlist_add_asprintf(text, "%s %s\n",ln->key, ln->value);
+ }
+ joined = smartlist_join_strings(text, "", 0, NULL);
+ tt_str_op(joined, OP_EQ,
+ "Guard in=default rsa_id=052900AB0EA3ED54BAB84AE8A99E74E8693CE2B2 "
+ "nickname=5OfNovember sampled_on=2016-11-20T04:32:05 "
+ "sampled_by=0.3.0.0-alpha-dev "
+ "listed=1 confirmed_on=2016-11-22T08:13:28 confirmed_idx=0 "
+ "pb_circ_attempts=4.000000 pb_circ_successes=2.000000 "
+ "pb_successful_circuits_closed=2.000000\n"
+ "Guard in=default rsa_id=7B700C0C207EBD0002E00F499BE265519AC3C25A "
+ "nickname=dc6jgk11 sampled_on=2016-11-28T11:50:13 "
+ "sampled_by=0.3.0.0-alpha-dev "
+ "listed=1 confirmed_on=2016-11-24T08:45:30 confirmed_idx=1 "
+ "pb_circ_attempts=5.000000 pb_circ_successes=5.000000 "
+ "pb_successful_circuits_closed=5.000000\n"
+ "Guard in=default rsa_id=E9025AD60D86875D5F11548D536CC6AF60F0EF5E "
+ "nickname=maibrunn sampled_on=2016-11-25T22:36:38 "
+ "sampled_by=0.3.0.0-alpha-dev listed=1\n"
+ "Guard in=default rsa_id=DCD30B90BA3A792DA75DC54A327EF353FB84C38E "
+ "nickname=Unnamed sampled_on=2016-11-25T14:34:00 "
+ "sampled_by=0.3.0.0-alpha-dev listed=1\n"
+ "Guard in=wobblesome rsa_id=7B700C0C207EBD0002E00F499BE265519AC3C25A "
+ "nickname=dc6jgk11 sampled_on=2016-11-28T11:50:13 "
+ "sampled_by=0.3.0.0-alpha-dev "
+ "listed=1\n"
+ "Guard in=bridges rsa_id=8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2E "
+ "bridge_addr=24.1.1.1:443 sampled_on=2016-11-25T06:44:14 "
+ "sampled_by=0.3.0.0-alpha-dev listed=1 "
+ "confirmed_on=2016-11-29T10:36:06 confirmed_idx=0 "
+ "pb_circ_attempts=8.000000 pb_circ_successes=8.000000 "
+ "pb_successful_circuits_closed=13.000000\n"
+ "Guard in=bridges rsa_id=5800000000000000000000000000000000000000 "
+ "bridge_addr=37.218.246.143:28366 "
+ "sampled_on=2016-11-18T15:07:34 sampled_by=0.3.0.0-alpha-dev listed=1\n");
done:
- memset(&mocked_options, 0, sizeof(mocked_options));
- UNMOCK(get_options);
+ config_free_lines(lines);
+ tor_free(state);
+ tor_free(msg);
+ UNMOCK(get_or_state);
+ UNMOCK(entry_guard_is_listed);
+ SMARTLIST_FOREACH(text, char *, cp, tor_free(cp));
+ smartlist_free(text);
+ tor_free(joined);
}
-/** Helper to conduct tests for populate_live_entry_guards().
+static void
+test_entry_guard_parse_from_state_broken(void *arg)
+{
+ (void)arg;
+ /* Here's a variation on the previous state. Every line but the first is
+ * busted somehow. */
+ const char STATE[] =
+ /* Okay. */
+ "Guard in=default rsa_id=214F44BD5B638E8C817D47FF7C97397790BF0345 "
+ "nickname=TotallyNinja sampled_on=2016-11-12T19:32:49 "
+ "sampled_by=0.3.0.0-alpha-dev "
+ "listed=1\n"
+ /* No selection listed. */
+ "Guard rsa_id=052900AB0EA3ED54BAB84AE8A99E74E8693CE2B2 "
+ "nickname=5OfNovember sampled_on=2016-11-20T04:32:05 "
+ "sampled_by=0.3.0.0-alpha-dev "
+ "listed=1 confirmed_on=2016-11-22T08:13:28 confirmed_idx=0 "
+ "pb_circ_attempts=4.000000 pb_circ_successes=2.000000 "
+ "pb_successful_circuits_closed=2.000000\n"
+ /* Selection is "legacy"!! */
+ "Guard in=legacy rsa_id=7B700C0C207EBD0002E00F499BE265519AC3C25A "
+ "nickname=dc6jgk11 sampled_on=2016-11-28T11:50:13 "
+ "sampled_by=0.3.0.0-alpha-dev "
+ "listed=1 confirmed_on=2016-11-24T08:45:30 confirmed_idx=4 "
+ "pb_circ_attempts=5.000000 pb_circ_successes=5.000000 "
+ "pb_successful_circuits_closed=5.000000\n";
+
+ config_line_t *lines = NULL;
+ or_state_t *state = tor_malloc_zero(sizeof(or_state_t));
+ int r = config_get_lines(STATE, &lines, 0);
+ char *msg = NULL;
+
+ dummy_state = state;
+ MOCK(get_or_state,
+ get_or_state_replacement);
+
+ tt_int_op(r, OP_EQ, 0);
+ tt_assert(lines);
- This test adds some entry guards to our list, and then tests
- populate_live_entry_guards() to mke sure it filters them correctly.
+ state->Guard = lines;
+
+ /* First, no-set case. we should get an error. */
+ r = entry_guards_parse_state(state, 0, &msg);
+ tt_int_op(r, OP_LT, 0);
+ tt_ptr_op(msg, OP_NE, NULL);
+ /* And we shouldn't have made anything. */
+ guard_selection_t *gs_df =
+ get_guard_selection_by_name("default", GS_TYPE_NORMAL, 0);
+ tt_ptr_op(gs_df, OP_EQ, NULL);
+ tor_free(msg);
+
+ /* Now see about the set case (which shouldn't happen IRL) */
+ r = entry_guards_parse_state(state, 1, &msg);
+ tt_int_op(r, OP_LT, 0);
+ tt_ptr_op(msg, OP_NE, NULL);
+ gs_df = get_guard_selection_by_name("default", GS_TYPE_NORMAL, 0);
+ tt_ptr_op(gs_df, OP_NE, NULL);
+ tt_int_op(smartlist_len(gs_df->sampled_entry_guards), OP_EQ, 1);
+
+ done:
+ config_free_lines(lines);
+ tor_free(state);
+ tor_free(msg);
+ UNMOCK(get_or_state);
+}
- <b>num_needed</b> is the number of guard nodes we support. It's
- configurable to make sure we function properly with 1 or 3 guard
- nodes configured.
-*/
static void
-populate_live_entry_guards_test_helper(int num_needed)
+test_entry_guard_get_guard_selection_by_name(void *arg)
{
- smartlist_t *our_nodelist = NULL;
- smartlist_t *live_entry_guards = smartlist_new();
- const smartlist_t *all_entry_guards = get_entry_guards();
- or_options_t *options = get_options_mutable();
- int retval;
+ (void)arg;
+ guard_selection_t *gs1, *gs2, *gs3;
+
+ gs1 = get_guard_selection_by_name("unlikely", GS_TYPE_NORMAL, 0);
+ tt_ptr_op(gs1, OP_EQ, NULL);
+ gs1 = get_guard_selection_by_name("unlikely", GS_TYPE_NORMAL, 1);
+ tt_ptr_op(gs1, OP_NE, NULL);
+ gs2 = get_guard_selection_by_name("unlikely", GS_TYPE_NORMAL, 1);
+ tt_assert(gs2 == gs1);
+ gs2 = get_guard_selection_by_name("unlikely", GS_TYPE_NORMAL, 0);
+ tt_assert(gs2 == gs1);
+
+ gs2 = get_guard_selection_by_name("implausible", GS_TYPE_NORMAL, 0);
+ tt_ptr_op(gs2, OP_EQ, NULL);
+ gs2 = get_guard_selection_by_name("implausible", GS_TYPE_NORMAL, 1);
+ tt_ptr_op(gs2, OP_NE, NULL);
+ tt_assert(gs2 != gs1);
+ gs3 = get_guard_selection_by_name("implausible", GS_TYPE_NORMAL, 0);
+ tt_assert(gs3 == gs2);
+
+ gs3 = get_guard_selection_by_name("default", GS_TYPE_NORMAL, 0);
+ tt_ptr_op(gs3, OP_EQ, NULL);
+ gs3 = get_guard_selection_by_name("default", GS_TYPE_NORMAL, 1);
+ tt_ptr_op(gs3, OP_NE, NULL);
+ tt_assert(gs3 != gs2);
+ tt_assert(gs3 != gs1);
+ tt_assert(gs3 == get_guard_selection_info());
+
+ done:
+ entry_guards_free_all();
+}
- /* Set NumEntryGuards to the provided number. */
- options->NumEntryGuards = num_needed;
- tt_int_op(num_needed, OP_EQ, decide_num_guards(options, 0));
-
- /* The global entry guards smartlist should be empty now. */
- tt_int_op(smartlist_len(all_entry_guards), OP_EQ, 0);
-
- /* Walk the nodelist and add all nodes as entry guards. */
- our_nodelist = nodelist_get_list();
- tt_int_op(smartlist_len(our_nodelist), OP_EQ, HELPER_NUMBER_OF_DESCRIPTORS);
-
- SMARTLIST_FOREACH_BEGIN(our_nodelist, const node_t *, node) {
- const node_t *node_tmp;
- node_tmp = add_an_entry_guard(node, 0, 1, 0, 0);
- tt_assert(node_tmp);
- } SMARTLIST_FOREACH_END(node);
-
- /* Make sure the nodes were added as entry guards. */
- tt_int_op(smartlist_len(all_entry_guards), OP_EQ,
- HELPER_NUMBER_OF_DESCRIPTORS);
-
- /* Ensure that all the possible entry guards are enough to satisfy us. */
- tt_int_op(smartlist_len(all_entry_guards), OP_GE, num_needed);
-
- /* Walk the entry guard list for some sanity checking */
- SMARTLIST_FOREACH_BEGIN(all_entry_guards, const entry_guard_t *, entry) {
- /* Since we called add_an_entry_guard() with 'for_discovery' being
- False, all guards should have made_contact enabled. */
- tt_int_op(entry->made_contact, OP_EQ, 1);
-
- } SMARTLIST_FOREACH_END(entry);
-
- /* First, try to get some fast guards. This should fail. */
- retval = populate_live_entry_guards(live_entry_guards,
- all_entry_guards,
- NULL,
- NO_DIRINFO, /* Don't care about DIRINFO*/
- 0, 0,
- 1); /* We want fast guard! */
- tt_int_op(retval, OP_EQ, 0);
- tt_int_op(smartlist_len(live_entry_guards), OP_EQ, 0);
-
- /* Now try to get some stable guards. This should fail too. */
- retval = populate_live_entry_guards(live_entry_guards,
- all_entry_guards,
- NULL,
- NO_DIRINFO,
- 0,
- 1, /* We want stable guard! */
- 0);
- tt_int_op(retval, OP_EQ, 0);
- tt_int_op(smartlist_len(live_entry_guards), OP_EQ, 0);
-
- /* Now try to get any guard we can find. This should succeed. */
- retval = populate_live_entry_guards(live_entry_guards,
- all_entry_guards,
- NULL,
- NO_DIRINFO,
- 0, 0, 0); /* No restrictions! */
-
- /* Since we had more than enough guards in 'all_entry_guards', we
- should have added 'num_needed' of them to live_entry_guards.
- 'retval' should be 1 since we now have enough live entry guards
- to pick one. */
- tt_int_op(retval, OP_EQ, 1);
- tt_int_op(smartlist_len(live_entry_guards), OP_EQ, num_needed);
-
- done:
- smartlist_free(live_entry_guards);
-}
-
-/* Test populate_live_entry_guards() for 1 guard node. */
-static void
-test_populate_live_entry_guards_1guard(void *arg)
+static void
+test_entry_guard_choose_selection_initial(void *arg)
{
- (void) arg;
+ /* Tests for picking our initial guard selection (based on having had
+ * no previous selection */
+ (void)arg;
+ guard_selection_type_t type = GS_TYPE_INFER;
+ const char *name = choose_guard_selection(get_options(),
+ dummy_consensus, NULL, &type);
+ tt_str_op(name, OP_EQ, "default");
+ tt_int_op(type, OP_EQ, GS_TYPE_NORMAL);
+
+ /* If we're using bridges, we get the bridge selection. */
+ get_options_mutable()->UseBridges = 1;
+ name = choose_guard_selection(get_options(),
+ dummy_consensus, NULL, &type);
+ tt_str_op(name, OP_EQ, "bridges");
+ tt_int_op(type, OP_EQ, GS_TYPE_BRIDGE);
+ get_options_mutable()->UseBridges = 0;
+
+ /* If we discard >99% of our guards, though, we should be in the restricted
+ * set. */
+ tt_assert(get_options_mutable()->EntryNodes == NULL);
+ get_options_mutable()->EntryNodes = routerset_new();
+ routerset_parse(get_options_mutable()->EntryNodes, "1.0.0.0/8", "foo");
+ name = choose_guard_selection(get_options(),
+ dummy_consensus, NULL, &type);
+ tt_str_op(name, OP_EQ, "restricted");
+ tt_int_op(type, OP_EQ, GS_TYPE_RESTRICTED);
- populate_live_entry_guards_test_helper(1);
+ done:
+ ;
}
-/* Test populate_live_entry_guards() for 3 guard nodes. */
static void
-test_populate_live_entry_guards_3guards(void *arg)
+test_entry_guard_add_single_guard(void *arg)
{
- (void) arg;
+ (void)arg;
+ guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
+
+ /* 1: Add a single guard to the sample. */
+ node_t *n1 = smartlist_get(big_fake_net_nodes, 0);
+ time_t now = approx_time();
+ tt_assert(n1->is_possible_guard == 1);
+ entry_guard_t *g1 = entry_guard_add_to_sample(gs, n1);
+ tt_assert(g1);
+
+ /* Make sure its fields look right. */
+ tt_mem_op(n1->identity, OP_EQ, g1->identity, DIGEST_LEN);
+ tt_i64_op(g1->sampled_on_date, OP_GE, now - 12*86400);
+ tt_i64_op(g1->sampled_on_date, OP_LE, now);
+ tt_str_op(g1->sampled_by_version, OP_EQ, VERSION);
+ tt_uint_op(g1->currently_listed, OP_EQ, 1);
+ tt_i64_op(g1->confirmed_on_date, OP_EQ, 0);
+ tt_int_op(g1->confirmed_idx, OP_EQ, -1);
+ tt_int_op(g1->last_tried_to_connect, OP_EQ, 0);
+ tt_uint_op(g1->is_reachable, OP_EQ, GUARD_REACHABLE_MAYBE);
+ tt_i64_op(g1->failing_since, OP_EQ, 0);
+ tt_uint_op(g1->is_filtered_guard, OP_EQ, 1);
+ tt_uint_op(g1->is_usable_filtered_guard, OP_EQ, 1);
+ tt_uint_op(g1->is_primary, OP_EQ, 0);
+ tt_ptr_op(g1->extra_state_fields, OP_EQ, NULL);
+
+ /* Make sure it got added. */
+ tt_int_op(1, OP_EQ, smartlist_len(gs->sampled_entry_guards));
+ tt_ptr_op(g1, OP_EQ, smartlist_get(gs->sampled_entry_guards, 0));
+ tt_ptr_op(g1, OP_EQ, get_sampled_guard_with_id(gs, (uint8_t*)n1->identity));
+ const uint8_t bad_id[20] = {0};
+ tt_ptr_op(NULL, OP_EQ, get_sampled_guard_with_id(gs, bad_id));
- populate_live_entry_guards_test_helper(3);
+ done:
+ guard_selection_free(gs);
}
-/** Append some EntryGuard lines to the Tor state at <b>state</b>.
-
- <b>entry_guard_lines</b> is a smartlist containing 2-tuple
- smartlists that carry the key and values of the statefile.
- As an example:
- entry_guard_lines =
- (("EntryGuard", "name 67E72FF33D7D41BF11C569646A0A7B4B188340DF DirCache"),
- ("EntryGuardDownSince", "2014-06-07 16:02:46 2014-06-07 16:02:46"))
-*/
static void
-state_insert_entry_guard_helper(or_state_t *state,
- smartlist_t *entry_guard_lines)
+test_entry_guard_node_filter(void *arg)
{
- config_line_t **next, *line;
-
- next = &state->EntryGuards;
- *next = NULL;
+ (void)arg;
+ guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
+ bridge_line_t *bl = NULL;
+
+ /* Initialize a bunch of node objects that are all guards. */
+#define NUM 7
+ node_t *n[NUM];
+ entry_guard_t *g[NUM];
+ int i;
+ for (i=0; i < NUM; ++i) {
+ n[i] = smartlist_get(big_fake_net_nodes, i*2); // even ones are guards.
+ g[i] = entry_guard_add_to_sample(gs, n[i]);
+
+ // everything starts out filtered-in
+ tt_uint_op(g[i]->is_filtered_guard, OP_EQ, 1);
+ tt_uint_op(g[i]->is_usable_filtered_guard, OP_EQ, 1);
+ }
+ tt_int_op(num_reachable_filtered_guards(gs, NULL), OP_EQ, NUM);
- /* Loop over all the state lines in the smartlist */
- SMARTLIST_FOREACH_BEGIN(entry_guard_lines, const smartlist_t *,state_lines) {
- /* Get key and value for each line */
- const char *state_key = smartlist_get(state_lines, 0);
- const char *state_value = smartlist_get(state_lines, 1);
+ /* Make sure refiltering doesn't hurt */
+ entry_guards_update_filtered_sets(gs);
+ for (i = 0; i < NUM; ++i) {
+ tt_uint_op(g[i]->is_filtered_guard, OP_EQ, 1);
+ tt_uint_op(g[i]->is_usable_filtered_guard, OP_EQ, 1);
+ }
+ tt_int_op(num_reachable_filtered_guards(gs, NULL), OP_EQ, NUM);
+
+ /* Now start doing things to make the guards get filtered out, 1 by 1. */
+
+ /* 0: Not listed. */
+ g[0]->currently_listed = 0;
+
+ /* 1: path bias says this guard is maybe eeeevil. */
+ g[1]->pb.path_bias_disabled = 1;
+
+ /* 2: Unreachable address. */
+ n[2]->rs->addr = 0;
+
+ /* 3: ExcludeNodes */
+ n[3]->rs->addr = 0x90902020;
+ routerset_free(get_options_mutable()->ExcludeNodes);
+ get_options_mutable()->ExcludeNodes = routerset_new();
+ routerset_parse(get_options_mutable()->ExcludeNodes, "144.144.0.0/16", "");
+
+ /* 4: Bridge. */
+ get_options_mutable()->UseBridges = 1;
+ sweep_bridge_list();
+ bl = tor_malloc_zero(sizeof(bridge_line_t));
+ tor_addr_from_ipv4h(&bl->addr, n[4]->rs->addr);
+ bl->port = n[4]->rs->or_port;
+ memcpy(bl->digest, n[4]->identity, 20);
+ bridge_add_from_config(bl);
+ bl = NULL; // prevent free.
+ get_options_mutable()->UseBridges = 0;
+
+ /* 5: Unreachable. This stays in the filter, but isn't in usable-filtered */
+ g[5]->last_tried_to_connect = approx_time(); // prevent retry.
+ g[5]->is_reachable = GUARD_REACHABLE_NO;
+
+ /* 6: no change. */
+
+ /* Now refilter and inspect. */
+ entry_guards_update_filtered_sets(gs);
+ for (i = 0; i < NUM; ++i) {
+ tt_assert(g[i]->is_filtered_guard == (i == 5 || i == 6));
+ tt_assert(g[i]->is_usable_filtered_guard == (i == 6));
+ }
+ tt_int_op(num_reachable_filtered_guards(gs, NULL), OP_EQ, 1);
+
+ /* Now make sure we have no live consensus, and no nodes. Nothing should
+ * pass the filter any more. */
+ tor_free(dummy_consensus);
+ dummy_consensus = NULL;
+ SMARTLIST_FOREACH(big_fake_net_nodes, node_t *, node, {
+ memset(node->identity, 0xff, 20);
+ });
+ entry_guards_update_filtered_sets(gs);
+ for (i = 0; i < NUM; ++i) {
+ tt_uint_op(g[i]->is_filtered_guard, OP_EQ, 0);
+ tt_uint_op(g[i]->is_usable_filtered_guard, OP_EQ, 0);
+ }
+ tt_int_op(num_reachable_filtered_guards(gs, NULL), OP_EQ, 0);
- *next = line = tor_malloc_zero(sizeof(config_line_t));
- line->key = tor_strdup(state_key);
- tor_asprintf(&line->value, "%s", state_value);
- next = &(line->next);
- } SMARTLIST_FOREACH_END(state_lines);
+ done:
+ guard_selection_free(gs);
+ tor_free(bl);
+#undef NUM
}
-/** Free memory occupied by <b>entry_guard_lines</b>. */
static void
-state_lines_free(smartlist_t *entry_guard_lines)
+test_entry_guard_expand_sample(void *arg)
{
- SMARTLIST_FOREACH_BEGIN(entry_guard_lines, smartlist_t *, state_lines) {
- char *state_key = smartlist_get(state_lines, 0);
- char *state_value = smartlist_get(state_lines, 1);
+ (void)arg;
+ guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
+ digestmap_t *node_by_id = digestmap_new();
+
+ entry_guard_t *guard = entry_guards_expand_sample(gs);
+ tt_assert(guard); // the last guard returned.
+
+ // Every sampled guard here should be filtered and reachable for now.
+ tt_int_op(smartlist_len(gs->sampled_entry_guards), OP_EQ,
+ num_reachable_filtered_guards(gs, NULL));
+
+ /* Make sure we got the right number. */
+ tt_int_op(DFLT_MIN_FILTERED_SAMPLE_SIZE, OP_EQ,
+ num_reachable_filtered_guards(gs, NULL));
+
+ // Make sure everything we got was from our fake node list, and everything
+ // was unique.
+ SMARTLIST_FOREACH_BEGIN(gs->sampled_entry_guards, entry_guard_t *, g) {
+ const node_t *n = bfn_mock_node_get_by_id(g->identity);
+ tt_assert(n);
+ tt_ptr_op(NULL, OP_EQ, digestmap_get(node_by_id, g->identity));
+ digestmap_set(node_by_id, g->identity, (void*) n);
+ int idx = smartlist_pos(big_fake_net_nodes, n);
+ // The even ones are the guards; make sure we got guards.
+ tt_int_op(idx & 1, OP_EQ, 0);
+ } SMARTLIST_FOREACH_END(g);
+
+ // Nothing became unusable/unfiltered, so a subsequent expand should
+ // make no changes.
+ guard = entry_guards_expand_sample(gs);
+ tt_ptr_op(guard, OP_EQ, NULL); // no guard was added.
+ tt_int_op(DFLT_MIN_FILTERED_SAMPLE_SIZE, OP_EQ,
+ num_reachable_filtered_guards(gs, NULL));
+
+ // Make a few guards unreachable.
+ guard = smartlist_get(gs->sampled_entry_guards, 0);
+ guard->is_usable_filtered_guard = 0;
+ guard = smartlist_get(gs->sampled_entry_guards, 1);
+ guard->is_usable_filtered_guard = 0;
+ guard = smartlist_get(gs->sampled_entry_guards, 2);
+ guard->is_usable_filtered_guard = 0;
+ tt_int_op(DFLT_MIN_FILTERED_SAMPLE_SIZE - 3, OP_EQ,
+ num_reachable_filtered_guards(gs, NULL));
+
+ // This time, expanding the sample will add some more guards.
+ guard = entry_guards_expand_sample(gs);
+ tt_assert(guard); // no guard was added.
+ tt_int_op(DFLT_MIN_FILTERED_SAMPLE_SIZE, OP_EQ,
+ num_reachable_filtered_guards(gs, NULL));
+ tt_int_op(smartlist_len(gs->sampled_entry_guards), OP_EQ,
+ num_reachable_filtered_guards(gs, NULL)+3);
+
+ // Still idempotent.
+ guard = entry_guards_expand_sample(gs);
+ tt_ptr_op(guard, OP_EQ, NULL); // no guard was added.
+ tt_int_op(DFLT_MIN_FILTERED_SAMPLE_SIZE, OP_EQ,
+ num_reachable_filtered_guards(gs, NULL));
+
+ // Now, do a nasty trick: tell the filter to exclude 31/32 of the guards.
+ // This will cause the sample size to get reeeeally huge, while the
+ // filtered sample size grows only slowly.
+ routerset_free(get_options_mutable()->ExcludeNodes);
+ get_options_mutable()->ExcludeNodes = routerset_new();
+ routerset_parse(get_options_mutable()->ExcludeNodes, "144.144.0.0/16", "");
+ SMARTLIST_FOREACH(big_fake_net_nodes, node_t *, n, {
+ if (n_sl_idx % 64 != 0) {
+ n->rs->addr = 0x90903030;
+ }
+ });
+ entry_guards_update_filtered_sets(gs);
+
+ // Surely (p ~ 1-2**-60), one of our guards has been excluded.
+ tt_int_op(num_reachable_filtered_guards(gs, NULL), OP_LT,
+ DFLT_MIN_FILTERED_SAMPLE_SIZE);
+
+ // Try to regenerate the guards.
+ guard = entry_guards_expand_sample(gs);
+ tt_assert(guard); // no guard was added.
+
+ /* this time, it's possible that we didn't add enough sampled guards. */
+ tt_int_op(num_reachable_filtered_guards(gs, NULL), OP_LE,
+ DFLT_MIN_FILTERED_SAMPLE_SIZE);
+ /* but we definitely didn't exceed the sample maximum. */
+ const int n_guards = 271 / 2;
+ tt_int_op(smartlist_len(gs->sampled_entry_guards), OP_LE,
+ (int)(n_guards * .3));
- tor_free(state_key);
- tor_free(state_value);
- smartlist_free(state_lines);
- } SMARTLIST_FOREACH_END(state_lines);
+ done:
+ guard_selection_free(gs);
+ digestmap_free(node_by_id, NULL);
+}
- smartlist_free(entry_guard_lines);
+static void
+test_entry_guard_expand_sample_small_net(void *arg)
+{
+ (void)arg;
+ guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
+
+ /* Fun corner case: not enough guards to make up our whole sample size. */
+ SMARTLIST_FOREACH(big_fake_net_nodes, node_t *, n, {
+ if (n_sl_idx >= 15) {
+ tor_free(n->rs);
+ tor_free(n->md);
+ tor_free(n);
+ SMARTLIST_DEL_CURRENT(big_fake_net_nodes, n);
+ } else {
+ n->rs->addr = 0; // make the filter reject this.
+ }
+ });
+
+ entry_guard_t *guard = entry_guards_expand_sample(gs);
+ tt_assert(guard); // the last guard returned -- some guard was added.
+ // half the nodes are guards, so we have 8 guards left. The set
+ // is small, so we sampled everything.
+ tt_int_op(smartlist_len(gs->sampled_entry_guards), OP_EQ, 8);
+ tt_int_op(num_reachable_filtered_guards(gs, NULL), OP_EQ, 0);
+ done:
+ guard_selection_free(gs);
}
-/* Tests entry_guards_parse_state(). It creates a fake Tor state with
- a saved entry guard and makes sure that Tor can parse it and
- creates the right entry node out of it.
-*/
static void
-test_entry_guards_parse_state_simple(void *arg)
+test_entry_guard_update_from_consensus_status(void *arg)
{
- or_state_t *state = or_state_new();
- const smartlist_t *all_entry_guards = get_entry_guards();
- smartlist_t *entry_state_lines = smartlist_new();
- char *msg = NULL;
- int retval;
+ /* Here we're going to have some nodes become un-guardy, and say we got a
+ * new consensus. This should cause those nodes to get detected as
+ * unreachable. */
- /* Details of our fake guard node */
- const char *nickname = "hagbard";
- const char *fpr = "B29D536DD1752D542E1FBB3C9CE4449D51298212";
- const char *tor_version = "0.2.5.3-alpha-dev";
- const char *added_at = get_yesterday_date_str();
- const char *unlisted_since = "2014-06-08 16:16:50";
+ (void)arg;
+ int i;
+ time_t start = approx_time();
+ guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
+ networkstatus_t *ns_tmp = NULL;
+
+ /* Don't randomly backdate stuff; it will make correctness harder to check.*/
+ MOCK(randomize_time, mock_randomize_time_no_randomization);
+
+ /* First, sample some guards. */
+ entry_guards_expand_sample(gs);
+ int n_sampled_pre = smartlist_len(gs->sampled_entry_guards);
+ int n_filtered_pre = num_reachable_filtered_guards(gs, NULL);
+ tt_i64_op(n_sampled_pre, OP_EQ, n_filtered_pre);
+ tt_i64_op(n_sampled_pre, OP_GT, 10);
+
+ /* At this point, it should be a no-op to do this: */
+ sampled_guards_update_from_consensus(gs);
+
+ /* Now let's make some of our guards become unlisted. The easiest way to
+ * do that would be to take away their guard flag. */
+ for (i = 0; i < 5; ++i) {
+ entry_guard_t *g = smartlist_get(gs->sampled_entry_guards, i);
+ node_t *n = (node_t*) bfn_mock_node_get_by_id(g->identity);
+ tt_assert(n);
+ n->is_possible_guard = 0;
+ }
- (void) arg;
+ update_approx_time(start + 30);
+ {
+ /* try this with no live networkstatus. Nothing should happen! */
+ ns_tmp = dummy_consensus;
+ dummy_consensus = NULL;
+ sampled_guards_update_from_consensus(gs);
+ tt_i64_op(smartlist_len(gs->sampled_entry_guards), OP_EQ, n_sampled_pre);
+ tt_i64_op(num_reachable_filtered_guards(gs, NULL), OP_EQ, n_filtered_pre);
+ /* put the networkstatus back. */
+ dummy_consensus = ns_tmp;
+ ns_tmp = NULL;
+ }
+
+ /* Now those guards should become unlisted, and drop off the filter, but
+ * stay in the sample. */
+ update_approx_time(start + 60);
+ sampled_guards_update_from_consensus(gs);
+
+ tt_i64_op(smartlist_len(gs->sampled_entry_guards), OP_EQ, n_sampled_pre);
+ tt_i64_op(num_reachable_filtered_guards(gs, NULL), OP_EQ, n_filtered_pre-5);
+ for (i = 0; i < 5; ++i) {
+ entry_guard_t *g = smartlist_get(gs->sampled_entry_guards, i);
+ tt_assert(! g->currently_listed);
+ tt_i64_op(g->unlisted_since_date, OP_EQ, start+60);
+ }
+ for (i = 5; i < n_sampled_pre; ++i) {
+ entry_guard_t *g = smartlist_get(gs->sampled_entry_guards, i);
+ tt_assert(g->currently_listed);
+ tt_i64_op(g->unlisted_since_date, OP_EQ, 0);
+ }
+
+ /* Now re-list one, and remove one completely. */
+ {
+ entry_guard_t *g = smartlist_get(gs->sampled_entry_guards, 0);
+ node_t *n = (node_t*) bfn_mock_node_get_by_id(g->identity);
+ tt_assert(n);
+ n->is_possible_guard = 1;
+ }
+ {
+ /* try removing the node, to make sure we don't crash on an absent node
+ */
+ entry_guard_t *g = smartlist_get(gs->sampled_entry_guards, 5);
+ node_t *n = (node_t*) bfn_mock_node_get_by_id(g->identity);
+ tt_assert(n);
+ smartlist_remove(big_fake_net_nodes, n);
+ tor_free(n->rs);
+ tor_free(n->md);
+ tor_free(n);
+ }
+ update_approx_time(start + 300);
+ sampled_guards_update_from_consensus(gs);
+
+ /* guards 1..5 are now unlisted; 0,6,7.. are listed. */
+ tt_i64_op(smartlist_len(gs->sampled_entry_guards), OP_EQ, n_sampled_pre);
+ for (i = 1; i < 6; ++i) {
+ entry_guard_t *g = smartlist_get(gs->sampled_entry_guards, i);
+ tt_assert(! g->currently_listed);
+ if (i == 5)
+ tt_i64_op(g->unlisted_since_date, OP_EQ, start+300);
+ else
+ tt_i64_op(g->unlisted_since_date, OP_EQ, start+60);
+ }
+ for (i = 0; i < n_sampled_pre; i = (!i) ? 6 : i+1) { /* 0,6,7,8, ... */
+ entry_guard_t *g = smartlist_get(gs->sampled_entry_guards, i);
+ tt_assert(g->currently_listed);
+ tt_i64_op(g->unlisted_since_date, OP_EQ, 0);
+ }
- /* The global entry guards smartlist should be empty now. */
- tt_int_op(smartlist_len(all_entry_guards), OP_EQ, 0);
+ done:
+ tor_free(ns_tmp); /* in case we couldn't put it back */
+ guard_selection_free(gs);
+ UNMOCK(randomize_time);
+}
- { /* Prepare the state entry */
+static void
+test_entry_guard_update_from_consensus_repair(void *arg)
+{
+ /* Here we'll make sure that our code to repair the unlisted-since
+ * times is correct. */
- /* Prepare the smartlist to hold the key/value of each line */
- smartlist_t *state_line = smartlist_new();
- smartlist_add_asprintf(state_line, "EntryGuard");
- smartlist_add_asprintf(state_line, "%s %s %s", nickname, fpr, "DirCache");
- smartlist_add(entry_state_lines, state_line);
+ (void)arg;
+ int i;
+ time_t start = approx_time();
+ guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
+
+ /* Don't randomly backdate stuff; it will make correctness harder to check.*/
+ MOCK(randomize_time, mock_randomize_time_no_randomization);
+
+ /* First, sample some guards. */
+ entry_guards_expand_sample(gs);
+ int n_sampled_pre = smartlist_len(gs->sampled_entry_guards);
+ int n_filtered_pre = num_reachable_filtered_guards(gs, NULL);
+ tt_i64_op(n_sampled_pre, OP_EQ, n_filtered_pre);
+ tt_i64_op(n_sampled_pre, OP_GT, 10);
+
+ /* Now corrupt the list a bit. Call some unlisted-since-never, and some
+ * listed-and-unlisted-since-a-time. */
+ update_approx_time(start + 300);
+ for (i = 0; i < 3; ++i) {
+ /* these will get a date. */
+ entry_guard_t *g = smartlist_get(gs->sampled_entry_guards, i);
+ node_t *n = (node_t*) bfn_mock_node_get_by_id(g->identity);
+ tt_assert(n);
+ n->is_possible_guard = 0;
+ g->currently_listed = 0;
+ }
+ for (i = 3; i < 6; ++i) {
+ /* these will become listed. */
+ entry_guard_t *g = smartlist_get(gs->sampled_entry_guards, i);
+ g->unlisted_since_date = start+100;
+ }
+ setup_full_capture_of_logs(LOG_WARN);
+ sampled_guards_update_from_consensus(gs);
+ expect_log_msg_containing(
+ "was listed, but with unlisted_since_date set");
+ expect_log_msg_containing(
+ "was unlisted, but with unlisted_since_date unset");
+ teardown_capture_of_logs();
+
+ tt_int_op(smartlist_len(gs->sampled_entry_guards), OP_EQ, n_sampled_pre);
+ tt_int_op(num_reachable_filtered_guards(gs, NULL), OP_EQ, n_filtered_pre-3);
+ for (i = 3; i < n_sampled_pre; ++i) {
+ /* these will become listed. */
+ entry_guard_t *g = smartlist_get(gs->sampled_entry_guards, i);
+ if (i < 3) {
+ tt_assert(! g->currently_listed);
+ tt_i64_op(g->unlisted_since_date, OP_EQ, start+300);
+ } else {
+ tt_assert(g->currently_listed);
+ tt_i64_op(g->unlisted_since_date, OP_EQ, 0);
+ }
+ }
- state_line = smartlist_new();
- smartlist_add_asprintf(state_line, "EntryGuardAddedBy");
- smartlist_add_asprintf(state_line, "%s %s %s", fpr, tor_version, added_at);
- smartlist_add(entry_state_lines, state_line);
+ done:
+ teardown_capture_of_logs();
+ guard_selection_free(gs);
+ UNMOCK(randomize_time);
+}
- state_line = smartlist_new();
- smartlist_add_asprintf(state_line, "EntryGuardUnlistedSince");
- smartlist_add_asprintf(state_line, "%s", unlisted_since);
- smartlist_add(entry_state_lines, state_line);
+static void
+test_entry_guard_update_from_consensus_remove(void *arg)
+{
+ /* Now let's check the logic responsible for removing guards from the
+ * sample entirely. */
+
+ (void)arg;
+ //int i;
+ guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
+ smartlist_t *keep_ids = smartlist_new();
+ smartlist_t *remove_ids = smartlist_new();
+
+ /* Don't randomly backdate stuff; it will make correctness harder to check.*/
+ MOCK(randomize_time, mock_randomize_time_no_randomization);
+
+ /* First, sample some guards. */
+ entry_guards_expand_sample(gs);
+ int n_sampled_pre = smartlist_len(gs->sampled_entry_guards);
+ int n_filtered_pre = num_reachable_filtered_guards(gs, NULL);
+ tt_i64_op(n_sampled_pre, OP_EQ, n_filtered_pre);
+ tt_i64_op(n_sampled_pre, OP_GT, 10);
+
+ const time_t one_day_ago = approx_time() - 1*24*60*60;
+ const time_t one_year_ago = approx_time() - 365*24*60*60;
+ const time_t two_years_ago = approx_time() - 2*365*24*60*60;
+ /* 0: unlisted for a day. (keep this) */
+ {
+ entry_guard_t *g = smartlist_get(gs->sampled_entry_guards, 0);
+ node_t *n = (node_t*) bfn_mock_node_get_by_id(g->identity);
+ tt_assert(n);
+ n->is_possible_guard = 0;
+ g->currently_listed = 0;
+ g->unlisted_since_date = one_day_ago;
+ smartlist_add(keep_ids, tor_memdup(g->identity, 20));
+ }
+ /* 1: unlisted for a year. (remove this) */
+ {
+ entry_guard_t *g = smartlist_get(gs->sampled_entry_guards, 1);
+ node_t *n = (node_t*) bfn_mock_node_get_by_id(g->identity);
+ tt_assert(n);
+ n->is_possible_guard = 0;
+ g->currently_listed = 0;
+ g->unlisted_since_date = one_year_ago;
+ smartlist_add(remove_ids, tor_memdup(g->identity, 20));
+ }
+ /* 2: added a day ago, never confirmed. (keep this) */
+ {
+ entry_guard_t *g = smartlist_get(gs->sampled_entry_guards, 2);
+ g->sampled_on_date = one_day_ago;
+ smartlist_add(keep_ids, tor_memdup(g->identity, 20));
+ }
+ /* 3: added a year ago, never confirmed. (remove this) */
+ {
+ entry_guard_t *g = smartlist_get(gs->sampled_entry_guards, 3);
+ g->sampled_on_date = one_year_ago;
+ smartlist_add(remove_ids, tor_memdup(g->identity, 20));
+ }
+ /* 4: added two year ago, confirmed yesterday, primary. (keep this.) */
+ {
+ entry_guard_t *g = smartlist_get(gs->sampled_entry_guards, 4);
+ g->sampled_on_date = one_year_ago;
+ g->confirmed_on_date = one_day_ago;
+ g->confirmed_idx = 0;
+ g->is_primary = 1;
+ smartlist_add(gs->confirmed_entry_guards, g);
+ smartlist_add(gs->primary_entry_guards, g);
+ smartlist_add(keep_ids, tor_memdup(g->identity, 20));
+ }
+ /* 5: added two years ago, confirmed a year ago, primary. (remove this) */
+ {
+ entry_guard_t *g = smartlist_get(gs->sampled_entry_guards, 5);
+ g->sampled_on_date = two_years_ago;
+ g->confirmed_on_date = one_year_ago;
+ g->confirmed_idx = 1;
+ g->is_primary = 1;
+ smartlist_add(gs->confirmed_entry_guards, g);
+ smartlist_add(gs->primary_entry_guards, g);
+ smartlist_add(remove_ids, tor_memdup(g->identity, 20));
}
- /* Inject our lines in the state */
- state_insert_entry_guard_helper(state, entry_state_lines);
+ sampled_guards_update_from_consensus(gs);
- /* Parse state */
- retval = entry_guards_parse_state(state, 1, &msg);
- tt_int_op(retval, OP_GE, 0);
+ /* Did we remove the right ones? */
+ SMARTLIST_FOREACH(keep_ids, uint8_t *, id, {
+ tt_assert(get_sampled_guard_with_id(gs, id) != NULL);
+ });
+ SMARTLIST_FOREACH(remove_ids, uint8_t *, id, {
+ tt_want(get_sampled_guard_with_id(gs, id) == NULL);
+ });
- /* Test that the guard was registered.
- We need to re-get the entry guard list since its pointer was
- overwritten in entry_guards_parse_state(). */
- all_entry_guards = get_entry_guards();
- tt_int_op(smartlist_len(all_entry_guards), OP_EQ, 1);
+ /* Did we remove the right number? */
+ tt_int_op(smartlist_len(gs->sampled_entry_guards), OP_EQ, n_sampled_pre - 3);
- { /* Test the entry guard structure */
- char hex_digest[1024];
- char str_time[1024];
+ done:
+ guard_selection_free(gs);
+ UNMOCK(randomize_time);
+ SMARTLIST_FOREACH(keep_ids, char *, cp, tor_free(cp));
+ SMARTLIST_FOREACH(remove_ids, char *, cp, tor_free(cp));
+ smartlist_free(keep_ids);
+ smartlist_free(remove_ids);
+}
- const entry_guard_t *e = smartlist_get(all_entry_guards, 0);
- tt_str_op(e->nickname, OP_EQ, nickname); /* Verify nickname */
+static void
+test_entry_guard_confirming_guards(void *arg)
+{
+ (void)arg;
+ /* Now let's check the logic responsible for manipulating the list
+ * of confirmed guards */
+ guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
+ MOCK(randomize_time, mock_randomize_time_no_randomization);
+
+ /* Create the sample. */
+ entry_guards_expand_sample(gs);
+
+ /* Confirm a few guards. */
+ time_t start = approx_time();
+ entry_guard_t *g1 = smartlist_get(gs->sampled_entry_guards, 0);
+ entry_guard_t *g2 = smartlist_get(gs->sampled_entry_guards, 1);
+ entry_guard_t *g3 = smartlist_get(gs->sampled_entry_guards, 8);
+ make_guard_confirmed(gs, g2);
+ update_approx_time(start + 10);
+ make_guard_confirmed(gs, g1);
+ make_guard_confirmed(gs, g3);
+
+ /* Were the correct dates and indices fed in? */
+ tt_int_op(g1->confirmed_idx, OP_EQ, 1);
+ tt_int_op(g2->confirmed_idx, OP_EQ, 0);
+ tt_int_op(g3->confirmed_idx, OP_EQ, 2);
+ tt_i64_op(g1->confirmed_on_date, OP_EQ, start+10);
+ tt_i64_op(g2->confirmed_on_date, OP_EQ, start);
+ tt_i64_op(g3->confirmed_on_date, OP_EQ, start+10);
+ tt_ptr_op(smartlist_get(gs->confirmed_entry_guards, 0), OP_EQ, g2);
+ tt_ptr_op(smartlist_get(gs->confirmed_entry_guards, 1), OP_EQ, g1);
+ tt_ptr_op(smartlist_get(gs->confirmed_entry_guards, 2), OP_EQ, g3);
+
+ /* Now make sure we can regenerate the confirmed_entry_guards list. */
+ smartlist_clear(gs->confirmed_entry_guards);
+ g2->confirmed_idx = 0;
+ g1->confirmed_idx = 10;
+ g3->confirmed_idx = 100;
+ entry_guards_update_confirmed(gs);
+ tt_int_op(g1->confirmed_idx, OP_EQ, 1);
+ tt_int_op(g2->confirmed_idx, OP_EQ, 0);
+ tt_int_op(g3->confirmed_idx, OP_EQ, 2);
+ tt_ptr_op(smartlist_get(gs->confirmed_entry_guards, 0), OP_EQ, g2);
+ tt_ptr_op(smartlist_get(gs->confirmed_entry_guards, 1), OP_EQ, g1);
+ tt_ptr_op(smartlist_get(gs->confirmed_entry_guards, 2), OP_EQ, g3);
+
+ /* Now make sure we can regenerate the confirmed_entry_guards list if
+ * the indices are messed up. */
+ g1->confirmed_idx = g2->confirmed_idx = g3->confirmed_idx = 999;
+ smartlist_clear(gs->confirmed_entry_guards);
+ entry_guards_update_confirmed(gs);
+ tt_int_op(g1->confirmed_idx, OP_GE, 0);
+ tt_int_op(g2->confirmed_idx, OP_GE, 0);
+ tt_int_op(g3->confirmed_idx, OP_GE, 0);
+ tt_int_op(g1->confirmed_idx, OP_LE, 2);
+ tt_int_op(g2->confirmed_idx, OP_LE, 2);
+ tt_int_op(g3->confirmed_idx, OP_LE, 2);
+ g1 = smartlist_get(gs->confirmed_entry_guards, 0);
+ g2 = smartlist_get(gs->confirmed_entry_guards, 1);
+ g3 = smartlist_get(gs->confirmed_entry_guards, 2);
+ tt_int_op(g1->confirmed_idx, OP_EQ, 0);
+ tt_int_op(g2->confirmed_idx, OP_EQ, 1);
+ tt_int_op(g3->confirmed_idx, OP_EQ, 2);
+ tt_assert(g1 != g2);
+ tt_assert(g1 != g3);
+ tt_assert(g2 != g3);
- base16_encode(hex_digest, sizeof(hex_digest),
- e->identity, DIGEST_LEN);
- tt_str_op(hex_digest, OP_EQ, fpr); /* Verify fingerprint */
+ done:
+ UNMOCK(randomize_time);
+ guard_selection_free(gs);
+}
- tt_assert(e->is_dir_cache); /* Verify dirness */
+static void
+test_entry_guard_sample_reachable_filtered(void *arg)
+{
+ (void)arg;
+ guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
+ entry_guards_expand_sample(gs);
+ const int N = 10000;
+ bitarray_t *selected = NULL;
+ int i, j;
+
+ /* We've got a sampled list now; let's make one non-usable-filtered; some
+ * confirmed, some primary, some pending.
+ */
+ int n_guards = smartlist_len(gs->sampled_entry_guards);
+ tt_int_op(n_guards, OP_GT, 10);
+ entry_guard_t *g;
+ g = smartlist_get(gs->sampled_entry_guards, 0);
+ g->is_pending = 1;
+ g = smartlist_get(gs->sampled_entry_guards, 1);
+ make_guard_confirmed(gs, g);
+ g = smartlist_get(gs->sampled_entry_guards, 2);
+ g->is_primary = 1;
+ g = smartlist_get(gs->sampled_entry_guards, 3);
+ g->pb.path_bias_disabled = 1;
+
+ entry_guards_update_filtered_sets(gs);
+ gs->primary_guards_up_to_date = 1;
+ tt_int_op(num_reachable_filtered_guards(gs, NULL), OP_EQ, n_guards - 1);
+ tt_int_op(smartlist_len(gs->sampled_entry_guards), OP_EQ, n_guards);
+
+ // +1 since the one we made disabled will make another one get added.
+ ++n_guards;
+
+ /* Try a bunch of selections. */
+ const struct {
+ int flag; int idx;
+ } tests[] = {
+ { 0, -1 },
+ { SAMPLE_EXCLUDE_CONFIRMED, 1 },
+ { SAMPLE_EXCLUDE_PRIMARY|SAMPLE_NO_UPDATE_PRIMARY, 2 },
+ { SAMPLE_EXCLUDE_PENDING, 0 },
+ { -1, -1},
+ };
+
+ for (j = 0; tests[j].flag >= 0; ++j) {
+ selected = bitarray_init_zero(n_guards);
+ const int excluded_flags = tests[j].flag;
+ const int excluded_idx = tests[j].idx;
+ for (i = 0; i < N; ++i) {
+ g = sample_reachable_filtered_entry_guards(gs, NULL, excluded_flags);
+ tor_assert(g);
+ int pos = smartlist_pos(gs->sampled_entry_guards, g);
+ tt_int_op(smartlist_len(gs->sampled_entry_guards), OP_EQ, n_guards);
+ tt_int_op(pos, OP_GE, 0);
+ tt_int_op(pos, OP_LT, n_guards);
+ bitarray_set(selected, pos);
+ }
+ for (i = 0; i < n_guards; ++i) {
+ const int should_be_set = (i != excluded_idx &&
+ i != 3); // filtered out.
+ tt_int_op(!!bitarray_is_set(selected, i), OP_EQ, should_be_set);
+ }
+ bitarray_free(selected);
+ selected = NULL;
+ }
- tt_str_op(e->chosen_by_version, OP_EQ, tor_version); /* Verify version */
+ done:
+ guard_selection_free(gs);
+ bitarray_free(selected);
+}
- tt_assert(e->made_contact); /* All saved guards have been contacted */
+static void
+test_entry_guard_sample_reachable_filtered_empty(void *arg)
+{
+ (void)arg;
+ guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
+ /* What if we try to sample from a set of 0? */
+ SMARTLIST_FOREACH(big_fake_net_nodes, node_t *, n,
+ n->is_possible_guard = 0);
- tt_assert(e->bad_since); /* Verify bad_since timestamp */
- format_iso_time(str_time, e->bad_since);
- tt_str_op(str_time, OP_EQ, unlisted_since);
+ entry_guard_t *g = sample_reachable_filtered_entry_guards(gs, NULL, 0);
+ tt_ptr_op(g, OP_EQ, NULL);
- /* The rest should be unset */
- tt_assert(!e->unreachable_since);
- tt_assert(!e->can_retry);
- tt_assert(!e->path_bias_noticed);
- tt_assert(!e->path_bias_warned);
- tt_assert(!e->path_bias_extreme);
- tt_assert(!e->path_bias_disabled);
- tt_assert(!e->path_bias_use_noticed);
- tt_assert(!e->path_bias_use_extreme);
- tt_assert(!e->last_attempted);
- }
+ done:
+ guard_selection_free(gs);
+}
+
+static void
+test_entry_guard_retry_unreachable(void *arg)
+{
+ (void)arg;
+ guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
+
+ entry_guards_expand_sample(gs);
+ /* Let's say that we have two guards, and they're down.
+ */
+ time_t start = approx_time();
+ entry_guard_t *g1 = smartlist_get(gs->sampled_entry_guards, 0);
+ entry_guard_t *g2 = smartlist_get(gs->sampled_entry_guards, 1);
+ entry_guard_t *g3 = smartlist_get(gs->sampled_entry_guards, 2);
+ g1->is_reachable = GUARD_REACHABLE_NO;
+ g2->is_reachable = GUARD_REACHABLE_NO;
+ g1->is_primary = 1;
+ g1->failing_since = g2->failing_since = start;
+ g1->last_tried_to_connect = g2->last_tried_to_connect = start;
+
+ /* Wait 5 minutes. Nothing will get retried. */
+ update_approx_time(start + 5 * 60);
+ entry_guard_consider_retry(g1);
+ entry_guard_consider_retry(g2);
+ entry_guard_consider_retry(g3); // just to make sure this doesn't crash.
+ tt_int_op(g1->is_reachable, OP_EQ, GUARD_REACHABLE_NO);
+ tt_int_op(g2->is_reachable, OP_EQ, GUARD_REACHABLE_NO);
+ tt_int_op(g3->is_reachable, OP_EQ, GUARD_REACHABLE_MAYBE);
+
+ /* After 30 min, the primary one gets retried */
+ update_approx_time(start + 35 * 60);
+ entry_guard_consider_retry(g1);
+ entry_guard_consider_retry(g2);
+ tt_int_op(g1->is_reachable, OP_EQ, GUARD_REACHABLE_MAYBE);
+ tt_int_op(g2->is_reachable, OP_EQ, GUARD_REACHABLE_NO);
+
+ g1->is_reachable = GUARD_REACHABLE_NO;
+ g1->last_tried_to_connect = start + 55*60;
+
+ /* After 1 hour, we'll retry the nonprimary one. */
+ update_approx_time(start + 61 * 60);
+ entry_guard_consider_retry(g1);
+ entry_guard_consider_retry(g2);
+ tt_int_op(g1->is_reachable, OP_EQ, GUARD_REACHABLE_NO);
+ tt_int_op(g2->is_reachable, OP_EQ, GUARD_REACHABLE_MAYBE);
+
+ g2->is_reachable = GUARD_REACHABLE_NO;
+ g2->last_tried_to_connect = start + 61*60;
+
+ /* And then the primary one again. */
+ update_approx_time(start + 66 * 60);
+ entry_guard_consider_retry(g1);
+ entry_guard_consider_retry(g2);
+ tt_int_op(g1->is_reachable, OP_EQ, GUARD_REACHABLE_MAYBE);
+ tt_int_op(g2->is_reachable, OP_EQ, GUARD_REACHABLE_NO);
done:
- state_lines_free(entry_state_lines);
- or_state_free(state);
- tor_free(msg);
+ guard_selection_free(gs);
}
-/** Similar to test_entry_guards_parse_state_simple() but aims to test
- the PathBias-related details of the entry guard. */
static void
-test_entry_guards_parse_state_pathbias(void *arg)
+test_entry_guard_manage_primary(void *arg)
{
- or_state_t *state = or_state_new();
- const smartlist_t *all_entry_guards = get_entry_guards();
- char *msg = NULL;
- int retval;
- smartlist_t *entry_state_lines = smartlist_new();
+ (void)arg;
+ guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
+ smartlist_t *prev_guards = smartlist_new();
+
+ /* If no guards are confirmed, we should pick a few reachable guards and
+ * call them all primary. But not confirmed.*/
+ entry_guards_update_primary(gs);
+ int n_primary = smartlist_len(gs->primary_entry_guards);
+ tt_int_op(n_primary, OP_GE, 1);
+ SMARTLIST_FOREACH(gs->primary_entry_guards, entry_guard_t *, g, {
+ tt_assert(g->is_primary);
+ tt_assert(g->confirmed_idx == -1);
+ });
+
+ /* Calling it a second time should leave the guards unchanged. */
+ smartlist_add_all(prev_guards, gs->primary_entry_guards);
+ entry_guards_update_primary(gs);
+ tt_int_op(smartlist_len(gs->primary_entry_guards), OP_EQ, n_primary);
+ SMARTLIST_FOREACH(gs->primary_entry_guards, entry_guard_t *, g, {
+ tt_ptr_op(g, OP_EQ, smartlist_get(prev_guards, g_sl_idx));
+ });
+
+ /* If we have one confirmed guard, that guards becomes the first primary
+ * guard, and the other primary guards get kept. */
+
+ /* find a non-primary guard... */
+ entry_guard_t *confirmed = NULL;
+ SMARTLIST_FOREACH(gs->sampled_entry_guards, entry_guard_t *, g, {
+ if (! g->is_primary) {
+ confirmed = g;
+ break;
+ }
+ });
+ tt_assert(confirmed);
+ /* make it confirmed. */
+ make_guard_confirmed(gs, confirmed);
+ /* update the list... */
+ smartlist_clear(prev_guards);
+ smartlist_add_all(prev_guards, gs->primary_entry_guards);
+ entry_guards_update_primary(gs);
+
+ /* and see what's primary now! */
+ tt_int_op(smartlist_len(gs->primary_entry_guards), OP_EQ, n_primary);
+ tt_ptr_op(smartlist_get(gs->primary_entry_guards, 0), OP_EQ, confirmed);
+ SMARTLIST_FOREACH(gs->primary_entry_guards, entry_guard_t *, g, {
+ tt_assert(g->is_primary);
+ if (g_sl_idx == 0)
+ continue;
+ tt_ptr_op(g, OP_EQ, smartlist_get(prev_guards, g_sl_idx - 1));
+ });
+ {
+ entry_guard_t *prev_last_guard = smartlist_get(prev_guards, n_primary-1);
+ tt_assert(! prev_last_guard->is_primary);
+ }
- /* Path bias details of the fake guard */
- const double circ_attempts = 9;
- const double circ_successes = 8;
- const double successful_closed = 4;
- const double collapsed = 2;
- const double unusable = 0;
- const double timeouts = 1;
+ /* Calling it a fourth time should leave the guards unchanged. */
+ smartlist_clear(prev_guards);
+ smartlist_add_all(prev_guards, gs->primary_entry_guards);
+ entry_guards_update_primary(gs);
+ tt_int_op(smartlist_len(gs->primary_entry_guards), OP_EQ, n_primary);
+ SMARTLIST_FOREACH(gs->primary_entry_guards, entry_guard_t *, g, {
+ tt_ptr_op(g, OP_EQ, smartlist_get(prev_guards, g_sl_idx));
+ });
+
+ /* Do some dirinfo checks */
+ {
+ /* Check that we have all required dirinfo for the primaries (that's done
+ * in big_fake_network_setup()) */
+ char *dir_info_str =
+ guard_selection_get_err_str_if_dir_info_missing(gs, 0, 0, 0);
+ tt_assert(!dir_info_str);
+
+ /* Now artificially remove the first primary's descriptor and re-check */
+ entry_guard_t *first_primary;
+ first_primary = smartlist_get(gs->primary_entry_guards, 0);
+ /* Change the first primary's identity digest so that the mocked functions
+ * can't find its descriptor */
+ memset(first_primary->identity, 9, sizeof(first_primary->identity));
+ dir_info_str =guard_selection_get_err_str_if_dir_info_missing(gs, 1, 2, 3);
+ tt_str_op(dir_info_str, OP_EQ,
+ "We're missing descriptors for 1/2 of our primary entry guards "
+ "(total microdescriptors: 2/3).");
+ tor_free(dir_info_str);
+ }
+ done:
+ guard_selection_free(gs);
+ smartlist_free(prev_guards);
+}
+
+static void
+test_entry_guard_guard_preferred(void *arg)
+{
(void) arg;
+ entry_guard_t *g1 = tor_malloc_zero(sizeof(entry_guard_t));
+ entry_guard_t *g2 = tor_malloc_zero(sizeof(entry_guard_t));
- /* The global entry guards smartlist should be empty now. */
- tt_int_op(smartlist_len(all_entry_guards), OP_EQ, 0);
+ g1->confirmed_idx = g2->confirmed_idx = -1;
+ g1->last_tried_to_connect = approx_time();
+ g2->last_tried_to_connect = approx_time();
- { /* Prepare the state entry */
+ tt_int_op(0, OP_EQ, entry_guard_has_higher_priority(g1, g1));
- /* Prepare the smartlist to hold the key/value of each line */
- smartlist_t *state_line = smartlist_new();
- smartlist_add_asprintf(state_line, "EntryGuard");
- smartlist_add_asprintf(state_line,
- "givethanks B29D536DD1752D542E1FBB3C9CE4449D51298212 NoDirCache");
- smartlist_add(entry_state_lines, state_line);
+ /* Neither is pending; priorities equal. */
+ tt_int_op(0, OP_EQ, entry_guard_has_higher_priority(g2, g1));
+ tt_int_op(0, OP_EQ, entry_guard_has_higher_priority(g1, g2));
- state_line = smartlist_new();
- smartlist_add_asprintf(state_line, "EntryGuardAddedBy");
- smartlist_add_asprintf(state_line,
- "B29D536DD1752D542E1FBB3C9CE4449D51298212 0.2.5.3-alpha-dev "
- "%s", get_yesterday_date_str());
- smartlist_add(entry_state_lines, state_line);
+ /* If one is pending, the pending one has higher priority */
+ g1->is_pending = 1;
+ tt_int_op(1, OP_EQ, entry_guard_has_higher_priority(g1, g2));
+ tt_int_op(0, OP_EQ, entry_guard_has_higher_priority(g2, g1));
- state_line = smartlist_new();
- smartlist_add_asprintf(state_line, "EntryGuardUnlistedSince");
- smartlist_add_asprintf(state_line, "2014-06-08 16:16:50");
- smartlist_add(entry_state_lines, state_line);
+ /* If both are pending, and last_tried_to_connect is equal:
+ priorities equal */
+ g2->is_pending = 1;
+ tt_int_op(0, OP_EQ, entry_guard_has_higher_priority(g2, g1));
+ tt_int_op(0, OP_EQ, entry_guard_has_higher_priority(g1, g2));
- state_line = smartlist_new();
- smartlist_add_asprintf(state_line, "EntryGuardPathBias");
- smartlist_add_asprintf(state_line, "%f %f %f %f %f %f",
- circ_attempts, circ_successes, successful_closed,
- collapsed, unusable, timeouts);
- smartlist_add(entry_state_lines, state_line);
- }
+ /* One had a connection that startied earlier: it has higher priority. */
+ g2->last_tried_to_connect -= 10;
+ tt_int_op(1, OP_EQ, entry_guard_has_higher_priority(g2, g1));
+ tt_int_op(0, OP_EQ, entry_guard_has_higher_priority(g1, g2));
- /* Inject our lines in the state */
- state_insert_entry_guard_helper(state, entry_state_lines);
+ /* Now, say that g1 is confirmed. It will get higher priority. */
+ g1->confirmed_idx = 5;
+ tt_int_op(0, OP_EQ, entry_guard_has_higher_priority(g2, g1));
+ tt_int_op(1, OP_EQ, entry_guard_has_higher_priority(g1, g2));
- /* Parse state */
- retval = entry_guards_parse_state(state, 1, &msg);
- tt_int_op(retval, OP_GE, 0);
+ /* But if g2 was confirmed first, it will get priority */
+ g2->confirmed_idx = 2;
+ tt_int_op(1, OP_EQ, entry_guard_has_higher_priority(g2, g1));
+ tt_int_op(0, OP_EQ, entry_guard_has_higher_priority(g1, g2));
- /* Test that the guard was registered */
- all_entry_guards = get_entry_guards();
- tt_int_op(smartlist_len(all_entry_guards), OP_EQ, 1);
+ done:
+ tor_free(g1);
+ tor_free(g2);
+}
- { /* Test the path bias of this guard */
- const entry_guard_t *e = smartlist_get(all_entry_guards, 0);
+static void
+test_entry_guard_select_for_circuit_no_confirmed(void *arg)
+{
+ /* Simpler cases: no gaurds are confirmed yet. */
+ (void)arg;
+ guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
+ entry_guard_restriction_t *rst = NULL;
+
+ /* simple starting configuration */
+ entry_guards_update_primary(gs);
+ unsigned state = 9999;
+
+ entry_guard_t *g = select_entry_guard_for_circuit(gs, GUARD_USAGE_TRAFFIC,
+ NULL, &state);
+
+ tt_assert(g);
+ tt_assert(g->is_primary);
+ tt_int_op(g->confirmed_idx, OP_EQ, -1);
+ tt_uint_op(g->is_pending, OP_EQ, 0); // primary implies non-pending.
+ tt_uint_op(state, OP_EQ, GUARD_CIRC_STATE_USABLE_ON_COMPLETION);
+ tt_i64_op(g->last_tried_to_connect, OP_EQ, approx_time());
+
+ // If we do that again, we should get the same guard.
+ entry_guard_t *g2 = select_entry_guard_for_circuit(gs, GUARD_USAGE_TRAFFIC,
+ NULL, &state);
+ tt_ptr_op(g2, OP_EQ, g);
+
+ // if we mark that guard down, we should get a different primary guard.
+ // auto-retry it.
+ g->is_reachable = GUARD_REACHABLE_NO;
+ g->failing_since = approx_time() - 10;
+ g->last_tried_to_connect = approx_time() - 10;
+ state = 9999;
+ g2 = select_entry_guard_for_circuit(gs, GUARD_USAGE_TRAFFIC, NULL, &state);
+ tt_ptr_op(g2, OP_NE, g);
+ tt_assert(g2);
+ tt_assert(g2->is_primary);
+ tt_int_op(g2->confirmed_idx, OP_EQ, -1);
+ tt_uint_op(g2->is_pending, OP_EQ, 0); // primary implies non-pending.
+ tt_uint_op(state, OP_EQ, GUARD_CIRC_STATE_USABLE_ON_COMPLETION);
+ tt_i64_op(g2->last_tried_to_connect, OP_EQ, approx_time());
+
+ // If we say that the first primary guard was last tried a long time ago, we
+ // should get an automatic retry on it.
+ g->failing_since = approx_time() - 72*60*60;
+ g->last_tried_to_connect = approx_time() - 72*60*60;
+ state = 9999;
+ g2 = select_entry_guard_for_circuit(gs, GUARD_USAGE_TRAFFIC, NULL, &state);
+ tt_ptr_op(g2, OP_EQ, g);
+ tt_assert(g2);
+ tt_uint_op(state, OP_EQ, GUARD_CIRC_STATE_USABLE_ON_COMPLETION);
+ tt_i64_op(g2->last_tried_to_connect, OP_EQ, approx_time());
+ tt_int_op(g2->is_reachable, OP_EQ, GUARD_REACHABLE_MAYBE);
+
+ // And if we mark ALL the primary guards down, we should get another guard
+ // at random.
+ SMARTLIST_FOREACH(gs->primary_entry_guards, entry_guard_t *, guard, {
+ guard->is_reachable = GUARD_REACHABLE_NO;
+ guard->last_tried_to_connect = approx_time() - 5;
+ guard->failing_since = approx_time() - 30;
+ });
+ state = 9999;
+ g2 = select_entry_guard_for_circuit(gs, GUARD_USAGE_TRAFFIC, NULL, &state);
+ tt_assert(g2);
+ tt_assert(!g2->is_primary);
+ tt_int_op(g2->confirmed_idx, OP_EQ, -1);
+ tt_uint_op(g2->is_pending, OP_EQ, 1);
+ tt_uint_op(state, OP_EQ, GUARD_CIRC_STATE_USABLE_IF_NO_BETTER_GUARD);
+ tt_i64_op(g2->last_tried_to_connect, OP_EQ, approx_time());
+ tt_int_op(g2->is_reachable, OP_EQ, GUARD_REACHABLE_MAYBE);
+
+ // As a bonus, maybe we should be retrying the primary guards. Let's say so.
+ mark_primary_guards_maybe_reachable(gs);
+ SMARTLIST_FOREACH(gs->primary_entry_guards, entry_guard_t *, guard, {
+ tt_int_op(guard->is_reachable, OP_EQ, GUARD_REACHABLE_MAYBE);
+ tt_assert(guard->is_usable_filtered_guard == 1);
+ // no change to these fields.
+ tt_i64_op(guard->last_tried_to_connect, OP_EQ, approx_time() - 5);
+ tt_i64_op(guard->failing_since, OP_EQ, approx_time() - 30);
+ });
+
+ /* Let's try again and we should get the first primary guard again */
+ g = select_entry_guard_for_circuit(gs, GUARD_USAGE_TRAFFIC, NULL, &state);
+ tt_ptr_op(g, OP_EQ, smartlist_get(gs->primary_entry_guards, 0));
+ g2 = select_entry_guard_for_circuit(gs, GUARD_USAGE_TRAFFIC, NULL, &state);
+ tt_ptr_op(g2, OP_EQ, g);
+
+ /* But if we impose a restriction, we don't get the same guard */
+ rst = guard_create_exit_restriction((uint8_t*)g->identity);
+ g2 = select_entry_guard_for_circuit(gs, GUARD_USAGE_TRAFFIC, rst, &state);
+ tt_ptr_op(g2, OP_NE, g);
- tt_assert(!e->is_dir_cache);
- tt_assert(!e->can_retry);
+ done:
+ guard_selection_free(gs);
+ entry_guard_restriction_free(rst);
+}
- /* XXX tt_double_op doesn't support equality. Cast to int for now. */
- tt_int_op((int)e->circ_attempts, OP_EQ, (int)circ_attempts);
- tt_int_op((int)e->circ_successes, OP_EQ, (int)circ_successes);
- tt_int_op((int)e->successful_circuits_closed, OP_EQ,
- (int)successful_closed);
- tt_int_op((int)e->timeouts, OP_EQ, (int)timeouts);
- tt_int_op((int)e->collapsed_circuits, OP_EQ, (int)collapsed);
- tt_int_op((int)e->unusable_circuits, OP_EQ, (int)unusable);
+static void
+test_entry_guard_select_for_circuit_confirmed(void *arg)
+{
+ /* Case 2: if all the primary guards are down, and there are more confirmed
+ guards, we use a confirmed guard. */
+ (void)arg;
+ int i;
+ entry_guard_restriction_t *rst = NULL;
+ guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
+ const int N_CONFIRMED = 10;
+
+ /* slightly more complicated simple starting configuration */
+ entry_guards_update_primary(gs);
+ for (i = 0; i < N_CONFIRMED; ++i) {
+ entry_guard_t *guard = smartlist_get(gs->sampled_entry_guards, i);
+ make_guard_confirmed(gs, guard);
+ }
+ entry_guards_update_primary(gs); // rebuild the primary list.
+
+ unsigned state = 9999;
+
+ // As above, this gives us a primary guard.
+ entry_guard_t *g = select_entry_guard_for_circuit(gs, GUARD_USAGE_TRAFFIC,
+ NULL, &state);
+ tt_assert(g);
+ tt_assert(g->is_primary);
+ tt_int_op(g->confirmed_idx, OP_EQ, 0);
+ tt_uint_op(g->is_pending, OP_EQ, 0); // primary implies non-pending.
+ tt_uint_op(state, OP_EQ, GUARD_CIRC_STATE_USABLE_ON_COMPLETION);
+ tt_i64_op(g->last_tried_to_connect, OP_EQ, approx_time());
+ tt_ptr_op(g, OP_EQ, smartlist_get(gs->primary_entry_guards, 0));
+
+ // But if we mark all the primary guards down...
+ SMARTLIST_FOREACH(gs->primary_entry_guards, entry_guard_t *, guard, {
+ guard->last_tried_to_connect = approx_time();
+ entry_guards_note_guard_failure(gs, guard);
+ });
+
+ // ... we should get a confirmed guard.
+ state = 9999;
+ g = select_entry_guard_for_circuit(gs, GUARD_USAGE_TRAFFIC, NULL, &state);
+ tt_assert(g);
+ tt_assert(! g->is_primary);
+ tt_int_op(g->confirmed_idx, OP_EQ, smartlist_len(gs->primary_entry_guards));
+ tt_assert(g->is_pending);
+ tt_uint_op(state, OP_EQ, GUARD_CIRC_STATE_USABLE_IF_NO_BETTER_GUARD);
+ tt_i64_op(g->last_tried_to_connect, OP_EQ, approx_time());
+
+ // And if we try again, we should get a different confirmed guard, since
+ // that one is pending.
+ state = 9999;
+ entry_guard_t *g2 = select_entry_guard_for_circuit(gs, GUARD_USAGE_TRAFFIC,
+ NULL, &state);
+ tt_assert(g2);
+ tt_assert(! g2->is_primary);
+ tt_ptr_op(g2, OP_NE, g);
+ tt_int_op(g2->confirmed_idx, OP_EQ,
+ smartlist_len(gs->primary_entry_guards)+1);
+ tt_assert(g2->is_pending);
+ tt_uint_op(state, OP_EQ, GUARD_CIRC_STATE_USABLE_IF_NO_BETTER_GUARD);
+ tt_i64_op(g2->last_tried_to_connect, OP_EQ, approx_time());
+
+ // If we say that the next confirmed guard in order is excluded, and
+ // we disable EnforceDistinctSubnets, we get the guard AFTER the
+ // one we excluded.
+ get_options_mutable()->EnforceDistinctSubnets = 0;
+ g = smartlist_get(gs->confirmed_entry_guards,
+ smartlist_len(gs->primary_entry_guards)+2);
+ rst = guard_create_exit_restriction((uint8_t*)g->identity);
+ g2 = select_entry_guard_for_circuit(gs, GUARD_USAGE_TRAFFIC, rst, &state);
+ tt_ptr_op(g2, OP_NE, NULL);
+ tt_ptr_op(g2, OP_NE, g);
+ tt_int_op(g2->confirmed_idx, OP_EQ,
+ smartlist_len(gs->primary_entry_guards)+3);
+
+ // If we make every confirmed guard become pending then we start poking
+ // other guards.
+ const int n_remaining_confirmed =
+ N_CONFIRMED - 3 - smartlist_len(gs->primary_entry_guards);
+ for (i = 0; i < n_remaining_confirmed; ++i) {
+ g = select_entry_guard_for_circuit(gs, GUARD_USAGE_TRAFFIC, NULL, &state);
+ tt_int_op(g->confirmed_idx, OP_GE, 0);
+ tt_assert(g);
}
+ state = 9999;
+ g = select_entry_guard_for_circuit(gs, GUARD_USAGE_TRAFFIC, NULL, &state);
+ tt_assert(g);
+ tt_assert(g->is_pending);
+ tt_int_op(g->confirmed_idx, OP_EQ, -1);
+
+ // If we EnforceDistinctSubnets and apply a restriction, we get
+ // nothing, since we put all of the nodes in the same /16.
+ // Regression test for bug 22753/TROVE-2017-006.
+ get_options_mutable()->EnforceDistinctSubnets = 1;
+ g = smartlist_get(gs->confirmed_entry_guards, 0);
+ memcpy(rst->exclude_id, g->identity, DIGEST_LEN);
+ g2 = select_entry_guard_for_circuit(gs, GUARD_USAGE_TRAFFIC, rst, &state);
+ tt_ptr_op(g2, OP_EQ, NULL);
done:
- or_state_free(state);
- state_lines_free(entry_state_lines);
- tor_free(msg);
+ guard_selection_free(gs);
+ entry_guard_restriction_free(rst);
}
-/* Simple test of entry_guards_set_from_config() by specifying a
- particular EntryNode and making sure it gets picked. */
static void
-test_entry_guards_set_from_config(void *arg)
+test_entry_guard_select_for_circuit_highlevel_primary(void *arg)
{
- or_options_t *options = get_options_mutable();
- const smartlist_t *all_entry_guards = get_entry_guards();
- const char *entrynodes_str = "test003r";
- const node_t *chosen_entry = NULL;
- int retval;
+ /* Play around with selecting primary guards for circuits and markign
+ * them up and down */
+ (void)arg;
+ guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
+
+ time_t start = approx_time();
+
+ const node_t *node = NULL;
+ circuit_guard_state_t *guard = NULL;
+ entry_guard_t *g;
+ guard_usable_t u;
+ /*
+ * Make sure that the pick-for-circuit API basically works. We'll get
+ * a primary guard, so it'll be usable on completion.
+ */
+ int r = entry_guard_pick_for_circuit(gs, GUARD_USAGE_TRAFFIC, NULL,
+ &node, &guard);
+
+ tt_int_op(r, OP_EQ, 0);
+ tt_assert(node);
+ tt_assert(guard);
+ tt_int_op(guard->state, OP_EQ, GUARD_CIRC_STATE_USABLE_ON_COMPLETION);
+ g = entry_guard_handle_get(guard->guard);
+ tt_assert(g);
+ tt_mem_op(g->identity, OP_EQ, node->identity, DIGEST_LEN);
+ tt_int_op(g->is_primary, OP_EQ, 1);
+ tt_i64_op(g->last_tried_to_connect, OP_EQ, start);
+ tt_int_op(g->confirmed_idx, OP_EQ, -1);
+
+ /* Call that circuit successful. */
+ update_approx_time(start+15);
+ u = entry_guard_succeeded(&guard);
+ tt_int_op(u, OP_EQ, GUARD_USABLE_NOW); /* We can use it now. */
+ tt_assert(guard);
+ tt_int_op(guard->state, OP_EQ, GUARD_CIRC_STATE_COMPLETE);
+ g = entry_guard_handle_get(guard->guard);
+ tt_assert(g);
+ tt_int_op(g->is_reachable, OP_EQ, GUARD_REACHABLE_YES);
+ tt_int_op(g->confirmed_idx, OP_EQ, 0);
+
+ circuit_guard_state_free(guard);
+ guard = NULL;
+ node = NULL;
+ g = NULL;
+
+ /* Try again. We'll also get a primary guard this time. (The same one,
+ in fact.) But this time, we'll say the connection has failed. */
+ update_approx_time(start+35);
+ r = entry_guard_pick_for_circuit(gs, GUARD_USAGE_TRAFFIC, NULL,
+ &node, &guard);
+ tt_int_op(r, OP_EQ, 0);
+ tt_assert(node);
+ tt_assert(guard);
+ tt_int_op(guard->state, OP_EQ, GUARD_CIRC_STATE_USABLE_ON_COMPLETION);
+ tt_i64_op(guard->state_set_at, OP_EQ, start+35);
+ g = entry_guard_handle_get(guard->guard);
+ tt_assert(g);
+ tt_mem_op(g->identity, OP_EQ, node->identity, DIGEST_LEN);
+ tt_int_op(g->is_primary, OP_EQ, 1);
+ tt_i64_op(g->last_tried_to_connect, OP_EQ, start+35);
+ tt_int_op(g->confirmed_idx, OP_EQ, 0); // same one.
+
+ /* It's failed! What will happen to our poor guard? */
+ update_approx_time(start+45);
+ entry_guard_failed(&guard);
+ tt_assert(guard);
+ tt_int_op(guard->state, OP_EQ, GUARD_CIRC_STATE_DEAD);
+ tt_i64_op(guard->state_set_at, OP_EQ, start+45);
+ g = entry_guard_handle_get(guard->guard);
+ tt_assert(g);
+ tt_int_op(g->is_reachable, OP_EQ, GUARD_REACHABLE_NO);
+ tt_i64_op(g->failing_since, OP_EQ, start+45);
+ tt_int_op(g->confirmed_idx, OP_EQ, 0); // still confirmed.
+
+ circuit_guard_state_free(guard);
+ guard = NULL;
+ node = NULL;
+ entry_guard_t *g_prev = g;
+ g = NULL;
+
+ /* Now try a third time. Since the other one is down, we'll get a different
+ * (still primary) guard.
+ */
+ update_approx_time(start+60);
+ r = entry_guard_pick_for_circuit(gs, GUARD_USAGE_TRAFFIC, NULL,
+ &node, &guard);
+ tt_int_op(r, OP_EQ, 0);
+ tt_assert(node);
+ tt_assert(guard);
+ tt_int_op(guard->state, OP_EQ, GUARD_CIRC_STATE_USABLE_ON_COMPLETION);
+ g = entry_guard_handle_get(guard->guard);
+ tt_assert(g);
+ tt_ptr_op(g, OP_NE, g_prev);
+ tt_mem_op(g->identity, OP_EQ, node->identity, DIGEST_LEN);
+ tt_mem_op(g->identity, OP_NE, g_prev->identity, DIGEST_LEN);
+ tt_int_op(g->is_primary, OP_EQ, 1);
+ tt_i64_op(g->last_tried_to_connect, OP_EQ, start+60);
+ tt_int_op(g->confirmed_idx, OP_EQ, -1); // not confirmd now.
+
+ /* Call this one up; watch it get confirmed. */
+ update_approx_time(start+90);
+ u = entry_guard_succeeded(&guard);
+ tt_int_op(u, OP_EQ, GUARD_USABLE_NOW);
+ tt_assert(guard);
+ tt_int_op(guard->state, OP_EQ, GUARD_CIRC_STATE_COMPLETE);
+ g = entry_guard_handle_get(guard->guard);
+ tt_assert(g);
+ tt_int_op(g->is_reachable, OP_EQ, GUARD_REACHABLE_YES);
+ tt_int_op(g->confirmed_idx, OP_EQ, 1);
+ done:
+ guard_selection_free(gs);
+ circuit_guard_state_free(guard);
+}
+
+static void
+test_entry_guard_select_for_circuit_highlevel_confirm_other(void *arg)
+{
(void) arg;
+ const int N_PRIMARY = DFLT_N_PRIMARY_GUARDS;
+
+ /* At the start, we have no confirmed guards. We'll mark the primary guards
+ * down, then confirm something else. As soon as we do, it should become
+ * primary, and we should get it next time. */
+
+ time_t start = approx_time();
+ guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
+ circuit_guard_state_t *guard = NULL;
+ int i, r;
+ const node_t *node = NULL;
+ guard_usable_t u;
+
+ /* Declare that we're on the internet. */
+ entry_guards_note_internet_connectivity(gs);
+
+ /* Primary guards are down! */
+ for (i = 0; i < N_PRIMARY; ++i) {
+ r = entry_guard_pick_for_circuit(gs, GUARD_USAGE_TRAFFIC, NULL,
+ &node, &guard);
+ tt_assert(node);
+ tt_assert(guard);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(guard->state, OP_EQ, GUARD_CIRC_STATE_USABLE_ON_COMPLETION);
+ entry_guard_failed(&guard);
+ circuit_guard_state_free(guard);
+ guard = NULL;
+ node = NULL;
+ }
- /* Prase EntryNodes as a routerset. */
- options->EntryNodes = routerset_new();
- retval = routerset_parse(options->EntryNodes,
- entrynodes_str,
- "test_entrynodes");
- tt_int_op(retval, OP_GE, 0);
+ /* Next guard should be non-primary. */
+ node = NULL;
+ r = entry_guard_pick_for_circuit(gs, GUARD_USAGE_TRAFFIC, NULL,
+ &node, &guard);
+ tt_assert(node);
+ tt_assert(guard);
+ tt_int_op(r, OP_EQ, 0);
+ entry_guard_t *g = entry_guard_handle_get(guard->guard);
+ tt_assert(g);
+ tt_int_op(guard->state, OP_EQ, GUARD_CIRC_STATE_USABLE_IF_NO_BETTER_GUARD);
+ tt_int_op(g->confirmed_idx, OP_EQ, -1);
+ tt_int_op(g->is_primary, OP_EQ, 0);
+ tt_int_op(g->is_pending, OP_EQ, 1);
+ (void)start;
+
+ u = entry_guard_succeeded(&guard);
+ /* We're on the internet (by fiat), so this guard will get called "confirmed"
+ * and should immediately become primary.
+ */
+ tt_int_op(guard->state, OP_EQ, GUARD_CIRC_STATE_COMPLETE);
+ tt_assert(u == GUARD_USABLE_NOW);
+ tt_int_op(g->confirmed_idx, OP_EQ, 0);
+ tt_int_op(g->is_primary, OP_EQ, 1);
+ tt_int_op(g->is_pending, OP_EQ, 0);
- /* Read nodes from EntryNodes */
- entry_guards_set_from_config(options);
+ done:
+ guard_selection_free(gs);
+ circuit_guard_state_free(guard);
+}
- /* Test that only one guard was added. */
- tt_int_op(smartlist_len(all_entry_guards), OP_EQ, 1);
+static void
+test_entry_guard_select_for_circuit_highlevel_primary_retry(void *arg)
+{
+ (void) arg;
+ const int N_PRIMARY = DFLT_N_PRIMARY_GUARDS;
+
+ /* At the start, we have no confirmed guards. We'll mark the primary guards
+ * down, then confirm something else. As soon as we do, it should become
+ * primary, and we should get it next time. */
+
+ time_t start = approx_time();
+ guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
+ circuit_guard_state_t *guard = NULL, *guard2 = NULL;
+ int i, r;
+ const node_t *node = NULL;
+ entry_guard_t *g;
+ guard_usable_t u;
+
+ /* Declare that we're on the internet. */
+ entry_guards_note_internet_connectivity(gs);
+
+ /* Make primary guards confirmed (so they won't be superseded by a later
+ * guard), then mark them down. */
+ for (i = 0; i < N_PRIMARY; ++i) {
+ r = entry_guard_pick_for_circuit(gs, GUARD_USAGE_TRAFFIC, NULL,
+ &node, &guard);
+ tt_assert(node);
+ tt_assert(guard);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(guard->state, OP_EQ, GUARD_CIRC_STATE_USABLE_ON_COMPLETION);
+ g = entry_guard_handle_get(guard->guard);
+ make_guard_confirmed(gs, g);
+ tt_int_op(g->is_primary, OP_EQ, 1);
+ entry_guard_failed(&guard);
+ circuit_guard_state_free(guard);
+ tt_int_op(g->is_reachable, OP_EQ, GUARD_REACHABLE_NO);
+ guard = NULL;
+ node = NULL;
+ }
- /* Make sure it was the guard we specified. */
- chosen_entry = choose_random_entry(NULL);
- tt_str_op(chosen_entry->ri->nickname, OP_EQ, entrynodes_str);
+ /* Get another guard that we might try. */
+ r = entry_guard_pick_for_circuit(gs, GUARD_USAGE_TRAFFIC, NULL,
+ &node, &guard);
+ tt_assert(node);
+ tt_assert(guard);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(guard->state, OP_EQ, GUARD_CIRC_STATE_USABLE_IF_NO_BETTER_GUARD);
+ g = entry_guard_handle_get(guard->guard);
+ tt_int_op(g->is_primary, OP_EQ, 0);
+
+ tt_assert(entry_guards_all_primary_guards_are_down(gs));
+
+ /* And an hour has passed ... */
+ update_approx_time(start + 3600);
+
+ /* Say that guard has succeeded! */
+ u = entry_guard_succeeded(&guard);
+ tt_int_op(u, OP_EQ, GUARD_MAYBE_USABLE_LATER);
+ tt_int_op(guard->state, OP_EQ, GUARD_CIRC_STATE_WAITING_FOR_BETTER_GUARD);
+ g = entry_guard_handle_get(guard->guard);
+
+ /* The primary guards should have been marked up! */
+ SMARTLIST_FOREACH(gs->primary_entry_guards, entry_guard_t *, pg, {
+ tt_int_op(pg->is_primary, OP_EQ, 1);
+ tt_ptr_op(g, OP_NE, pg);
+ tt_int_op(pg->is_reachable, OP_EQ, GUARD_REACHABLE_MAYBE);
+ });
+
+ /* Have a circuit to a primary guard succeed. */
+ r = entry_guard_pick_for_circuit(gs, GUARD_USAGE_TRAFFIC, NULL,
+ &node, &guard2);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(guard2->state, OP_EQ, GUARD_CIRC_STATE_USABLE_ON_COMPLETION);
+ u = entry_guard_succeeded(&guard2);
+ tt_assert(u == GUARD_USABLE_NOW);
+ tt_int_op(guard2->state, OP_EQ, GUARD_CIRC_STATE_COMPLETE);
+
+ tt_assert(! entry_guards_all_primary_guards_are_down(gs));
done:
- routerset_free(options->EntryNodes);
+ guard_selection_free(gs);
+ circuit_guard_state_free(guard);
+ circuit_guard_state_free(guard2);
}
static void
-test_entry_is_time_to_retry(void *arg)
+test_entry_guard_select_and_cancel(void *arg)
{
- entry_guard_t *test_guard;
- time_t now;
- int retval;
- (void)arg;
+ (void) arg;
+ const int N_PRIMARY = DFLT_N_PRIMARY_GUARDS;
+ int i,r;
+ const node_t *node = NULL;
+ circuit_guard_state_t *guard;
+ guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
+ entry_guard_t *g;
+
+ /* Once more, we mark all the primary guards down. */
+ entry_guards_note_internet_connectivity(gs);
+ for (i = 0; i < N_PRIMARY; ++i) {
+ r = entry_guard_pick_for_circuit(gs, GUARD_USAGE_TRAFFIC, NULL,
+ &node, &guard);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(guard->state, OP_EQ, GUARD_CIRC_STATE_USABLE_ON_COMPLETION);
+ g = entry_guard_handle_get(guard->guard);
+ tt_int_op(g->is_primary, OP_EQ, 1);
+ tt_int_op(g->is_pending, OP_EQ, 0);
+ make_guard_confirmed(gs, g);
+ entry_guard_failed(&guard);
+ circuit_guard_state_free(guard);
+ guard = NULL;
+ node = NULL;
+ }
- now = time(NULL);
+ tt_assert(entry_guards_all_primary_guards_are_down(gs));
+
+ /* Now get another guard we could try... */
+ r = entry_guard_pick_for_circuit(gs, GUARD_USAGE_TRAFFIC, NULL,
+ &node, &guard);
+ tt_assert(node);
+ tt_assert(guard);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(guard->state, OP_EQ, GUARD_CIRC_STATE_USABLE_IF_NO_BETTER_GUARD);
+ g = entry_guard_handle_get(guard->guard);
+ tt_int_op(g->is_primary, OP_EQ, 0);
+ tt_int_op(g->is_pending, OP_EQ, 1);
+
+ /* Whoops! We should never have asked for this guard. Cancel the request! */
+ entry_guard_cancel(&guard);
+ tt_ptr_op(guard, OP_EQ, NULL);
+ tt_int_op(g->is_primary, OP_EQ, 0);
+ tt_int_op(g->is_pending, OP_EQ, 0);
- test_guard = tor_malloc_zero(sizeof(entry_guard_t));
+ done:
+ guard_selection_free(gs);
+ circuit_guard_state_free(guard);
+}
- test_guard->last_attempted = now - 10;
- test_guard->unreachable_since = now - 1;
+static void
+test_entry_guard_drop_guards(void *arg)
+{
+ (void) arg;
+ int r;
+ const node_t *node = NULL;
+ circuit_guard_state_t *guard;
+ guard_selection_t *gs = get_guard_selection_info();
+
+ // Pick a guard, to get things set up.
+ r = entry_guard_pick_for_circuit(gs, GUARD_USAGE_TRAFFIC, NULL,
+ &node, &guard);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(smartlist_len(gs->sampled_entry_guards), OP_GE,
+ DFLT_MIN_FILTERED_SAMPLE_SIZE);
+ tt_ptr_op(gs, OP_EQ, get_guard_selection_info());
+
+ // Drop all the guards! (This is a bad idea....)
+ remove_all_entry_guards_for_guard_selection(gs);
+ gs = get_guard_selection_info();
+ tt_int_op(smartlist_len(gs->sampled_entry_guards), OP_EQ, 0);
+ tt_int_op(smartlist_len(gs->primary_entry_guards), OP_EQ, 0);
+ tt_int_op(smartlist_len(gs->confirmed_entry_guards), OP_EQ, 0);
- retval = entry_is_time_to_retry(test_guard,now);
- tt_int_op(retval,OP_EQ,1);
+ done:
+ circuit_guard_state_free(guard);
+ guard_selection_free(gs);
+}
- test_guard->unreachable_since = now - (6*60*60 - 1);
- test_guard->last_attempted = now - (60*60 + 1);
+/* Unit test setup function: Create a fake network, and set everything up
+ * for testing the upgrade-a-waiting-circuit code. */
+typedef struct {
+ guard_selection_t *gs;
+ time_t start;
+ circuit_guard_state_t *guard1_state;
+ circuit_guard_state_t *guard2_state;
+ entry_guard_t *guard1;
+ entry_guard_t *guard2;
+ origin_circuit_t *circ1;
+ origin_circuit_t *circ2;
+ smartlist_t *all_origin_circuits;
+} upgrade_circuits_data_t;
+static void *
+upgrade_circuits_setup(const struct testcase_t *testcase)
+{
+ upgrade_circuits_data_t *data = tor_malloc_zero(sizeof(*data));
+ guard_selection_t *gs = data->gs =
+ guard_selection_new("default", GS_TYPE_NORMAL);
+ circuit_guard_state_t *guard;
+ const node_t *node;
+ entry_guard_t *g;
+ int i;
+ const int N_PRIMARY = DFLT_N_PRIMARY_GUARDS;
+ const char *argument = testcase->setup_data;
+ const int make_circ1_succeed = strstr(argument, "c1-done") != NULL;
+ const int make_circ2_succeed = strstr(argument, "c2-done") != NULL;
+
+ big_fake_network_setup(testcase);
+
+ /* We're going to set things up in a state where a circuit will be ready to
+ * be upgraded. Each test can make a single change (or not) that should
+ * block the upgrade.
+ */
+
+ /* First, make all the primary guards confirmed, and down. */
+ data->start = approx_time();
+ entry_guards_note_internet_connectivity(gs);
+ for (i = 0; i < N_PRIMARY; ++i) {
+ entry_guard_pick_for_circuit(gs, GUARD_USAGE_TRAFFIC, NULL, &node, &guard);
+ g = entry_guard_handle_get(guard->guard);
+ make_guard_confirmed(gs, g);
+ entry_guard_failed(&guard);
+ circuit_guard_state_free(guard);
+ }
- retval = entry_is_time_to_retry(test_guard,now);
- tt_int_op(retval,OP_EQ,1);
+ /* Grab another couple of guards */
+ data->all_origin_circuits = smartlist_new();
+
+ update_approx_time(data->start + 27);
+ entry_guard_pick_for_circuit(gs, GUARD_USAGE_TRAFFIC, NULL,
+ &node, &data->guard1_state);
+ origin_circuit_t *circ;
+ data->circ1 = circ = origin_circuit_new();
+ circ->base_.purpose = CIRCUIT_PURPOSE_C_GENERAL;
+ circ->guard_state = data->guard1_state;
+ smartlist_add(data->all_origin_circuits, circ);
+
+ update_approx_time(data->start + 30);
+ entry_guard_pick_for_circuit(gs, GUARD_USAGE_TRAFFIC, NULL,
+ &node, &data->guard2_state);
+ data->circ2 = circ = origin_circuit_new();
+ circ->base_.purpose = CIRCUIT_PURPOSE_C_GENERAL;
+ circ->guard_state = data->guard2_state;
+ smartlist_add(data->all_origin_circuits, circ);
+
+ data->guard1 = entry_guard_handle_get(data->guard1_state->guard);
+ data->guard2 = entry_guard_handle_get(data->guard2_state->guard);
+ tor_assert(data->guard1 != data->guard2);
+ tor_assert(data->guard1_state->state ==
+ GUARD_CIRC_STATE_USABLE_IF_NO_BETTER_GUARD);
+ tor_assert(data->guard2_state->state ==
+ GUARD_CIRC_STATE_USABLE_IF_NO_BETTER_GUARD);
+
+ guard_usable_t r;
+ update_approx_time(data->start + 32);
+ if (make_circ1_succeed) {
+ r = entry_guard_succeeded(&data->guard1_state);
+ tor_assert(r == GUARD_MAYBE_USABLE_LATER);
+ tor_assert(data->guard1_state->state ==
+ GUARD_CIRC_STATE_WAITING_FOR_BETTER_GUARD);
+ }
+ update_approx_time(data->start + 33);
+ if (make_circ2_succeed) {
+ r = entry_guard_succeeded(&data->guard2_state);
+ tor_assert(r == GUARD_MAYBE_USABLE_LATER);
+ tor_assert(data->guard2_state->state ==
+ GUARD_CIRC_STATE_WAITING_FOR_BETTER_GUARD);
+ }
- test_guard->last_attempted = now - (60*60 - 1);
+ return data;
+}
+static int
+upgrade_circuits_cleanup(const struct testcase_t *testcase, void *ptr)
+{
+ upgrade_circuits_data_t *data = ptr;
+ // circuit_guard_state_free(data->guard1_state); // held in circ1
+ // circuit_guard_state_free(data->guard2_state); // held in circ2
+ guard_selection_free(data->gs);
+ smartlist_free(data->all_origin_circuits);
+ circuit_free(TO_CIRCUIT(data->circ1));
+ circuit_free(TO_CIRCUIT(data->circ2));
+ tor_free(data);
+ return big_fake_network_cleanup(testcase, NULL);
+}
- retval = entry_is_time_to_retry(test_guard,now);
- tt_int_op(retval,OP_EQ,0);
+static void
+test_entry_guard_upgrade_a_circuit(void *arg)
+{
+ upgrade_circuits_data_t *data = arg;
- test_guard->unreachable_since = now - (6*60*60 + 1);
- test_guard->last_attempted = now - (4*60*60 + 1);
+ /* This is the easy case: we have no COMPLETED circuits, all the
+ * primary guards are down, we have two WAITING circuits: one will
+ * get upgraded to COMPLETED! (The one that started first.)
+ */
- retval = entry_is_time_to_retry(test_guard,now);
- tt_int_op(retval,OP_EQ,1);
+ smartlist_t *result = smartlist_new();
+ int r;
+ r = entry_guards_upgrade_waiting_circuits(data->gs,
+ data->all_origin_circuits,
+ result);
+ tt_int_op(r, OP_EQ, 1);
+ tt_int_op(smartlist_len(result), OP_EQ, 1);
+ origin_circuit_t *oc = smartlist_get(result, 0);
- test_guard->unreachable_since = now - (3*24*60*60 - 1);
- test_guard->last_attempted = now - (4*60*60 + 1);
+ /* circ1 was started first, so we'll get told to ugrade it... */
+ tt_ptr_op(oc, OP_EQ, data->circ1);
- retval = entry_is_time_to_retry(test_guard,now);
- tt_int_op(retval,OP_EQ,1);
+ /* And the guard state should be complete */
+ tt_ptr_op(data->guard1_state, OP_NE, NULL);
+ tt_int_op(data->guard1_state->state, OP_EQ, GUARD_CIRC_STATE_COMPLETE);
- test_guard->unreachable_since = now - (3*24*60*60 + 1);
- test_guard->last_attempted = now - (18*60*60 + 1);
+ done:
+ smartlist_free(result);
+}
- retval = entry_is_time_to_retry(test_guard,now);
- tt_int_op(retval,OP_EQ,1);
+static void
+test_entry_guard_upgrade_blocked_by_live_primary_guards(void *arg)
+{
+ upgrade_circuits_data_t *data = arg;
+
+ /* If any primary guards might be up, we can't upgrade any waiting
+ * circuits.
+ */
+ mark_primary_guards_maybe_reachable(data->gs);
+
+ smartlist_t *result = smartlist_new();
+ int r;
+ setup_capture_of_logs(LOG_DEBUG);
+ r = entry_guards_upgrade_waiting_circuits(data->gs,
+ data->all_origin_circuits,
+ result);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(smartlist_len(result), OP_EQ, 0);
+ expect_log_msg_containing("not all primary guards were definitely down.");
- test_guard->unreachable_since = now - (7*24*60*60 - 1);
- test_guard->last_attempted = now - (18*60*60 + 1);
+ done:
+ teardown_capture_of_logs();
+ smartlist_free(result);
+}
- retval = entry_is_time_to_retry(test_guard,now);
- tt_int_op(retval,OP_EQ,1);
+static void
+test_entry_guard_upgrade_blocked_by_lack_of_waiting_circuits(void *arg)
+{
+ upgrade_circuits_data_t *data = arg;
+
+ /* If no circuits are waiting, we can't upgrade anything. (The test
+ * setup in this case was told not to make any of the circuits "waiting".)
+ */
+ smartlist_t *result = smartlist_new();
+ int r;
+ setup_capture_of_logs(LOG_DEBUG);
+ r = entry_guards_upgrade_waiting_circuits(data->gs,
+ data->all_origin_circuits,
+ result);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(smartlist_len(result), OP_EQ, 0);
+ expect_log_msg_containing("Considered upgrading guard-stalled circuits, "
+ "but didn't find any.");
- test_guard->last_attempted = now - (18*60*60 - 1);
+ done:
+ teardown_capture_of_logs();
+ smartlist_free(result);
+}
- retval = entry_is_time_to_retry(test_guard,now);
- tt_int_op(retval,OP_EQ,0);
+static void
+test_entry_guard_upgrade_blocked_by_better_circ_complete(void *arg)
+{
+ upgrade_circuits_data_t *data = arg;
+
+ /* We'll run through the logic of upgrade_a_circuit below...
+ * and then try again to make sure that circ2 isn't also upgraded.
+ */
+
+ smartlist_t *result = smartlist_new();
+ int r;
+ r = entry_guards_upgrade_waiting_circuits(data->gs,
+ data->all_origin_circuits,
+ result);
+ tt_int_op(r, OP_EQ, 1);
+ tt_int_op(smartlist_len(result), OP_EQ, 1);
+ origin_circuit_t *oc = smartlist_get(result, 0);
+ tt_ptr_op(oc, OP_EQ, data->circ1);
+ tt_ptr_op(data->guard1_state, OP_NE, NULL);
+ tt_int_op(data->guard1_state->state, OP_EQ, GUARD_CIRC_STATE_COMPLETE);
+
+ /* Now, try again. Make sure that circ2 isn't upgraded. */
+ smartlist_clear(result);
+ setup_capture_of_logs(LOG_DEBUG);
+ r = entry_guards_upgrade_waiting_circuits(data->gs,
+ data->all_origin_circuits,
+ result);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(smartlist_len(result), OP_EQ, 0);
+ expect_log_msg_containing("At least one complete circuit had higher "
+ "priority, so not upgrading.");
- test_guard->unreachable_since = now - (7*24*60*60 + 1);
- test_guard->last_attempted = now - (36*60*60 + 1);
+ done:
+ teardown_capture_of_logs();
+ smartlist_free(result);
+}
- retval = entry_is_time_to_retry(test_guard,now);
- tt_int_op(retval,OP_EQ,1);
+static void
+test_entry_guard_upgrade_not_blocked_by_restricted_circ_complete(void *arg)
+{
+ upgrade_circuits_data_t *data = arg;
+
+ /* Once more, let circ1 become complete. But this time, we'll claim
+ * that circ2 was restricted to not use the same guard as circ1. */
+ data->guard2_state->restrictions =
+ guard_create_exit_restriction((uint8_t*)data->guard1->identity);
+
+ smartlist_t *result = smartlist_new();
+ int r;
+ r = entry_guards_upgrade_waiting_circuits(data->gs,
+ data->all_origin_circuits,
+ result);
+ tt_int_op(r, OP_EQ, 1);
+ tt_int_op(smartlist_len(result), OP_EQ, 1);
+ origin_circuit_t *oc = smartlist_get(result, 0);
+ tt_ptr_op(oc, OP_EQ, data->circ1);
+ tt_ptr_op(data->guard1_state, OP_NE, NULL);
+ tt_int_op(data->guard1_state->state, OP_EQ, GUARD_CIRC_STATE_COMPLETE);
+
+ /* Now, we try again. Since circ2 has a restriction that circ1 doesn't obey,
+ * circ2 _is_ eligible for upgrade. */
+ smartlist_clear(result);
+ r = entry_guards_upgrade_waiting_circuits(data->gs,
+ data->all_origin_circuits,
+ result);
+ tt_int_op(r, OP_EQ, 1);
+ tt_int_op(smartlist_len(result), OP_EQ, 1);
+ origin_circuit_t *oc2 = smartlist_get(result, 0);
+ tt_ptr_op(oc2, OP_EQ, data->circ2);
- test_guard->unreachable_since = now - (7*24*60*60 + 1);
- test_guard->last_attempted = now - (36*60*60 + 1);
+ done:
+ smartlist_free(result);
+}
- retval = entry_is_time_to_retry(test_guard,now);
- tt_int_op(retval,OP_EQ,1);
+static void
+test_entry_guard_upgrade_not_blocked_by_worse_circ_complete(void *arg)
+{
+ upgrade_circuits_data_t *data = arg;
+ smartlist_t *result = smartlist_new();
+ /* here we manually make circ2 COMPLETE, and make sure that circ1
+ * gets made complete anyway, since guard1 has higher priority
+ */
+ update_approx_time(data->start + 300);
+ data->guard2_state->state = GUARD_CIRC_STATE_COMPLETE;
+ data->guard2_state->state_set_at = approx_time();
+ update_approx_time(data->start + 301);
+
+ /* Now, try again. Make sure that circ1 is approved. */
+ int r;
+ r = entry_guards_upgrade_waiting_circuits(data->gs,
+ data->all_origin_circuits,
+ result);
+ tt_int_op(r, OP_EQ, 1);
+ tt_int_op(smartlist_len(result), OP_EQ, 1);
+ origin_circuit_t *oc = smartlist_get(result, 0);
+ tt_ptr_op(oc, OP_EQ, data->circ1);
done:
- tor_free(test_guard);
+ smartlist_free(result);
}
-/** XXX Do some tests that entry_is_live() */
static void
-test_entry_is_live(void *arg)
+test_entry_guard_upgrade_blocked_by_better_circ_pending(void *arg)
{
- smartlist_t *our_nodelist = NULL;
- const smartlist_t *all_entry_guards = get_entry_guards();
- const node_t *test_node = NULL;
- const entry_guard_t *test_entry = NULL;
- const char *msg;
- int which_node;
+ upgrade_circuits_data_t *data = arg;
+
+ /* circ2 is done, but circ1 is still pending. Since circ1 is better,
+ * we won't upgrade circ2. */
+
+ /* XXXX Prop271 -- this is a kludge. I'm making sure circ1 _is_ better,
+ * by messing with the guards' confirmed_idx */
+ make_guard_confirmed(data->gs, data->guard1);
+ {
+ int tmp;
+ tmp = data->guard1->confirmed_idx;
+ data->guard1->confirmed_idx = data->guard2->confirmed_idx;
+ data->guard2->confirmed_idx = tmp;
+ }
- (void) arg;
+ smartlist_t *result = smartlist_new();
+ setup_capture_of_logs(LOG_DEBUG);
+ int r;
+ r = entry_guards_upgrade_waiting_circuits(data->gs,
+ data->all_origin_circuits,
+ result);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(smartlist_len(result), OP_EQ, 0);
+ expect_log_msg_containing("but 1 pending circuit(s) had higher guard "
+ "priority, so not upgrading.");
- /* The global entry guards smartlist should be empty now. */
- tt_int_op(smartlist_len(all_entry_guards), OP_EQ, 0);
+ done:
+ teardown_capture_of_logs();
+ smartlist_free(result);
+}
- /* Walk the nodelist and add all nodes as entry guards. */
- our_nodelist = nodelist_get_list();
- tt_int_op(smartlist_len(our_nodelist), OP_EQ, HELPER_NUMBER_OF_DESCRIPTORS);
+static void
+test_entry_guard_upgrade_not_blocked_by_restricted_circ_pending(void *arg)
+{
+ upgrade_circuits_data_t *data = arg;
+ /* circ2 is done, but circ1 is still pending. But when there is a
+ restriction on circ2 that circ1 can't satisfy, circ1 can't block
+ circ2. */
+
+ /* XXXX Prop271 -- this is a kludge. I'm making sure circ1 _is_ better,
+ * by messing with the guards' confirmed_idx */
+ make_guard_confirmed(data->gs, data->guard1);
+ {
+ int tmp;
+ tmp = data->guard1->confirmed_idx;
+ data->guard1->confirmed_idx = data->guard2->confirmed_idx;
+ data->guard2->confirmed_idx = tmp;
+ }
- SMARTLIST_FOREACH_BEGIN(our_nodelist, const node_t *, node) {
- const node_t *node_tmp;
- node_tmp = add_an_entry_guard(node, 0, 1, 0, 0);
- tt_assert(node_tmp);
+ data->guard2_state->restrictions =
+ guard_create_exit_restriction((uint8_t*)data->guard1->identity);
- tt_int_op(node->is_stable, OP_EQ, 0);
- tt_int_op(node->is_fast, OP_EQ, 0);
- } SMARTLIST_FOREACH_END(node);
+ smartlist_t *result = smartlist_new();
+ int r;
+ r = entry_guards_upgrade_waiting_circuits(data->gs,
+ data->all_origin_circuits,
+ result);
+ tt_int_op(r, OP_EQ, 1);
+ tt_int_op(smartlist_len(result), OP_EQ, 1);
+ origin_circuit_t *oc = smartlist_get(result, 0);
+ tt_ptr_op(oc, OP_EQ, data->circ2);
- /* Make sure the nodes were added as entry guards. */
- tt_int_op(smartlist_len(all_entry_guards), OP_EQ,
- HELPER_NUMBER_OF_DESCRIPTORS);
+ done:
+ smartlist_free(result);
+}
- /* Now get a random test entry that we will use for this unit test. */
- which_node = 3; /* (chosen by fair dice roll) */
- test_entry = smartlist_get(all_entry_guards, which_node);
+static void
+test_entry_guard_upgrade_not_blocked_by_worse_circ_pending(void *arg)
+{
+ upgrade_circuits_data_t *data = arg;
+
+ /* circ1 is done, but circ2 is still pending. Since circ1 is better,
+ * we will upgrade it. */
+ smartlist_t *result = smartlist_new();
+ int r;
+ r = entry_guards_upgrade_waiting_circuits(data->gs,
+ data->all_origin_circuits,
+ result);
+ tt_int_op(r, OP_EQ, 1);
+ tt_int_op(smartlist_len(result), OP_EQ, 1);
+ origin_circuit_t *oc = smartlist_get(result, 0);
+ tt_ptr_op(oc, OP_EQ, data->circ1);
+
+ done:
+ smartlist_free(result);
+}
+
+static void
+test_enty_guard_should_expire_waiting(void *arg)
+{
+ (void)arg;
+ circuit_guard_state_t *fake_state = tor_malloc_zero(sizeof(*fake_state));
+ /* We'll leave "guard" unset -- it won't matter here. */
- /* Let's do some entry_is_live() tests! */
+ /* No state? Can't expire. */
+ tt_assert(! entry_guard_state_should_expire(NULL));
- /* Require the node to be stable, but it's not. Should fail.
- Also enable 'assume_reachable' because why not. */
- test_node = entry_is_live(test_entry,
- ENTRY_NEED_UPTIME | ENTRY_ASSUME_REACHABLE,
- &msg);
- tt_assert(!test_node);
+ /* Let's try one that expires. */
+ fake_state->state = GUARD_CIRC_STATE_WAITING_FOR_BETTER_GUARD;
+ fake_state->state_set_at =
+ approx_time() - DFLT_NONPRIMARY_GUARD_IDLE_TIMEOUT - 1;
- /* Require the node to be fast, but it's not. Should fail. */
- test_node = entry_is_live(test_entry,
- ENTRY_NEED_CAPACITY | ENTRY_ASSUME_REACHABLE,
- &msg);
- tt_assert(!test_node);
+ tt_assert(entry_guard_state_should_expire(fake_state));
- /* Don't impose any restrictions on the node. Should succeed. */
- test_node = entry_is_live(test_entry, 0, &msg);
- tt_assert(test_node);
- tt_ptr_op(test_node, OP_EQ, node_get_by_id(test_entry->identity));
+ /* But it wouldn't expire if we changed the state. */
+ fake_state->state = GUARD_CIRC_STATE_USABLE_IF_NO_BETTER_GUARD;
+ tt_assert(! entry_guard_state_should_expire(fake_state));
- /* Require descriptor for this node. It has one so it should succeed. */
- test_node = entry_is_live(test_entry, ENTRY_NEED_DESCRIPTOR, &msg);
- tt_assert(test_node);
- tt_ptr_op(test_node, OP_EQ, node_get_by_id(test_entry->identity));
+ /* And it wouldn't have expired a few seconds ago. */
+ fake_state->state = GUARD_CIRC_STATE_WAITING_FOR_BETTER_GUARD;
+ fake_state->state_set_at =
+ approx_time() - DFLT_NONPRIMARY_GUARD_IDLE_TIMEOUT + 5;
+ tt_assert(! entry_guard_state_should_expire(fake_state));
done:
- ; /* XXX */
+ tor_free(fake_state);
}
-#define TEST_IPV4_ADDR "123.45.67.89"
-#define TEST_IPV6_ADDR "[1234:5678:90ab:cdef::]"
-
static void
-test_node_preferred_orport(void *arg)
+mock_directory_initiate_request(directory_request_t *req)
{
- (void)arg;
- tor_addr_t ipv4_addr;
- const uint16_t ipv4_port = 4444;
- tor_addr_t ipv6_addr;
- const uint16_t ipv6_port = 6666;
- routerinfo_t node_ri;
- node_t node;
- tor_addr_port_t ap;
-
- /* Setup options */
- memset(&mocked_options, 0, sizeof(mocked_options));
- /* We don't test ClientPreferIPv6ORPort here, because it's used in
- * nodelist_set_consensus to setup node.ipv6_preferred, which we set
- * directly. */
- MOCK(get_options, mock_get_options);
-
- /* Setup IP addresses */
- tor_addr_parse(&ipv4_addr, TEST_IPV4_ADDR);
- tor_addr_parse(&ipv6_addr, TEST_IPV6_ADDR);
+ if (req->guard_state) {
+ circuit_guard_state_free(req->guard_state);
+ }
+}
- /* Setup node_ri */
- memset(&node_ri, 0, sizeof(node_ri));
- node_ri.addr = tor_addr_to_ipv4h(&ipv4_addr);
- node_ri.or_port = ipv4_port;
- tor_addr_copy(&node_ri.ipv6_addr, &ipv6_addr);
- node_ri.ipv6_orport = ipv6_port;
+static networkstatus_t *mock_ns_val = NULL;
+static networkstatus_t *
+mock_ns_get_by_flavor(consensus_flavor_t f)
+{
+ (void)f;
+ return mock_ns_val;
+}
- /* Setup node */
- memset(&node, 0, sizeof(node));
- node.ri = &node_ri;
+/** Test that when we fetch microdescriptors we skip guards that have
+ * previously failed to serve us needed microdescriptors. */
+static void
+test_entry_guard_outdated_dirserver_exclusion(void *arg)
+{
+ int retval;
+ response_handler_args_t *args = NULL;
+ dir_connection_t *conn = NULL;
+ (void) arg;
- /* Check the preferred address is IPv4 if we're only using IPv4, regardless
- * of whether we prefer it or not */
- mocked_options.ClientUseIPv4 = 1;
- mocked_options.ClientUseIPv6 = 0;
- node.ipv6_preferred = 0;
- node_get_pref_orport(&node, &ap);
- tt_assert(tor_addr_eq(&ap.addr, &ipv4_addr));
- tt_assert(ap.port == ipv4_port);
+ /* Test prep: Make a new guard selection */
+ guard_selection_t *gs = get_guard_selection_by_name("default",
+ GS_TYPE_NORMAL, 1);
- node.ipv6_preferred = 1;
- node_get_pref_orport(&node, &ap);
- tt_assert(tor_addr_eq(&ap.addr, &ipv4_addr));
- tt_assert(ap.port == ipv4_port);
+ /* ... we want to use entry guards */
+ or_options_t *options = get_options_mutable();
+ options->UseEntryGuards = 1;
+ options->UseBridges = 0;
+
+ /* ... prepare some md digests we want to download in the future */
+ smartlist_t *digests = smartlist_new();
+ const char *prose = "unhurried and wise, we perceive.";
+ for (int i = 0; i < 20; i++) {
+ smartlist_add(digests, (char*)prose);
+ }
- /* Check the preferred address is IPv4 if we're using IPv4 and IPv6, but
- * don't prefer the IPv6 address */
- mocked_options.ClientUseIPv4 = 1;
- mocked_options.ClientUseIPv6 = 1;
- node.ipv6_preferred = 0;
- node_get_pref_orport(&node, &ap);
- tt_assert(tor_addr_eq(&ap.addr, &ipv4_addr));
- tt_assert(ap.port == ipv4_port);
+ tt_int_op(smartlist_len(digests), OP_EQ, 20);
+
+ /* ... now mock some functions */
+ mock_ns_val = tor_malloc_zero(sizeof(networkstatus_t));
+ MOCK(networkstatus_get_latest_consensus_by_flavor, mock_ns_get_by_flavor);
+ MOCK(directory_initiate_request, mock_directory_initiate_request);
+
+ /* Test logic:
+ * 0. Create a proper guard set and primary guard list.
+ * 1. Pretend to fail microdescriptor fetches from all the primary guards.
+ * 2. Order another microdescriptor fetch and make sure that primary guards
+ * get skipped since they failed previous fetches.
+ */
+
+ { /* Setup primary guard list */
+ int i;
+ entry_guards_update_primary(gs);
+ for (i = 0; i < DFLT_N_PRIMARY_GUARDS; ++i) {
+ entry_guard_t *guard = smartlist_get(gs->sampled_entry_guards, i);
+ make_guard_confirmed(gs, guard);
+ }
+ entry_guards_update_primary(gs);
+ }
- /* Check the preferred address is IPv6 if we prefer it and
- * ClientUseIPv6 is 1, regardless of ClientUseIPv4 */
- mocked_options.ClientUseIPv4 = 1;
- mocked_options.ClientUseIPv6 = 1;
- node.ipv6_preferred = 1;
- node_get_pref_orport(&node, &ap);
- tt_assert(tor_addr_eq(&ap.addr, &ipv6_addr));
- tt_assert(ap.port == ipv6_port);
+ {
+ /* Fail microdesc fetches with all the primary guards */
+ args = tor_malloc_zero(sizeof(response_handler_args_t));
+ args->status_code = 404;
+ args->reason = NULL;
+ args->body = NULL;
+ args->body_len = 0;
+
+ conn = tor_malloc_zero(sizeof(dir_connection_t));
+ conn->requested_resource = tor_strdup("d/jlinblackorigami");
+ conn->base_.purpose = DIR_PURPOSE_FETCH_MICRODESC;
+
+ /* Pretend to fail fetches with all primary guards */
+ SMARTLIST_FOREACH_BEGIN(gs->primary_entry_guards,const entry_guard_t *,g) {
+ memcpy(conn->identity_digest, g->identity, DIGEST_LEN);
+
+ retval = handle_response_fetch_microdesc(conn, args);
+ tt_int_op(retval, OP_EQ, 0);
+ } SMARTLIST_FOREACH_END(g);
+ }
- mocked_options.ClientUseIPv4 = 0;
- node_get_pref_orport(&node, &ap);
- tt_assert(tor_addr_eq(&ap.addr, &ipv6_addr));
- tt_assert(ap.port == ipv6_port);
+ {
+ /* Now order the final md download */
+ setup_full_capture_of_logs(LOG_INFO);
+ initiate_descriptor_downloads(NULL, DIR_PURPOSE_FETCH_MICRODESC,
+ digests, 3, 7, 0);
- /* Check the preferred address is IPv6 if we don't prefer it, but
- * ClientUseIPv4 is 0 */
- mocked_options.ClientUseIPv4 = 0;
- mocked_options.ClientUseIPv6 = 1;
- node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(&mocked_options);
- node_get_pref_orport(&node, &ap);
- tt_assert(tor_addr_eq(&ap.addr, &ipv6_addr));
- tt_assert(ap.port == ipv6_port);
+ /* ... and check that because we failed to fetch microdescs from all our
+ * primaries, we didnt end up selecting a primary for fetching dir info */
+ expect_log_msg_containing("No primary or confirmed guards available.");
+ teardown_capture_of_logs();
+ }
done:
- UNMOCK(get_options);
+ smartlist_free(digests);
+ tor_free(args);
+ if (conn) {
+ tor_free(conn->requested_resource);
+ tor_free(conn);
+ }
}
-static const struct testcase_setup_t fake_network = {
- fake_network_setup, fake_network_cleanup
+static const struct testcase_setup_t big_fake_network = {
+ big_fake_network_setup, big_fake_network_cleanup
+};
+
+static const struct testcase_setup_t upgrade_circuits = {
+ upgrade_circuits_setup, upgrade_circuits_cleanup
};
+#define BFN_TEST(name) \
+ { #name, test_entry_guard_ ## name, TT_FORK, &big_fake_network, NULL }
+
+#define UPGRADE_TEST(name, arg) \
+ { #name, test_entry_guard_ ## name, TT_FORK, &upgrade_circuits, \
+ (void*)(arg) }
+
struct testcase_t entrynodes_tests[] = {
- { "entry_is_time_to_retry", test_entry_is_time_to_retry,
- TT_FORK, NULL, NULL },
- { "choose_random_entry_no_guards", test_choose_random_entry_no_guards,
- TT_FORK, &fake_network, NULL },
- { "choose_random_entry_one_possibleguard",
- test_choose_random_entry_one_possible_guard,
- TT_FORK, &fake_network, NULL },
- { "populate_live_entry_guards_1guard",
- test_populate_live_entry_guards_1guard,
- TT_FORK, &fake_network, NULL },
- { "populate_live_entry_guards_3guards",
- test_populate_live_entry_guards_3guards,
- TT_FORK, &fake_network, NULL },
- { "entry_guards_parse_state_simple",
- test_entry_guards_parse_state_simple,
- TT_FORK, &fake_network, NULL },
- { "entry_guards_parse_state_pathbias",
- test_entry_guards_parse_state_pathbias,
- TT_FORK, &fake_network, NULL },
- { "entry_guards_set_from_config",
- test_entry_guards_set_from_config,
- TT_FORK, &fake_network, NULL },
- { "entry_is_live",
- test_entry_is_live,
- TT_FORK, &fake_network, NULL },
{ "node_preferred_orport",
test_node_preferred_orport,
0, NULL, NULL },
+ { "entry_guard_describe", test_entry_guard_describe, 0, NULL, NULL },
+ { "randomize_time", test_entry_guard_randomize_time, 0, NULL, NULL },
+ { "encode_for_state_minimal",
+ test_entry_guard_encode_for_state_minimal, 0, NULL, NULL },
+ { "encode_for_state_maximal",
+ test_entry_guard_encode_for_state_maximal, 0, NULL, NULL },
+ { "parse_from_state_minimal",
+ test_entry_guard_parse_from_state_minimal, 0, NULL, NULL },
+ { "parse_from_state_maximal",
+ test_entry_guard_parse_from_state_maximal, 0, NULL, NULL },
+ { "parse_from_state_failure",
+ test_entry_guard_parse_from_state_failure, 0, NULL, NULL },
+ { "parse_from_state_partial_failure",
+ test_entry_guard_parse_from_state_partial_failure, 0, NULL, NULL },
+ { "parse_from_state_full",
+ test_entry_guard_parse_from_state_full, TT_FORK, NULL, NULL },
+ { "parse_from_state_broken",
+ test_entry_guard_parse_from_state_broken, TT_FORK, NULL, NULL },
+ { "get_guard_selection_by_name",
+ test_entry_guard_get_guard_selection_by_name, TT_FORK, NULL, NULL },
+ BFN_TEST(choose_selection_initial),
+ BFN_TEST(add_single_guard),
+ BFN_TEST(node_filter),
+ BFN_TEST(expand_sample),
+ BFN_TEST(expand_sample_small_net),
+ BFN_TEST(update_from_consensus_status),
+ BFN_TEST(update_from_consensus_repair),
+ BFN_TEST(update_from_consensus_remove),
+ BFN_TEST(confirming_guards),
+ BFN_TEST(sample_reachable_filtered),
+ BFN_TEST(sample_reachable_filtered_empty),
+ BFN_TEST(retry_unreachable),
+ BFN_TEST(manage_primary),
+ { "guard_preferred", test_entry_guard_guard_preferred, TT_FORK, NULL, NULL },
+ BFN_TEST(select_for_circuit_no_confirmed),
+ BFN_TEST(select_for_circuit_confirmed),
+ BFN_TEST(select_for_circuit_highlevel_primary),
+ BFN_TEST(select_for_circuit_highlevel_confirm_other),
+ BFN_TEST(select_for_circuit_highlevel_primary_retry),
+ BFN_TEST(select_and_cancel),
+ BFN_TEST(drop_guards),
+ BFN_TEST(outdated_dirserver_exclusion),
+
+ UPGRADE_TEST(upgrade_a_circuit, "c1-done c2-done"),
+ UPGRADE_TEST(upgrade_blocked_by_live_primary_guards, "c1-done c2-done"),
+ UPGRADE_TEST(upgrade_blocked_by_lack_of_waiting_circuits, ""),
+ UPGRADE_TEST(upgrade_blocked_by_better_circ_complete, "c1-done c2-done"),
+ UPGRADE_TEST(upgrade_not_blocked_by_restricted_circ_complete,
+ "c1-done c2-done"),
+ UPGRADE_TEST(upgrade_not_blocked_by_worse_circ_complete, "c1-done c2-done"),
+ UPGRADE_TEST(upgrade_blocked_by_better_circ_pending, "c2-done"),
+ UPGRADE_TEST(upgrade_not_blocked_by_restricted_circ_pending,
+ "c2-done"),
+ UPGRADE_TEST(upgrade_not_blocked_by_worse_circ_pending, "c1-done"),
+ { "should_expire_waiting", test_enty_guard_should_expire_waiting, TT_FORK,
+ NULL, NULL },
+
END_OF_TESTCASES
};
diff --git a/src/test/test_extorport.c b/src/test/test_extorport.c
index 1f92780177..e18deb2700 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,13 +72,13 @@ 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);
- write_to_buf(string, len, conn->outbuf);
+ buf_add(conn->outbuf, string, len);
}
static char *
@@ -89,7 +89,7 @@ buf_get_contents(buf_t *buf, size_t *sz_out)
if (*sz_out >= ULONG_MAX)
return NULL; /* C'mon, really? */
out = tor_malloc(*sz_out + 1);
- if (fetch_from_buf(out, (unsigned long)*sz_out, buf) != 0) {
+ if (buf_get_bytes(buf, out, (unsigned long)*sz_out) != 0) {
tor_free(out);
return NULL;
}
@@ -399,14 +399,14 @@ handshake_start(or_connection_t *conn, int receiving)
#define WRITE(s,n) \
do { \
- write_to_buf((s), (n), TO_CONN(conn)->inbuf); \
+ buf_add(TO_CONN(conn)->inbuf, (s), (n)); \
} while (0)
#define CONTAINS(s,n) \
do { \
tt_int_op((n), OP_LE, sizeof(b)); \
tt_int_op(buf_datalen(TO_CONN(conn)->outbuf), OP_EQ, (n)); \
if ((n)) { \
- fetch_from_buf(b, (n), TO_CONN(conn)->outbuf); \
+ buf_get_bytes(TO_CONN(conn)->outbuf, b, (n)); \
tt_mem_op(b, OP_EQ, (s), (n)); \
} \
} while (0)
@@ -497,14 +497,14 @@ test_ext_or_handshake(void *arg)
"te road There is always another ", 64);
/* Send the wrong response. */
WRITE("not with a bang but a whimper...", 32);
- MOCK(control_event_bootstrap_problem, ignore_bootstrap_problem);
+ MOCK(control_event_bootstrap_prob_or, ignore_bootstrap_problem);
tt_int_op(-1, OP_EQ, connection_ext_or_process_inbuf(conn));
CONTAINS("\x00", 1);
tt_assert(TO_CONN(conn)->marked_for_close);
/* XXXX Hold-open-until-flushed. */
close_closeable_connections();
conn = NULL;
- UNMOCK(control_event_bootstrap_problem);
+ UNMOCK(control_event_bootstrap_prob_or);
MOCK(connection_start_reading, note_read_started);
MOCK(connection_stop_reading, note_read_stopped);
@@ -552,26 +552,26 @@ test_ext_or_handshake(void *arg)
do_ext_or_handshake(conn);
/* USERADDR command with an extra NUL byte */
WRITE("\x00\x01\x00\x0d""1.2.3.4:5678\x00", 17);
- MOCK(control_event_bootstrap_problem, ignore_bootstrap_problem);
+ MOCK(control_event_bootstrap_prob_or, ignore_bootstrap_problem);
tt_int_op(-1, OP_EQ, connection_ext_or_process_inbuf(conn));
CONTAINS("", 0);
tt_assert(TO_CONN(conn)->marked_for_close);
close_closeable_connections();
conn = NULL;
- UNMOCK(control_event_bootstrap_problem);
+ UNMOCK(control_event_bootstrap_prob_or);
/* Now fail the TRANSPORT command. */
conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
do_ext_or_handshake(conn);
/* TRANSPORT command with an extra NUL byte */
WRITE("\x00\x02\x00\x08""rfc1149\x00", 12);
- MOCK(control_event_bootstrap_problem, ignore_bootstrap_problem);
+ MOCK(control_event_bootstrap_prob_or, ignore_bootstrap_problem);
tt_int_op(-1, OP_EQ, connection_ext_or_process_inbuf(conn));
CONTAINS("", 0);
tt_assert(TO_CONN(conn)->marked_for_close);
close_closeable_connections();
conn = NULL;
- UNMOCK(control_event_bootstrap_problem);
+ UNMOCK(control_event_bootstrap_prob_or);
/* Now fail the TRANSPORT command. */
conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
@@ -579,13 +579,13 @@ test_ext_or_handshake(void *arg)
/* TRANSPORT command with transport name with symbols (not a
C-identifier) */
WRITE("\x00\x02\x00\x07""rf*1149", 11);
- MOCK(control_event_bootstrap_problem, ignore_bootstrap_problem);
+ MOCK(control_event_bootstrap_prob_or, ignore_bootstrap_problem);
tt_int_op(-1, OP_EQ, connection_ext_or_process_inbuf(conn));
CONTAINS("", 0);
tt_assert(TO_CONN(conn)->marked_for_close);
close_closeable_connections();
conn = NULL;
- UNMOCK(control_event_bootstrap_problem);
+ UNMOCK(control_event_bootstrap_prob_or);
done:
UNMOCK(connection_write_to_buf_impl_);
diff --git a/src/test/test_guardfraction.c b/src/test/test_guardfraction.c
index 8173e44d47..51ca8f08ec 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
@@ -38,10 +38,10 @@ gen_vote_routerstatus_for_tests(const char *digest_in_hex, int is_guard)
rs->is_possible_guard = is_guard;
/* Fill in the fpr */
- tt_int_op(strlen(digest_in_hex), ==, HEX_DIGEST_LEN);
+ tt_int_op(strlen(digest_in_hex), OP_EQ, HEX_DIGEST_LEN);
retval = base16_decode(digest_tmp, sizeof(digest_tmp),
digest_in_hex, HEX_DIGEST_LEN);
- tt_int_op(retval, ==, sizeof(digest_tmp));
+ tt_int_op(retval, OP_EQ, sizeof(digest_tmp));
memcpy(rs->identity_digest, digest_tmp, DIGEST_LEN);
}
@@ -88,7 +88,7 @@ test_parse_guardfraction_file_bad(void *arg)
yesterday_date_str);
retval = dirserv_read_guardfraction_file_from_str(guardfraction_bad, NULL);
- tt_int_op(retval, ==, -1);
+ tt_int_op(retval, OP_EQ, -1);
tor_free(guardfraction_bad);
/* This one does not have a date! Parsing should fail. */
@@ -100,7 +100,7 @@ test_parse_guardfraction_file_bad(void *arg)
"guard-seen 07B5547026DF3E229806E135CFA8552D56AFBABC 5 420\n");
retval = dirserv_read_guardfraction_file_from_str(guardfraction_bad, NULL);
- tt_int_op(retval, ==, -1);
+ tt_int_op(retval, OP_EQ, -1);
tor_free(guardfraction_bad);
/* This one has an incomplete n-inputs line, but parsing should
@@ -114,7 +114,7 @@ test_parse_guardfraction_file_bad(void *arg)
yesterday_date_str);
retval = dirserv_read_guardfraction_file_from_str(guardfraction_bad, NULL);
- tt_int_op(retval, ==, 2);
+ tt_int_op(retval, OP_EQ, 2);
tor_free(guardfraction_bad);
/* This one does not have a fingerprint in the guard line! */
@@ -126,7 +126,7 @@ test_parse_guardfraction_file_bad(void *arg)
yesterday_date_str);
retval = dirserv_read_guardfraction_file_from_str(guardfraction_bad, NULL);
- tt_int_op(retval, ==, 0);
+ tt_int_op(retval, OP_EQ, 0);
tor_free(guardfraction_bad);
/* This one does not even have an integer guardfraction value. */
@@ -139,7 +139,7 @@ test_parse_guardfraction_file_bad(void *arg)
yesterday_date_str);
retval = dirserv_read_guardfraction_file_from_str(guardfraction_bad, NULL);
- tt_int_op(retval, ==, 1);
+ tt_int_op(retval, OP_EQ, 1);
tor_free(guardfraction_bad);
/* This one is not a percentage (not in [0, 100]) */
@@ -152,7 +152,7 @@ test_parse_guardfraction_file_bad(void *arg)
yesterday_date_str);
retval = dirserv_read_guardfraction_file_from_str(guardfraction_bad, NULL);
- tt_int_op(retval, ==, 1);
+ tt_int_op(retval, OP_EQ, 1);
tor_free(guardfraction_bad);
/* This one is not a percentage either (not in [0, 100]) */
@@ -164,7 +164,7 @@ test_parse_guardfraction_file_bad(void *arg)
yesterday_date_str);
retval = dirserv_read_guardfraction_file_from_str(guardfraction_bad, NULL);
- tt_int_op(retval, ==, 0);
+ tt_int_op(retval, OP_EQ, 0);
done:
tor_free(guardfraction_bad);
@@ -216,14 +216,14 @@ test_parse_guardfraction_file_good(void *arg)
/* Read the guardfraction file */
retval = dirserv_read_guardfraction_file_from_str(guardfraction_good,
routerstatuses);
- tt_int_op(retval, ==, 1);
+ tt_int_op(retval, OP_EQ, 1);
{ /* Test that routerstatus fields got filled properly */
/* The guardfraction fields of the guard should be filled. */
tt_assert(vrs_guard->status.has_guardfraction);
tt_int_op(vrs_guard->status.guardfraction_percentage,
- ==,
+ OP_EQ,
guardfraction_value);
/* The guard that was not in the guardfraction file should not have
@@ -252,12 +252,12 @@ test_get_guardfraction_bandwidth(void *arg)
guard_get_guardfraction_bandwidth(&gf_bw,
orig_bw, 25);
- tt_int_op(gf_bw.guard_bw, ==, 250);
- tt_int_op(gf_bw.non_guard_bw, ==, 750);
+ tt_int_op(gf_bw.guard_bw, OP_EQ, 250);
+ tt_int_op(gf_bw.non_guard_bw, OP_EQ, 750);
/* Also check the 'guard_bw + non_guard_bw == original_bw'
* invariant. */
- tt_int_op(gf_bw.non_guard_bw + gf_bw.guard_bw, ==, orig_bw);
+ tt_int_op(gf_bw.non_guard_bw + gf_bw.guard_bw, OP_EQ, orig_bw);
done:
;
@@ -295,9 +295,9 @@ test_parse_guardfraction_consensus(void *arg)
retval = routerstatus_parse_guardfraction(guardfraction_str_good,
NULL, NULL,
&rs_good);
- tt_int_op(retval, ==, 0);
+ tt_int_op(retval, OP_EQ, 0);
tt_assert(rs_good.has_guardfraction);
- tt_int_op(rs_good.guardfraction_percentage, ==, 66);
+ tt_int_op(rs_good.guardfraction_percentage, OP_EQ, 66);
}
{ /* Properly formatted GuardFraction but router is not a
@@ -309,7 +309,7 @@ test_parse_guardfraction_consensus(void *arg)
retval = routerstatus_parse_guardfraction(guardfraction_str_good,
NULL, NULL,
&rs_no_guard);
- tt_int_op(retval, ==, 0);
+ tt_int_op(retval, OP_EQ, 0);
tt_assert(!rs_no_guard.has_guardfraction);
expect_single_log_msg_containing("Got GuardFraction for non-guard . "
"This is not supposed to happen.");
@@ -323,7 +323,7 @@ test_parse_guardfraction_consensus(void *arg)
retval = routerstatus_parse_guardfraction(guardfraction_str_bad1,
NULL, NULL,
&rs_bad1);
- tt_int_op(retval, ==, -1);
+ tt_int_op(retval, OP_EQ, -1);
tt_assert(!rs_bad1.has_guardfraction);
}
@@ -334,7 +334,7 @@ test_parse_guardfraction_consensus(void *arg)
retval = routerstatus_parse_guardfraction(guardfraction_str_bad2,
NULL, NULL,
&rs_bad2);
- tt_int_op(retval, ==, -1);
+ tt_int_op(retval, OP_EQ, -1);
tt_assert(!rs_bad2.has_guardfraction);
}
@@ -375,27 +375,27 @@ test_should_apply_guardfraction(void *arg)
/* If torrc option is set to yes, we should always use
* guardfraction.*/
options->UseGuardFraction = 1;
- tt_int_op(should_apply_guardfraction(&vote_disabled), ==, 1);
+ tt_int_op(should_apply_guardfraction(&vote_disabled), OP_EQ, 1);
/* If torrc option is set to no, we should never use
* guardfraction.*/
options->UseGuardFraction = 0;
- tt_int_op(should_apply_guardfraction(&vote_enabled), ==, 0);
+ tt_int_op(should_apply_guardfraction(&vote_enabled), OP_EQ, 0);
/* Now let's test torrc option set to auto. */
options->UseGuardFraction = -1;
/* If torrc option is set to auto, and consensus parameter is set to
* yes, we should use guardfraction. */
- tt_int_op(should_apply_guardfraction(&vote_enabled), ==, 1);
+ tt_int_op(should_apply_guardfraction(&vote_enabled), OP_EQ, 1);
/* If torrc option is set to auto, and consensus parameter is set to
* no, we should use guardfraction. */
- tt_int_op(should_apply_guardfraction(&vote_disabled), ==, 0);
+ tt_int_op(should_apply_guardfraction(&vote_disabled), OP_EQ, 0);
/* If torrc option is set to auto, and consensus parameter is not
* set, we should fallback to "no". */
- tt_int_op(should_apply_guardfraction(&vote_missing), ==, 0);
+ tt_int_op(should_apply_guardfraction(&vote_missing), OP_EQ, 0);
done:
SMARTLIST_FOREACH(vote_enabled.net_params, char *, cp, tor_free(cp));
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 ae9fc7a243..0da9cf64d0 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 */
/**
@@ -7,14 +7,25 @@
*/
#define ROUTERLIST_PRIVATE
+#define CONFIG_PRIVATE
+#define CONNECTION_PRIVATE
+#define MAIN_PRIVATE
+
#include "orconfig.h"
#include "or.h"
-#include "routerlist.h"
+#include "buffers.h"
+#include "config.h"
+#include "confparse.h"
+#include "connection.h"
+#include "main.h"
#include "nodelist.h"
+#include "relay.h"
+#include "routerlist.h"
#include "test.h"
#include "test_helpers.h"
+#include "test_connection.h"
#ifdef HAVE_CFLAG_WOVERLENGTH_STRINGS
DISABLE_GCC_WARNING(overlength-strings)
@@ -22,6 +33,8 @@ DISABLE_GCC_WARNING(overlength-strings)
* at large. */
#endif
#include "test_descriptors.inc"
+#include "or.h"
+#include "circuitlist.h"
#ifdef HAVE_CFLAG_WOVERLENGTH_STRINGS
ENABLE_GCC_WARNING(overlength-strings)
#endif
@@ -70,16 +83,16 @@ helper_setup_fake_routerlist(void)
retval = router_load_routers_from_string(TEST_DESCRIPTORS,
NULL, SAVED_IN_JOURNAL,
NULL, 0, NULL);
- tt_int_op(retval, ==, HELPER_NUMBER_OF_DESCRIPTORS);
+ tt_int_op(retval, OP_EQ, HELPER_NUMBER_OF_DESCRIPTORS);
/* Sanity checking of routerlist and nodelist. */
our_routerlist = router_get_routerlist();
- tt_int_op(smartlist_len(our_routerlist->routers), ==,
+ tt_int_op(smartlist_len(our_routerlist->routers), OP_EQ,
HELPER_NUMBER_OF_DESCRIPTORS);
routerlist_assert_ok(our_routerlist);
our_nodelist = nodelist_get_list();
- tt_int_op(smartlist_len(our_nodelist), ==, HELPER_NUMBER_OF_DESCRIPTORS);
+ tt_int_op(smartlist_len(our_nodelist), OP_EQ, HELPER_NUMBER_OF_DESCRIPTORS);
/* Mark all routers as non-guards but up and running! */
SMARTLIST_FOREACH_BEGIN(our_nodelist, node_t *, node) {
@@ -92,3 +105,175 @@ helper_setup_fake_routerlist(void)
UNMOCK(router_descriptor_is_older_than);
}
+void
+connection_write_to_buf_mock(const char *string, size_t len,
+ connection_t *conn, int compressed)
+{
+ (void) compressed;
+
+ tor_assert(string);
+ tor_assert(conn);
+
+ buf_add(conn->outbuf, string, len);
+}
+
+/* Set up a fake origin circuit with the specified number of cells,
+ * Return a pointer to the newly-created dummy circuit */
+circuit_t *
+dummy_origin_circuit_new(int n_cells)
+{
+ origin_circuit_t *circ = origin_circuit_new();
+ int i;
+ cell_t cell;
+
+ for (i=0; i < n_cells; ++i) {
+ crypto_rand((void*)&cell, sizeof(cell));
+ cell_queue_append_packed_copy(TO_CIRCUIT(circ),
+ &TO_CIRCUIT(circ)->n_chan_cells,
+ 1, &cell, 1, 0);
+ }
+
+ TO_CIRCUIT(circ)->purpose = CIRCUIT_PURPOSE_C_GENERAL;
+ return TO_CIRCUIT(circ);
+}
+
+/** Mock-replacement. As tor_addr_lookup, but always fails on any
+ * address containing a !. This is necessary for running the unit tests
+ * on networks where DNS hijackers think it's helpful to give answers
+ * for things like 1.2.3.4.5 or "invalidstuff!!"
+ */
+int
+mock_tor_addr_lookup__fail_on_bad_addrs(const char *name,
+ uint16_t family, tor_addr_t *out)
+{
+ if (name && strchr(name, '!')) {
+ return -1;
+ }
+ return tor_addr_lookup__real(name, family, out);
+}
+
+/*********** Helper funcs for making new connections/streams *****************/
+
+/* Helper for test_conn_get_connection() */
+static int
+fake_close_socket(evutil_socket_t sock)
+{
+ (void)sock;
+ return 0;
+}
+
+static int mock_connection_connect_sockaddr_called = 0;
+static int fake_socket_number = TEST_CONN_FD_INIT;
+
+/* Helper for test_conn_get_connection() */
+static int
+mock_connection_connect_sockaddr(connection_t *conn,
+ const struct sockaddr *sa,
+ socklen_t sa_len,
+ const struct sockaddr *bindaddr,
+ socklen_t bindaddr_len,
+ int *socket_error)
+{
+ (void)sa_len;
+ (void)bindaddr;
+ (void)bindaddr_len;
+
+ tor_assert(conn);
+ tor_assert(sa);
+ tor_assert(socket_error);
+
+ mock_connection_connect_sockaddr_called++;
+
+ conn->s = fake_socket_number++;
+ tt_assert(SOCKET_OK(conn->s));
+ /* We really should call tor_libevent_initialize() here. Because we don't,
+ * we are relying on other parts of the code not checking if the_event_base
+ * (and therefore event->ev_base) is NULL. */
+ tt_int_op(connection_add_connecting(conn), OP_EQ, 0);
+
+ done:
+ /* Fake "connected" status */
+ return 1;
+}
+
+/** Create and return a new connection/stream */
+connection_t *
+test_conn_get_connection(uint8_t state, uint8_t type, uint8_t purpose)
+{
+ connection_t *conn = NULL;
+ tor_addr_t addr;
+ int socket_err = 0;
+ int in_progress = 0;
+
+ MOCK(connection_connect_sockaddr,
+ mock_connection_connect_sockaddr);
+ MOCK(tor_close_socket, fake_close_socket);
+
+ init_connection_lists();
+
+ conn = connection_new(type, TEST_CONN_FAMILY);
+ tt_assert(conn);
+
+ test_conn_lookup_addr_helper(TEST_CONN_ADDRESS, TEST_CONN_FAMILY, &addr);
+ tt_assert(!tor_addr_is_null(&addr));
+
+ tor_addr_copy_tight(&conn->addr, &addr);
+ conn->port = TEST_CONN_PORT;
+ mock_connection_connect_sockaddr_called = 0;
+ in_progress = connection_connect(conn, TEST_CONN_ADDRESS_PORT, &addr,
+ TEST_CONN_PORT, &socket_err);
+ tt_int_op(mock_connection_connect_sockaddr_called, OP_EQ, 1);
+ tt_assert(!socket_err);
+ tt_assert(in_progress == 0 || in_progress == 1);
+
+ /* fake some of the attributes so the connection looks OK */
+ conn->state = state;
+ conn->purpose = purpose;
+ assert_connection_ok(conn, time(NULL));
+
+ UNMOCK(connection_connect_sockaddr);
+ UNMOCK(tor_close_socket);
+ return conn;
+
+ /* On failure */
+ done:
+ UNMOCK(connection_connect_sockaddr);
+ UNMOCK(tor_close_socket);
+ return NULL;
+}
+
+/* Helper function to parse a set of torrc options in a text format and return
+ * a newly allocated or_options_t object containing the configuration. On
+ * error, NULL is returned indicating that the conf couldn't be parsed
+ * properly. */
+or_options_t *
+helper_parse_options(const char *conf)
+{
+ int ret = 0;
+ char *msg = NULL;
+ or_options_t *opt = NULL;
+ config_line_t *line = NULL;
+
+ /* Kind of pointless to call this with a NULL value. */
+ tt_assert(conf);
+
+ opt = options_new();
+ tt_assert(opt);
+ ret = config_get_lines(conf, &line, 1);
+ if (ret != 0) {
+ goto done;
+ }
+ ret = config_assign(&options_format, opt, line, 0, &msg);
+ if (ret != 0) {
+ goto done;
+ }
+
+ done:
+ config_free_lines(line);
+ if (ret != 0) {
+ or_options_free(opt);
+ opt = NULL;
+ }
+ return opt;
+}
+
diff --git a/src/test/test_helpers.h b/src/test/test_helpers.h
index 684375e1b1..9bc8553257 100644
--- a/src/test/test_helpers.h
+++ b/src/test/test_helpers.h
@@ -1,17 +1,32 @@
-/* Copyright (c) 2014-2016, The Tor Project, Inc. */
+/* Copyright (c) 2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_TEST_HELPERS_H
#define TOR_TEST_HELPERS_H
+#include "or.h"
+
const char *get_yesterday_date_str(void);
+circuit_t * dummy_origin_circuit_new(int num_cells);
+
/* Number of descriptors contained in test_descriptors.txt. */
#define HELPER_NUMBER_OF_DESCRIPTORS 8
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 compressed);
+
+int mock_tor_addr_lookup__fail_on_bad_addrs(const char *name,
+ uint16_t family, tor_addr_t *out);
+
+connection_t *test_conn_get_connection(uint8_t state,
+ uint8_t type, uint8_t purpose);
+or_options_t *helper_parse_options(const char *conf);
+
extern const char TEST_DESCRIPTORS[];
-#endif
+#endif /* !defined(TOR_TEST_HELPERS_H) */
diff --git a/src/test/test_hs.c b/src/test/test_hs.c
index d572dd8d2e..09db176df8 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 */
/**
@@ -8,12 +8,15 @@
#define CONTROL_PRIVATE
#define CIRCUITBUILD_PRIVATE
+#define RENDCOMMON_PRIVATE
#define RENDSERVICE_PRIVATE
+#define HS_SERVICE_PRIVATE
#include "or.h"
#include "test.h"
#include "control.h"
#include "config.h"
+#include "hs_common.h"
#include "rendcommon.h"
#include "rendservice.h"
#include "routerset.h"
@@ -31,8 +34,9 @@
#define STR_HSDIR_NONE_EXIST_LONGNAME \
"$BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
-/* DuckDuckGo descriptor as an example. */
-static const char *hs_desc_content = "\
+/* DuckDuckGo descriptor as an example. This one has extra "\r" at the end so
+ * the control port is happy. */
+static const char *hs_desc_content_control = "\
rendezvous-service-descriptor g5ojobzupf275beh5ra72uyhb3dkpxwg\r\n\
version 2\r\n\
permanent-key\r\n\
@@ -93,6 +97,68 @@ PcftsZf2ztN0sbNCtPgDL3d0PqvxY3iHTQAI8EbaGq/IAJUZ8U4y963dD5+Bn6JQ\r\n\
myE3ctmh0vy5+QxSiRjmQBkuEpCyks7LvWvHYrhnmcg=\r\n\
-----END SIGNATURE-----";
+/* DuckDuckGo descriptor as an example. */
+static const char *hs_desc_content = "\
+rendezvous-service-descriptor g5ojobzupf275beh5ra72uyhb3dkpxwg\n\
+version 2\n\
+permanent-key\n\
+-----BEGIN RSA PUBLIC KEY-----\n\
+MIGJAoGBAJ/SzzgrXPxTlFrKVhXh3buCWv2QfcNgncUpDpKouLn3AtPH5Ocys0jE\n\
+aZSKdvaiQ62md2gOwj4x61cFNdi05tdQjS+2thHKEm/KsB9BGLSLBNJYY356bupg\n\
+I5gQozM65ENelfxYlysBjJ52xSDBd8C4f/p9umdzaaaCmzXG/nhzAgMBAAE=\n\
+-----END RSA PUBLIC KEY-----\n\
+secret-id-part anmjoxxwiupreyajjt5yasimfmwcnxlf\n\
+publication-time 2015-03-11 19:00:00\n\
+protocol-versions 2,3\n\
+introduction-points\n\
+-----BEGIN MESSAGE-----\n\
+aW50cm9kdWN0aW9uLXBvaW50IDd1bnd4cmg2dG5kNGh6eWt1Z3EzaGZzdHduc2ll\n\
+cmhyCmlwLWFkZHJlc3MgMTg4LjEzOC4xMjEuMTE4Cm9uaW9uLXBvcnQgOTAwMQpv\n\
+bmlvbi1rZXkKLS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JR0pBb0dC\n\
+QUxGRVVyeVpDbk9ROEhURmV5cDVjMTRObWVqL1BhekFLTTBxRENTNElKUWh0Y3g1\n\
+NXpRSFdOVWIKQ2hHZ0JqR1RjV3ZGRnA0N3FkdGF6WUZhVXE2c0lQKzVqeWZ5b0Q4\n\
+UmJ1bzBwQmFWclJjMmNhYUptWWM0RDh6Vgpuby9sZnhzOVVaQnZ1cWY4eHIrMDB2\n\
+S0JJNmFSMlA2OE1WeDhrMExqcUpUU2RKOE9idm9yQWdNQkFBRT0KLS0tLS1FTkQg\n\
+UlNBIFBVQkxJQyBLRVktLS0tLQpzZXJ2aWNlLWtleQotLS0tLUJFR0lOIFJTQSBQ\n\
+VUJMSUMgS0VZLS0tLS0KTUlHSkFvR0JBTnJHb0ozeTlHNXQzN2F2ekI1cTlwN1hG\n\
+VUplRUVYMUNOaExnWmJXWGJhVk5OcXpoZFhyL0xTUQppM1Z6dW5OaUs3cndUVnE2\n\
+K2QyZ1lRckhMMmIvMXBBY3ZKWjJiNSs0bTRRc0NibFpjRENXTktRbHJnRWN5WXRJ\n\
+CkdscXJTbFFEaXA0ZnNrUFMvNDVkWTI0QmJsQ3NGU1k3RzVLVkxJck4zZFpGbmJr\n\
+NEZIS1hBZ01CQUFFPQotLS0tLUVORCBSU0EgUFVCTElDIEtFWS0tLS0tCmludHJv\n\
+ZHVjdGlvbi1wb2ludCBiNGM3enlxNXNheGZzN2prNXFibG1wN3I1b3pwdHRvagpp\n\
+cC1hZGRyZXNzIDEwOS4xNjkuNDUuMjI2Cm9uaW9uLXBvcnQgOTAwMQpvbmlvbi1r\n\
+ZXkKLS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JR0pBb0dCQU8xSXpw\n\
+WFFUTUY3RXZUb1NEUXpzVnZiRVFRQUQrcGZ6NzczMVRXZzVaUEJZY1EyUkRaeVp4\n\
+OEQKNUVQSU1FeUE1RE83cGd0ak5LaXJvYXJGMC8yempjMkRXTUlSaXZyU29YUWVZ\n\
+ZXlMM1pzKzFIajJhMDlCdkYxZAp6MEswblRFdVhoNVR5V3lyMHdsbGI1SFBnTlI0\n\
+MS9oYkprZzkwZitPVCtIeGhKL1duUml2QWdNQkFBRT0KLS0tLS1FTkQgUlNBIFBV\n\
+QkxJQyBLRVktLS0tLQpzZXJ2aWNlLWtleQotLS0tLUJFR0lOIFJTQSBQVUJMSUMg\n\
+S0VZLS0tLS0KTUlHSkFvR0JBSzNWZEJ2ajFtQllLL3JrcHNwcm9Ub0llNUtHVmth\n\
+QkxvMW1tK1I2YUVJek1VZFE1SjkwNGtyRwpCd3k5NC8rV0lGNFpGYXh5Z2phejl1\n\
+N2pKY1k3ZGJhd1pFeG1hYXFCRlRwL2h2ZG9rcHQ4a1ByRVk4OTJPRHJ1CmJORUox\n\
+N1FPSmVMTVZZZk5Kcjl4TWZCQ3JQai8zOGh2RUdrbWVRNmRVWElvbVFNaUJGOVRB\n\
+Z01CQUFFPQotLS0tLUVORCBSU0EgUFVCTElDIEtFWS0tLS0tCmludHJvZHVjdGlv\n\
+bi1wb2ludCBhdjVtcWl0Y2Q3cjJkandsYmN0c2Jlc2R3eGt0ZWtvegppcC1hZGRy\n\
+ZXNzIDE0NC43Ni44LjczCm9uaW9uLXBvcnQgNDQzCm9uaW9uLWtleQotLS0tLUJF\n\
+R0lOIFJTQSBQVUJMSUMgS0VZLS0tLS0KTUlHSkFvR0JBTzVweVZzQmpZQmNmMXBE\n\
+dklHUlpmWXUzQ05nNldka0ZLMGlvdTBXTGZtejZRVDN0NWhzd3cyVwpjejlHMXhx\n\
+MmN0Nkd6VWkrNnVkTDlITTRVOUdHTi9BbW8wRG9GV1hKWHpBQkFXd2YyMVdsd1lW\n\
+eFJQMHRydi9WCkN6UDkzcHc5OG5vSmdGUGRUZ05iMjdKYmVUZENLVFBrTEtscXFt\n\
+b3NveUN2RitRa25vUS9BZ01CQUFFPQotLS0tLUVORCBSU0EgUFVCTElDIEtFWS0t\n\
+LS0tCnNlcnZpY2Uta2V5Ci0tLS0tQkVHSU4gUlNBIFBVQkxJQyBLRVktLS0tLQpN\n\
+SUdKQW9HQkFMVjNKSmtWN3lTNU9jc1lHMHNFYzFQOTVRclFRR3ZzbGJ6Wi9zRGxl\n\
+RlpKYXFSOUYvYjRUVERNClNGcFMxcU1GbldkZDgxVmRGMEdYRmN2WVpLamRJdHU2\n\
+SndBaTRJeEhxeXZtdTRKdUxrcXNaTEFLaXRLVkx4eGsKeERlMjlDNzRWMmJrOTRJ\n\
+MEgybTNKS2tzTHVwc3VxWWRVUmhOVXN0SElKZmgyZmNIalF0bEFnTUJBQUU9Ci0t\n\
+LS0tRU5EIFJTQSBQVUJMSUMgS0VZLS0tLS0KCg==\n\
+-----END MESSAGE-----\n\
+signature\n\
+-----BEGIN SIGNATURE-----\n\
+d4OuCE5OLAOnRB6cQN6WyMEmg/BHem144Vec+eYgeWoKwx3MxXFplUjFxgnMlmwN\n\
+PcftsZf2ztN0sbNCtPgDL3d0PqvxY3iHTQAI8EbaGq/IAJUZ8U4y963dD5+Bn6JQ\n\
+myE3ctmh0vy5+QxSiRjmQBkuEpCyks7LvWvHYrhnmcg=\n\
+-----END SIGNATURE-----";
+
/* Helper global variable for hidden service descriptor event test.
* It's used as a pointer to dynamically created message buffer in
* send_control_event_string_replacement function, which mocks
@@ -124,6 +190,30 @@ node_describe_longname_by_id_replacement(const char *id_digest)
}
}
+/** Test that we can parse a hardcoded v2 HS desc. */
+static void
+test_hs_parse_static_v2_desc(void *arg)
+{
+ int ret;
+ rend_encoded_v2_service_descriptor_t desc;
+
+ (void) arg;
+
+ /* Test an obviously not parseable string */
+ desc.desc_str = tor_strdup("ceci n'est pas un HS descriptor");
+ ret = rend_desc_v2_is_parsable(&desc);
+ tor_free(desc.desc_str);
+ tt_int_op(ret, OP_EQ, 0);
+
+ /* Test an actual descriptor */
+ desc.desc_str = tor_strdup(hs_desc_content);
+ ret = rend_desc_v2_is_parsable(&desc);
+ tor_free(desc.desc_str);
+ tt_int_op(ret, OP_EQ, 1);
+
+ done: ;
+}
+
/** Make sure each hidden service descriptor async event generation
*
* function generates the message in expected format.
@@ -136,7 +226,7 @@ test_hs_desc_event(void *arg)
#define STR_DESC_ID_BASE32 "hba3gmcgpfivzfhx5rtfqkfdhv65yrj3"
int ret;
- rend_data_t rend_query;
+ rend_data_v2_t rend_query;
const char *expected_msg;
char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
@@ -148,18 +238,19 @@ test_hs_desc_event(void *arg)
/* setup rend_query struct */
memset(&rend_query, 0, sizeof(rend_query));
+ rend_query.base_.version = 2;
strncpy(rend_query.onion_address, STR_HS_ADDR,
REND_SERVICE_ID_LEN_BASE32+1);
rend_query.auth_type = REND_NO_AUTH;
- rend_query.hsdirs_fp = smartlist_new();
- smartlist_add(rend_query.hsdirs_fp, tor_memdup(HSDIR_EXIST_ID,
- DIGEST_LEN));
+ rend_query.base_.hsdirs_fp = smartlist_new();
+ smartlist_add(rend_query.base_.hsdirs_fp, tor_memdup(HSDIR_EXIST_ID,
+ DIGEST_LEN));
/* Compute descriptor ID for replica 0, should be STR_DESC_ID_BASE32. */
ret = rend_compute_v2_desc_id(rend_query.descriptor_id[0],
rend_query.onion_address,
NULL, 0, 0);
- tt_int_op(ret, ==, 0);
+ tt_int_op(ret, OP_EQ, 0);
base32_encode(desc_id_base32, sizeof(desc_id_base32),
rend_query.descriptor_id[0], DIGEST_LEN);
/* Make sure rend_compute_v2_desc_id works properly. */
@@ -167,7 +258,7 @@ test_hs_desc_event(void *arg)
sizeof(desc_id_base32));
/* test request event */
- control_event_hs_descriptor_requested(&rend_query, HSDIR_EXIST_ID,
+ control_event_hs_descriptor_requested(&rend_query.base_, HSDIR_EXIST_ID,
STR_DESC_ID_BASE32);
expected_msg = "650 HS_DESC REQUESTED "STR_HS_ADDR" NO_AUTH "\
STR_HSDIR_EXIST_LONGNAME " " STR_DESC_ID_BASE32 "\r\n";
@@ -178,7 +269,7 @@ test_hs_desc_event(void *arg)
/* test received event */
rend_query.auth_type = REND_BASIC_AUTH;
control_event_hs_descriptor_received(rend_query.onion_address,
- &rend_query, HSDIR_EXIST_ID);
+ &rend_query.base_, HSDIR_EXIST_ID);
expected_msg = "650 HS_DESC RECEIVED "STR_HS_ADDR" BASIC_AUTH "\
STR_HSDIR_EXIST_LONGNAME " " STR_DESC_ID_BASE32"\r\n";
tt_assert(received_msg);
@@ -187,7 +278,7 @@ test_hs_desc_event(void *arg)
/* test failed event */
rend_query.auth_type = REND_STEALTH_AUTH;
- control_event_hs_descriptor_failed(&rend_query,
+ control_event_hs_descriptor_failed(&rend_query.base_,
HSDIR_NONE_EXIST_ID,
"QUERY_REJECTED");
expected_msg = "650 HS_DESC FAILED "STR_HS_ADDR" STEALTH_AUTH "\
@@ -198,7 +289,7 @@ test_hs_desc_event(void *arg)
/* test invalid auth type */
rend_query.auth_type = 999;
- control_event_hs_descriptor_failed(&rend_query,
+ control_event_hs_descriptor_failed(&rend_query.base_,
HSDIR_EXIST_ID,
"QUERY_REJECTED");
expected_msg = "650 HS_DESC FAILED "STR_HS_ADDR" UNKNOWN "\
@@ -208,21 +299,42 @@ test_hs_desc_event(void *arg)
tt_str_op(received_msg,OP_EQ, expected_msg);
tor_free(received_msg);
- /* test valid content. */
+ /* test no HSDir fingerprint type */
+ rend_query.auth_type = REND_NO_AUTH;
+ control_event_hs_descriptor_failed(&rend_query.base_, NULL,
+ "QUERY_NO_HSDIR");
+ expected_msg = "650 HS_DESC FAILED "STR_HS_ADDR" NO_AUTH " \
+ "UNKNOWN REASON=QUERY_NO_HSDIR\r\n";
+ tt_assert(received_msg);
+ tt_str_op(received_msg,OP_EQ, expected_msg);
+ tor_free(received_msg);
+
+ /* Test invalid content with no HSDir fingerprint. */
char *exp_msg;
control_event_hs_descriptor_content(rend_query.onion_address,
+ STR_HS_CONTENT_DESC_ID, NULL, NULL);
+ tor_asprintf(&exp_msg, "650+HS_DESC_CONTENT " STR_HS_ADDR " "\
+ STR_HS_CONTENT_DESC_ID " UNKNOWN" \
+ "\r\n\r\n.\r\n650 OK\r\n");
+ tt_assert(received_msg);
+ tt_str_op(received_msg, OP_EQ, exp_msg);
+ tor_free(received_msg);
+ tor_free(exp_msg);
+
+ /* test valid content. */
+ control_event_hs_descriptor_content(rend_query.onion_address,
STR_HS_CONTENT_DESC_ID, HSDIR_EXIST_ID,
- hs_desc_content);
+ hs_desc_content_control);
tor_asprintf(&exp_msg, "650+HS_DESC_CONTENT " STR_HS_ADDR " "\
STR_HS_CONTENT_DESC_ID " " STR_HSDIR_EXIST_LONGNAME\
- "\r\n%s\r\n.\r\n650 OK\r\n", hs_desc_content);
+ "\r\n%s\r\n.\r\n650 OK\r\n", hs_desc_content_control);
tt_assert(received_msg);
tt_str_op(received_msg, OP_EQ, exp_msg);
tor_free(received_msg);
tor_free(exp_msg);
- SMARTLIST_FOREACH(rend_query.hsdirs_fp, char *, d, tor_free(d));
- smartlist_free(rend_query.hsdirs_fp);
+ SMARTLIST_FOREACH(rend_query.base_.hsdirs_fp, char *, d, tor_free(d));
+ smartlist_free(rend_query.base_.hsdirs_fp);
done:
UNMOCK(queue_control_event_string);
@@ -251,14 +363,14 @@ test_pick_tor2web_rendezvous_node(void *arg)
retval = routerset_parse(options->Tor2webRendezvousPoints,
tor2web_rendezvous_str,
"test_tor2web_rp");
- tt_int_op(retval, >=, 0);
+ tt_int_op(retval, OP_GE, 0);
/* Pick rendezvous point. Make sure the correct one is
picked. Repeat many times to make sure it works properly. */
for (i = 0; i < 50 ; i++) {
chosen_rp = pick_tor2web_rendezvous_node(flags, options);
tt_assert(chosen_rp);
- tt_str_op(chosen_rp->ri->nickname, ==, tor2web_rendezvous_str);
+ tt_str_op(chosen_rp->ri->nickname, OP_EQ, tor2web_rendezvous_str);
}
done:
@@ -286,13 +398,13 @@ test_pick_bad_tor2web_rendezvous_node(void *arg)
retval = routerset_parse(options->Tor2webRendezvousPoints,
tor2web_rendezvous_str,
"test_tor2web_rp");
- tt_int_op(retval, >=, 0);
+ tt_int_op(retval, OP_GE, 0);
/* Pick rendezvous point. Since Tor2webRendezvousPoints was set to a
dummy value, we shouldn't find any eligible RPs. */
for (i = 0; i < 50 ; i++) {
chosen_rp = pick_tor2web_rendezvous_node(flags, options);
- tt_assert(!chosen_rp);
+ tt_ptr_op(chosen_rp, OP_EQ, NULL);
}
done:
@@ -322,43 +434,47 @@ test_hs_rend_data(void *arg)
client = rend_data_client_create(STR_HS_ADDR, desc_id, client_cookie,
REND_NO_AUTH);
tt_assert(client);
- tt_int_op(client->auth_type, ==, REND_NO_AUTH);
- tt_str_op(client->onion_address, OP_EQ, STR_HS_ADDR);
- tt_mem_op(client->desc_id_fetch, OP_EQ, desc_id, sizeof(desc_id));
- tt_mem_op(client->descriptor_cookie, OP_EQ, client_cookie,
+ rend_data_v2_t *client_v2 = TO_REND_DATA_V2(client);
+ tt_int_op(client_v2->auth_type, OP_EQ, REND_NO_AUTH);
+ tt_str_op(client_v2->onion_address, OP_EQ, STR_HS_ADDR);
+ tt_mem_op(client_v2->desc_id_fetch, OP_EQ, desc_id, sizeof(desc_id));
+ tt_mem_op(client_v2->descriptor_cookie, OP_EQ, client_cookie,
sizeof(client_cookie));
tt_assert(client->hsdirs_fp);
- tt_int_op(smartlist_len(client->hsdirs_fp), ==, 0);
+ tt_int_op(smartlist_len(client->hsdirs_fp), OP_EQ, 0);
for (rep = 0; rep < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; rep++) {
- int ret = rend_compute_v2_desc_id(desc_id, client->onion_address,
- client->descriptor_cookie, now, rep);
+ int ret = rend_compute_v2_desc_id(desc_id, client_v2->onion_address,
+ client_v2->descriptor_cookie, now, rep);
/* That shouldn't never fail. */
- tt_int_op(ret, ==, 0);
- tt_mem_op(client->descriptor_id[rep], OP_EQ, desc_id, sizeof(desc_id));
+ tt_int_op(ret, OP_EQ, 0);
+ tt_mem_op(client_v2->descriptor_id[rep], OP_EQ, desc_id,
+ sizeof(desc_id));
}
/* The rest should be zeroed because this is a client request. */
- tt_int_op(tor_digest_is_zero(client->rend_pk_digest), ==, 1);
- tt_int_op(tor_digest_is_zero(client->rend_cookie), ==, 1);
+ tt_int_op(tor_digest_is_zero(client_v2->rend_pk_digest), OP_EQ, 1);
+ tt_int_op(tor_digest_is_zero(client->rend_cookie), OP_EQ, 1);
/* Test dup(). */
client_dup = rend_data_dup(client);
tt_assert(client_dup);
- tt_int_op(client_dup->auth_type, ==, client->auth_type);
- tt_str_op(client_dup->onion_address, OP_EQ, client->onion_address);
- tt_mem_op(client_dup->desc_id_fetch, OP_EQ, client->desc_id_fetch,
- sizeof(client_dup->desc_id_fetch));
- tt_mem_op(client_dup->descriptor_cookie, OP_EQ, client->descriptor_cookie,
- sizeof(client_dup->descriptor_cookie));
+ rend_data_v2_t *client_dup_v2 = TO_REND_DATA_V2(client_dup);
+ tt_int_op(client_dup_v2->auth_type, OP_EQ, client_v2->auth_type);
+ tt_str_op(client_dup_v2->onion_address, OP_EQ, client_v2->onion_address);
+ tt_mem_op(client_dup_v2->desc_id_fetch, OP_EQ, client_v2->desc_id_fetch,
+ sizeof(client_dup_v2->desc_id_fetch));
+ tt_mem_op(client_dup_v2->descriptor_cookie, OP_EQ,
+ client_v2->descriptor_cookie,
+ sizeof(client_dup_v2->descriptor_cookie));
tt_assert(client_dup->hsdirs_fp);
- tt_int_op(smartlist_len(client_dup->hsdirs_fp), ==, 0);
+ tt_int_op(smartlist_len(client_dup->hsdirs_fp), OP_EQ, 0);
for (rep = 0; rep < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; rep++) {
- tt_mem_op(client_dup->descriptor_id[rep], OP_EQ,
- client->descriptor_id[rep], DIGEST_LEN);
+ tt_mem_op(client_dup_v2->descriptor_id[rep], OP_EQ,
+ client_v2->descriptor_id[rep], DIGEST_LEN);
}
/* The rest should be zeroed because this is a client request. */
- tt_int_op(tor_digest_is_zero(client_dup->rend_pk_digest), ==, 1);
- tt_int_op(tor_digest_is_zero(client_dup->rend_cookie), ==, 1);
+ tt_int_op(tor_digest_is_zero(client_dup_v2->rend_pk_digest), OP_EQ, 1);
+ tt_int_op(tor_digest_is_zero(client_dup->rend_cookie), OP_EQ, 1);
rend_data_free(client);
client = NULL;
rend_data_free(client_dup);
@@ -373,19 +489,20 @@ test_hs_rend_data(void *arg)
* zeroed out. */
client = rend_data_client_create(NULL, desc_id, NULL, REND_BASIC_AUTH);
tt_assert(client);
- tt_int_op(client->auth_type, ==, REND_BASIC_AUTH);
- tt_int_op(strlen(client->onion_address), ==, 0);
- tt_mem_op(client->desc_id_fetch, OP_EQ, desc_id, sizeof(desc_id));
- tt_int_op(tor_mem_is_zero(client->descriptor_cookie,
- sizeof(client->descriptor_cookie)), ==, 1);
+ client_v2 = TO_REND_DATA_V2(client);
+ tt_int_op(client_v2->auth_type, OP_EQ, REND_BASIC_AUTH);
+ tt_int_op(strlen(client_v2->onion_address), OP_EQ, 0);
+ tt_mem_op(client_v2->desc_id_fetch, OP_EQ, desc_id, sizeof(desc_id));
+ tt_int_op(tor_mem_is_zero(client_v2->descriptor_cookie,
+ sizeof(client_v2->descriptor_cookie)), OP_EQ, 1);
tt_assert(client->hsdirs_fp);
- tt_int_op(smartlist_len(client->hsdirs_fp), ==, 0);
+ tt_int_op(smartlist_len(client->hsdirs_fp), OP_EQ, 0);
for (rep = 0; rep < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; rep++) {
- tt_int_op(tor_digest_is_zero(client->descriptor_id[rep]), ==, 1);
+ tt_int_op(tor_digest_is_zero(client_v2->descriptor_id[rep]), OP_EQ, 1);
}
/* The rest should be zeroed because this is a client request. */
- tt_int_op(tor_digest_is_zero(client->rend_pk_digest), ==, 1);
- tt_int_op(tor_digest_is_zero(client->rend_cookie), ==, 1);
+ tt_int_op(tor_digest_is_zero(client_v2->rend_pk_digest), OP_EQ, 1);
+ tt_int_op(tor_digest_is_zero(client->rend_cookie), OP_EQ, 1);
rend_data_free(client);
client = NULL;
@@ -398,37 +515,39 @@ test_hs_rend_data(void *arg)
service = rend_data_service_create(STR_HS_ADDR, rend_pk_digest,
rend_cookie, REND_NO_AUTH);
tt_assert(service);
- tt_int_op(service->auth_type, ==, REND_NO_AUTH);
- tt_str_op(service->onion_address, OP_EQ, STR_HS_ADDR);
- tt_mem_op(service->rend_pk_digest, OP_EQ, rend_pk_digest,
+ rend_data_v2_t *service_v2 = TO_REND_DATA_V2(service);
+ tt_int_op(service_v2->auth_type, OP_EQ, REND_NO_AUTH);
+ tt_str_op(service_v2->onion_address, OP_EQ, STR_HS_ADDR);
+ tt_mem_op(service_v2->rend_pk_digest, OP_EQ, rend_pk_digest,
sizeof(rend_pk_digest));
tt_mem_op(service->rend_cookie, OP_EQ, rend_cookie, sizeof(rend_cookie));
tt_assert(service->hsdirs_fp);
- tt_int_op(smartlist_len(service->hsdirs_fp), ==, 0);
+ tt_int_op(smartlist_len(service->hsdirs_fp), OP_EQ, 0);
for (rep = 0; rep < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; rep++) {
- tt_int_op(tor_digest_is_zero(service->descriptor_id[rep]), ==, 1);
+ tt_int_op(tor_digest_is_zero(service_v2->descriptor_id[rep]), OP_EQ, 1);
}
/* The rest should be zeroed because this is a service request. */
- tt_int_op(tor_digest_is_zero(service->descriptor_cookie), ==, 1);
- tt_int_op(tor_digest_is_zero(service->desc_id_fetch), ==, 1);
+ tt_int_op(tor_digest_is_zero(service_v2->descriptor_cookie), OP_EQ, 1);
+ tt_int_op(tor_digest_is_zero(service_v2->desc_id_fetch), OP_EQ, 1);
/* Test dup(). */
service_dup = rend_data_dup(service);
+ rend_data_v2_t *service_dup_v2 = TO_REND_DATA_V2(service_dup);
tt_assert(service_dup);
- tt_int_op(service_dup->auth_type, ==, service->auth_type);
- tt_str_op(service_dup->onion_address, OP_EQ, service->onion_address);
- tt_mem_op(service_dup->rend_pk_digest, OP_EQ, service->rend_pk_digest,
- sizeof(service_dup->rend_pk_digest));
+ tt_int_op(service_dup_v2->auth_type, OP_EQ, service_v2->auth_type);
+ tt_str_op(service_dup_v2->onion_address, OP_EQ, service_v2->onion_address);
+ tt_mem_op(service_dup_v2->rend_pk_digest, OP_EQ, service_v2->rend_pk_digest,
+ sizeof(service_dup_v2->rend_pk_digest));
tt_mem_op(service_dup->rend_cookie, OP_EQ, service->rend_cookie,
sizeof(service_dup->rend_cookie));
tt_assert(service_dup->hsdirs_fp);
- tt_int_op(smartlist_len(service_dup->hsdirs_fp), ==, 0);
+ tt_int_op(smartlist_len(service_dup->hsdirs_fp), OP_EQ, 0);
for (rep = 0; rep < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; rep++) {
- tt_int_op(tor_digest_is_zero(service_dup->descriptor_id[rep]), ==, 1);
+ tt_assert(tor_digest_is_zero(service_dup_v2->descriptor_id[rep]));
}
/* The rest should be zeroed because this is a service request. */
- tt_int_op(tor_digest_is_zero(service_dup->descriptor_cookie), ==, 1);
- tt_int_op(tor_digest_is_zero(service_dup->desc_id_fetch), ==, 1);
+ tt_int_op(tor_digest_is_zero(service_dup_v2->descriptor_cookie), OP_EQ, 1);
+ tt_int_op(tor_digest_is_zero(service_dup_v2->desc_id_fetch), OP_EQ, 1);
done:
rend_data_free(service);
@@ -467,7 +586,7 @@ test_hs_auth_cookies(void *arg)
re = rend_auth_decode_cookie(TEST_COOKIE_ENCODED, raw_cookie, &auth_type,
&err_msg);
tt_assert(!re);
- tt_assert(!err_msg);
+ tt_ptr_op(err_msg, OP_EQ, NULL);
tt_mem_op(raw_cookie, OP_EQ, TEST_COOKIE_RAW, REND_DESC_COOKIE_LEN);
tt_int_op(auth_type, OP_EQ, REND_BASIC_AUTH);
memset(raw_cookie, 0, sizeof(raw_cookie));
@@ -475,7 +594,7 @@ test_hs_auth_cookies(void *arg)
re = rend_auth_decode_cookie(TEST_COOKIE_ENCODED_STEALTH, raw_cookie,
&auth_type, &err_msg);
tt_assert(!re);
- tt_assert(!err_msg);
+ tt_ptr_op(err_msg, OP_EQ, NULL);
tt_mem_op(raw_cookie, OP_EQ, TEST_COOKIE_RAW, REND_DESC_COOKIE_LEN);
tt_int_op(auth_type, OP_EQ, REND_STEALTH_AUTH);
memset(raw_cookie, 0, sizeof(raw_cookie));
@@ -484,7 +603,7 @@ test_hs_auth_cookies(void *arg)
re = rend_auth_decode_cookie(TEST_COOKIE_ENCODED "==", raw_cookie, NULL,
&err_msg);
tt_assert(!re);
- tt_assert(!err_msg);
+ tt_ptr_op(err_msg, OP_EQ, NULL);
tt_mem_op(raw_cookie, OP_EQ, TEST_COOKIE_RAW, REND_DESC_COOKIE_LEN);
/* Decoding with an unknown type should fail */
@@ -545,32 +664,24 @@ test_single_onion_poisoning(void *arg)
char *dir2 = tor_strdup(get_fname_rnd("test_hs_dir2"));
smartlist_t *services = smartlist_new();
char *poison_path = NULL;
+ char *err_msg = NULL;
- /* No services, no service to verify, no problem! */
- mock_options->HiddenServiceSingleHopMode = 0;
- mock_options->HiddenServiceNonAnonymousMode = 0;
- ret = rend_config_services(mock_options, 1);
- tt_assert(ret == 0);
-
- /* Either way, no problem. */
mock_options->HiddenServiceSingleHopMode = 1;
mock_options->HiddenServiceNonAnonymousMode = 1;
- ret = rend_config_services(mock_options, 1);
- tt_assert(ret == 0);
/* Create the data directory, and, if the correct bit in arg is set,
* create a directory for that service.
* The data directory is required for the lockfile, which is used when
* loading keys. */
ret = check_private_dir(mock_options->DataDirectory, CPD_CREATE, NULL);
- tt_assert(ret == 0);
+ tt_int_op(ret, OP_EQ, 0);
if (create_dir_mask & CREATE_HS_DIR1) {
ret = check_private_dir(dir1, CPD_CREATE, NULL);
- tt_assert(ret == 0);
+ tt_int_op(ret, OP_EQ, 0);
}
if (create_dir_mask & CREATE_HS_DIR2) {
ret = check_private_dir(dir2, CPD_CREATE, NULL);
- tt_assert(ret == 0);
+ tt_int_op(ret, OP_EQ, 0);
}
service_1->directory = dir1;
@@ -580,194 +691,197 @@ test_single_onion_poisoning(void *arg)
/* Add port to service 1 */
service_1->ports = smartlist_new();
service_2->ports = smartlist_new();
- char *err_msg = NULL;
rend_service_port_config_t *port1 = rend_service_parse_port_config("80", " ",
&err_msg);
tt_assert(port1);
- tt_assert(!err_msg);
+ tt_ptr_op(err_msg, OP_EQ, NULL);
smartlist_add(service_1->ports, port1);
rend_service_port_config_t *port2 = rend_service_parse_port_config("90", " ",
&err_msg);
/* Add port to service 2 */
tt_assert(port2);
- tt_assert(!err_msg);
+ tt_ptr_op(err_msg, OP_EQ, NULL);
smartlist_add(service_2->ports, port2);
/* No services, a service to verify, no problem! */
mock_options->HiddenServiceSingleHopMode = 0;
mock_options->HiddenServiceNonAnonymousMode = 0;
ret = rend_service_verify_single_onion_poison(service_1, mock_options);
- tt_assert(ret == 0);
+ tt_int_op(ret, OP_EQ, 0);
ret = rend_service_verify_single_onion_poison(service_2, mock_options);
- tt_assert(ret == 0);
+ tt_int_op(ret, OP_EQ, 0);
/* Either way, no problem. */
mock_options->HiddenServiceSingleHopMode = 1;
mock_options->HiddenServiceNonAnonymousMode = 1;
ret = rend_service_verify_single_onion_poison(service_1, mock_options);
- tt_assert(ret == 0);
+ tt_int_op(ret, OP_EQ, 0);
ret = rend_service_verify_single_onion_poison(service_2, mock_options);
- tt_assert(ret == 0);
+ tt_int_op(ret, OP_EQ, 0);
/* Add the first service */
- ret = rend_service_check_dir_and_add(services, mock_options, service_1, 0);
- tt_assert(ret == 0);
+ ret = hs_check_service_private_dir(mock_options->User, service_1->directory,
+ service_1->dir_group_readable, 1);
+ tt_int_op(ret, OP_EQ, 0);
+ smartlist_add(services, service_1);
/* But don't add the second service yet. */
/* Service directories, but no previous keys, no problem! */
mock_options->HiddenServiceSingleHopMode = 0;
mock_options->HiddenServiceNonAnonymousMode = 0;
ret = rend_service_verify_single_onion_poison(service_1, mock_options);
- tt_assert(ret == 0);
+ tt_int_op(ret, OP_EQ, 0);
ret = rend_service_verify_single_onion_poison(service_2, mock_options);
- tt_assert(ret == 0);
+ tt_int_op(ret, OP_EQ, 0);
/* Either way, no problem. */
mock_options->HiddenServiceSingleHopMode = 1;
mock_options->HiddenServiceNonAnonymousMode = 1;
ret = rend_service_verify_single_onion_poison(service_1, mock_options);
- tt_assert(ret == 0);
+ tt_int_op(ret, OP_EQ, 0);
ret = rend_service_verify_single_onion_poison(service_2, mock_options);
- tt_assert(ret == 0);
+ tt_int_op(ret, OP_EQ, 0);
/* Poison! Poison! Poison!
* This can only be done in HiddenServiceSingleHopMode. */
mock_options->HiddenServiceSingleHopMode = 1;
mock_options->HiddenServiceNonAnonymousMode = 1;
ret = rend_service_poison_new_single_onion_dir(service_1, mock_options);
- tt_assert(ret == 0);
+ tt_int_op(ret, OP_EQ, 0);
/* Poisoning twice is a no-op. */
ret = rend_service_poison_new_single_onion_dir(service_1, mock_options);
- tt_assert(ret == 0);
+ tt_int_op(ret, OP_EQ, 0);
/* Poisoned service directories, but no previous keys, no problem! */
mock_options->HiddenServiceSingleHopMode = 0;
mock_options->HiddenServiceNonAnonymousMode = 0;
ret = rend_service_verify_single_onion_poison(service_1, mock_options);
- tt_assert(ret == 0);
+ tt_int_op(ret, OP_EQ, 0);
ret = rend_service_verify_single_onion_poison(service_2, mock_options);
- tt_assert(ret == 0);
+ tt_int_op(ret, OP_EQ, 0);
/* Either way, no problem. */
mock_options->HiddenServiceSingleHopMode = 1;
mock_options->HiddenServiceNonAnonymousMode = 1;
ret = rend_service_verify_single_onion_poison(service_1, mock_options);
- tt_assert(ret == 0);
+ tt_int_op(ret, OP_EQ, 0);
ret = rend_service_verify_single_onion_poison(service_2, mock_options);
- tt_assert(ret == 0);
+ tt_int_op(ret, OP_EQ, 0);
/* Now add some keys, and we'll have a problem. */
ret = rend_service_load_all_keys(services);
- tt_assert(ret == 0);
+ tt_int_op(ret, OP_EQ, 0);
/* Poisoned service directories with previous keys are not allowed. */
mock_options->HiddenServiceSingleHopMode = 0;
mock_options->HiddenServiceNonAnonymousMode = 0;
ret = rend_service_verify_single_onion_poison(service_1, mock_options);
- tt_assert(ret < 0);
+ tt_int_op(ret, OP_LT, 0);
ret = rend_service_verify_single_onion_poison(service_2, mock_options);
- tt_assert(ret == 0);
+ tt_int_op(ret, OP_EQ, 0);
/* But they are allowed if we're in non-anonymous mode. */
mock_options->HiddenServiceSingleHopMode = 1;
mock_options->HiddenServiceNonAnonymousMode = 1;
ret = rend_service_verify_single_onion_poison(service_1, mock_options);
- tt_assert(ret == 0);
+ tt_int_op(ret, OP_EQ, 0);
ret = rend_service_verify_single_onion_poison(service_2, mock_options);
- tt_assert(ret == 0);
+ tt_int_op(ret, OP_EQ, 0);
/* Re-poisoning directories with existing keys is a no-op, because
* directories with existing keys are ignored. */
mock_options->HiddenServiceSingleHopMode = 1;
mock_options->HiddenServiceNonAnonymousMode = 1;
ret = rend_service_poison_new_single_onion_dir(service_1, mock_options);
- tt_assert(ret == 0);
+ tt_int_op(ret, OP_EQ, 0);
/* And it keeps the poison. */
ret = rend_service_verify_single_onion_poison(service_1, mock_options);
- tt_assert(ret == 0);
+ tt_int_op(ret, OP_EQ, 0);
ret = rend_service_verify_single_onion_poison(service_2, mock_options);
- tt_assert(ret == 0);
+ tt_int_op(ret, OP_EQ, 0);
/* Now add the second service: it has no key and no poison file */
- ret = rend_service_check_dir_and_add(services, mock_options, service_2, 0);
- tt_assert(ret == 0);
+ ret = hs_check_service_private_dir(mock_options->User, service_2->directory,
+ service_2->dir_group_readable, 1);
+ tt_int_op(ret, OP_EQ, 0);
+ smartlist_add(services, service_2);
/* A new service, and an existing poisoned service. Not ok. */
mock_options->HiddenServiceSingleHopMode = 0;
mock_options->HiddenServiceNonAnonymousMode = 0;
ret = rend_service_verify_single_onion_poison(service_1, mock_options);
- tt_assert(ret < 0);
+ tt_int_op(ret, OP_LT, 0);
ret = rend_service_verify_single_onion_poison(service_2, mock_options);
- tt_assert(ret == 0);
+ tt_int_op(ret, OP_EQ, 0);
/* But ok to add in non-anonymous mode. */
mock_options->HiddenServiceSingleHopMode = 1;
mock_options->HiddenServiceNonAnonymousMode = 1;
ret = rend_service_verify_single_onion_poison(service_1, mock_options);
- tt_assert(ret == 0);
+ tt_int_op(ret, OP_EQ, 0);
ret = rend_service_verify_single_onion_poison(service_2, mock_options);
- tt_assert(ret == 0);
+ tt_int_op(ret, OP_EQ, 0);
/* Now remove the poisoning from the first service, and we have the opposite
* problem. */
poison_path = rend_service_sos_poison_path(service_1);
tt_assert(poison_path);
ret = unlink(poison_path);
- tt_assert(ret == 0);
+ tt_int_op(ret, OP_EQ, 0);
/* Unpoisoned service directories with previous keys are ok, as are empty
* directories. */
mock_options->HiddenServiceSingleHopMode = 0;
mock_options->HiddenServiceNonAnonymousMode = 0;
ret = rend_service_verify_single_onion_poison(service_1, mock_options);
- tt_assert(ret == 0);
+ tt_int_op(ret, OP_EQ, 0);
ret = rend_service_verify_single_onion_poison(service_2, mock_options);
- tt_assert(ret == 0);
+ tt_int_op(ret, OP_EQ, 0);
/* But the existing unpoisoned key is not ok in non-anonymous mode, even if
* there is an empty service. */
mock_options->HiddenServiceSingleHopMode = 1;
mock_options->HiddenServiceNonAnonymousMode = 1;
ret = rend_service_verify_single_onion_poison(service_1, mock_options);
- tt_assert(ret < 0);
+ tt_int_op(ret, OP_LT, 0);
ret = rend_service_verify_single_onion_poison(service_2, mock_options);
- tt_assert(ret == 0);
+ tt_int_op(ret, OP_EQ, 0);
/* Poisoning directories with existing keys is a no-op, because directories
* with existing keys are ignored. But the new directory should poison. */
mock_options->HiddenServiceSingleHopMode = 1;
mock_options->HiddenServiceNonAnonymousMode = 1;
ret = rend_service_poison_new_single_onion_dir(service_1, mock_options);
- tt_assert(ret == 0);
+ tt_int_op(ret, OP_EQ, 0);
ret = rend_service_poison_new_single_onion_dir(service_2, mock_options);
- tt_assert(ret == 0);
+ tt_int_op(ret, OP_EQ, 0);
/* And the old directory remains unpoisoned. */
ret = rend_service_verify_single_onion_poison(service_1, mock_options);
- tt_assert(ret < 0);
+ tt_int_op(ret, OP_LT, 0);
ret = rend_service_verify_single_onion_poison(service_2, mock_options);
- tt_assert(ret == 0);
+ tt_int_op(ret, OP_EQ, 0);
/* And the new directory should be ignored, because it has no key. */
mock_options->HiddenServiceSingleHopMode = 0;
mock_options->HiddenServiceNonAnonymousMode = 0;
ret = rend_service_verify_single_onion_poison(service_1, mock_options);
- tt_assert(ret == 0);
+ tt_int_op(ret, OP_EQ, 0);
ret = rend_service_verify_single_onion_poison(service_2, mock_options);
- tt_assert(ret == 0);
+ tt_int_op(ret, OP_EQ, 0);
/* Re-poisoning directories without existing keys is a no-op. */
mock_options->HiddenServiceSingleHopMode = 1;
mock_options->HiddenServiceNonAnonymousMode = 1;
ret = rend_service_poison_new_single_onion_dir(service_1, mock_options);
- tt_assert(ret == 0);
+ tt_int_op(ret, OP_EQ, 0);
ret = rend_service_poison_new_single_onion_dir(service_2, mock_options);
- tt_assert(ret == 0);
+ tt_int_op(ret, OP_EQ, 0);
/* And the old directory remains unpoisoned. */
ret = rend_service_verify_single_onion_poison(service_1, mock_options);
- tt_assert(ret < 0);
+ tt_int_op(ret, OP_LT, 0);
ret = rend_service_verify_single_onion_poison(service_2, mock_options);
- tt_assert(ret == 0);
+ tt_int_op(ret, OP_EQ, 0);
done:
/* The test harness deletes the directories at exit */
@@ -779,11 +893,144 @@ test_single_onion_poisoning(void *arg)
rend_service_free(service_2);
UNMOCK(get_options);
tor_free(mock_options->DataDirectory);
+ tor_free(err_msg);
+}
+
+static rend_service_t *
+helper_create_rend_service(const char *path)
+{
+ rend_service_t *s = tor_malloc_zero(sizeof(rend_service_t));
+ s->ports = smartlist_new();
+ s->intro_nodes = smartlist_new();
+ s->expiring_nodes = smartlist_new();
+ if (path) {
+ s->directory = tor_strdup(path);
+ }
+ return s;
+}
+
+static void
+test_prune_services_on_reload(void *arg)
+{
+ smartlist_t *new = smartlist_new(), *old = smartlist_new();
+ /* Non ephemeral service. */
+ rend_service_t *s1 = helper_create_rend_service("SomePath");
+ /* Create a non ephemeral service with the _same_ path as so we can test the
+ * transfer of introduction point between the same services on reload. */
+ rend_service_t *s2 = helper_create_rend_service(s1->directory);
+ /* Ephemeral service (directory is NULL). */
+ rend_service_t *e1 = helper_create_rend_service(NULL);
+ rend_service_t *e2 = helper_create_rend_service(NULL);
+
+ (void) arg;
+
+ {
+ /* Add both services to the old list. */
+ smartlist_add(old, s1);
+ smartlist_add(old, e1);
+ /* Only put the non ephemeral in the new list. */
+ smartlist_add(new, s1);
+ 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);
+ tt_assert(smartlist_get(old, 0) == s1);
+ tt_int_op(smartlist_len(new), OP_EQ, 2);
+ tt_assert(smartlist_get(new, 0) == s1);
+ tt_assert(smartlist_get(new, 1) == e1);
+ /* Cleanup for next test. */
+ smartlist_clear(new);
+ smartlist_clear(old);
+ }
+
+ {
+ /* This test will make sure that only the ephemeral service is kept if the
+ * new list is empty. The old list should contain only the non ephemeral
+ * one. */
+ smartlist_add(old, s1);
+ smartlist_add(old, e1);
+ 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);
+ tt_assert(smartlist_get(new, 0) == e1);
+ /* Cleanup for next test. */
+ smartlist_clear(new);
+ smartlist_clear(old);
+ }
+
+ {
+ /* This test makes sure that the new list stays the same even from the old
+ * list being completely different. */
+ smartlist_add(new, s1);
+ smartlist_add(new, e1);
+ 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);
+ tt_assert(smartlist_get(new, 1) == e1);
+ /* Cleanup for next test. */
+ smartlist_clear(new);
+ }
+
+ {
+ rend_intro_point_t ip1;
+ /* This IP should be found in the s2 service after pruning. */
+ smartlist_add(s1->intro_nodes, &ip1);
+ /* Setup our list. */
+ smartlist_add(old, s1);
+ smartlist_add(new, s2);
+ 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);
+ tt_int_op(smartlist_len(new), OP_EQ, 1);
+ rend_service_t *elem = smartlist_get(new, 0);
+ tt_assert(elem);
+ tt_assert(elem == s2);
+ tt_int_op(smartlist_len(elem->intro_nodes), OP_EQ, 1);
+ tt_assert(smartlist_get(elem->intro_nodes, 0) == &ip1);
+ smartlist_clear(s1->intro_nodes);
+ smartlist_clear(s2->intro_nodes);
+ /* Cleanup for next test. */
+ smartlist_clear(new);
+ smartlist_clear(old);
+ }
+
+ {
+ /* Test two ephemeral services. */
+ smartlist_add(old, e1);
+ smartlist_add(old, e2);
+ 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);
+ }
+
+ done:
+ rend_service_free(s1);
+ rend_service_free(s2);
+ rend_service_free(e1);
+ rend_service_free(e2);
+ smartlist_free(new);
+ smartlist_free(old);
}
struct testcase_t hs_tests[] = {
{ "hs_rend_data", test_hs_rend_data, TT_FORK,
NULL, NULL },
+ { "hs_parse_static_v2_desc", test_hs_parse_static_v2_desc, TT_FORK,
+ NULL, NULL },
{ "hs_desc_event", test_hs_desc_event, TT_FORK,
NULL, NULL },
{ "pick_tor2web_rendezvous_node", test_pick_tor2web_rendezvous_node, TT_FORK,
@@ -801,6 +1048,9 @@ struct testcase_t hs_tests[] = {
TT_FORK, &passthrough_setup, (void*)(CREATE_HS_DIR2) },
{ "single_onion_poisoning_create_dir_both", test_single_onion_poisoning,
TT_FORK, &passthrough_setup, (void*)(CREATE_HS_DIR1 | CREATE_HS_DIR2) },
+ { "prune_services_on_reload", test_prune_services_on_reload, TT_FORK,
+ NULL, NULL },
+
END_OF_TESTCASES
};
diff --git a/src/test/test_hs_cache.c b/src/test/test_hs_cache.c
new file mode 100644
index 0000000000..91b13be862
--- /dev/null
+++ b/src/test/test_hs_cache.c
@@ -0,0 +1,561 @@
+/* Copyright (c) 2016-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file test_hs_cache.c
+ * \brief Test hidden service caches.
+ */
+
+#define CONNECTION_PRIVATE
+#define DIRECTORY_PRIVATE
+#define HS_CACHE_PRIVATE
+
+#include "ed25519_cert.h"
+#include "hs_cache.h"
+#include "rendcache.h"
+#include "directory.h"
+#include "networkstatus.h"
+#include "connection.h"
+#include "proto_http.h"
+
+#include "hs_test_helpers.h"
+#include "test_helpers.h"
+#include "test.h"
+
+/* Static variable used to encoded the HSDir query. */
+static char query_b64[256];
+
+/* Build an HSDir query using a ed25519 public key. */
+static const char *
+helper_get_hsdir_query(const hs_descriptor_t *desc)
+{
+ ed25519_public_to_base64(query_b64, &desc->plaintext_data.blinded_pubkey);
+ return query_b64;
+}
+
+static void
+init_test(void)
+{
+ /* Always needed. Initialize the subsystem. */
+ hs_cache_init();
+ /* We need the v2 cache since our OOM and cache cleanup does poke at it. */
+ rend_cache_init();
+}
+
+static void
+test_directory(void *arg)
+{
+ int ret;
+ size_t oom_size;
+ char *desc1_str = NULL;
+ const char *desc_out;
+ ed25519_keypair_t signing_kp1;
+ hs_descriptor_t *desc1 = NULL;
+
+ (void) arg;
+
+ init_test();
+ /* Generate a valid descriptor with normal values. */
+ ret = ed25519_keypair_generate(&signing_kp1, 0);
+ tt_int_op(ret, OP_EQ, 0);
+ desc1 = hs_helper_build_hs_desc_with_ip(&signing_kp1);
+ tt_assert(desc1);
+ ret = hs_desc_encode_descriptor(desc1, &signing_kp1, &desc1_str);
+ tt_int_op(ret, OP_EQ, 0);
+
+ /* Very first basic test, should be able to be stored, survive a
+ * clean, found with a lookup and then cleaned by our OOM. */
+ {
+ ret = hs_cache_store_as_dir(desc1_str);
+ tt_int_op(ret, OP_EQ, 0);
+ /* Re-add, it should fail since we already have it. */
+ ret = hs_cache_store_as_dir(desc1_str);
+ tt_int_op(ret, OP_EQ, -1);
+ /* Try to clean now which should be fine, there is at worst few seconds
+ * between the store and this call. */
+ hs_cache_clean_as_dir(time(NULL));
+ /* We should find it in our cache. */
+ ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), &desc_out);
+ tt_int_op(ret, OP_EQ, 1);
+ tt_str_op(desc_out, OP_EQ, desc1_str);
+ /* Tell our OOM to run and to at least remove a byte which will result in
+ * removing the descriptor from our cache. */
+ oom_size = hs_cache_handle_oom(time(NULL), 1);
+ tt_int_op(oom_size, OP_GE, 1);
+ ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), NULL);
+ tt_int_op(ret, OP_EQ, 0);
+ }
+
+ /* Store two descriptors and remove the expiring one only. */
+ {
+ ed25519_keypair_t signing_kp_zero;
+ ret = ed25519_keypair_generate(&signing_kp_zero, 0);
+ tt_int_op(ret, OP_EQ, 0);
+ hs_descriptor_t *desc_zero_lifetime;
+ desc_zero_lifetime = hs_helper_build_hs_desc_with_ip(&signing_kp_zero);
+ tt_assert(desc_zero_lifetime);
+ desc_zero_lifetime->plaintext_data.revision_counter = 1;
+ desc_zero_lifetime->plaintext_data.lifetime_sec = 0;
+ char *desc_zero_lifetime_str;
+ ret = hs_desc_encode_descriptor(desc_zero_lifetime, &signing_kp_zero,
+ &desc_zero_lifetime_str);
+ tt_int_op(ret, OP_EQ, 0);
+
+ ret = hs_cache_store_as_dir(desc1_str);
+ tt_int_op(ret, OP_EQ, 0);
+ ret = hs_cache_store_as_dir(desc_zero_lifetime_str);
+ tt_int_op(ret, OP_EQ, 0);
+ /* This one should clear out our zero lifetime desc. */
+ hs_cache_clean_as_dir(time(NULL));
+ /* We should find desc1 in our cache. */
+ ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), &desc_out);
+ tt_int_op(ret, OP_EQ, 1);
+ tt_str_op(desc_out, OP_EQ, desc1_str);
+ /* We should NOT find our zero lifetime desc in our cache. */
+ ret = hs_cache_lookup_as_dir(3,
+ helper_get_hsdir_query(desc_zero_lifetime),
+ NULL);
+ tt_int_op(ret, OP_EQ, 0);
+ /* Cleanup our entire cache. */
+ oom_size = hs_cache_handle_oom(time(NULL), 1);
+ tt_int_op(oom_size, OP_GE, 1);
+ hs_descriptor_free(desc_zero_lifetime);
+ tor_free(desc_zero_lifetime_str);
+ }
+
+ /* Throw junk at it. */
+ {
+ ret = hs_cache_store_as_dir("blah");
+ tt_int_op(ret, OP_EQ, -1);
+ /* Poor attempt at tricking the decoding. */
+ ret = hs_cache_store_as_dir("hs-descriptor 3\nJUNK");
+ tt_int_op(ret, OP_EQ, -1);
+ /* Undecodable base64 query. */
+ ret = hs_cache_lookup_as_dir(3, "blah", NULL);
+ tt_int_op(ret, OP_EQ, -1);
+ /* Decodable base64 query but wrong ed25519 size. */
+ ret = hs_cache_lookup_as_dir(3, "dW5pY29ybg==", NULL);
+ tt_int_op(ret, OP_EQ, -1);
+ }
+
+ /* Test descriptor replacement with revision counter. */
+ {
+ char *new_desc_str;
+
+ /* Add a descriptor. */
+ ret = hs_cache_store_as_dir(desc1_str);
+ tt_int_op(ret, OP_EQ, 0);
+ ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), &desc_out);
+ tt_int_op(ret, OP_EQ, 1);
+ /* Bump revision counter. */
+ desc1->plaintext_data.revision_counter++;
+ ret = hs_desc_encode_descriptor(desc1, &signing_kp1, &new_desc_str);
+ tt_int_op(ret, OP_EQ, 0);
+ ret = hs_cache_store_as_dir(new_desc_str);
+ tt_int_op(ret, OP_EQ, 0);
+ /* Look it up, it should have been replaced. */
+ ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), &desc_out);
+ tt_int_op(ret, OP_EQ, 1);
+ tt_str_op(desc_out, OP_EQ, new_desc_str);
+ tor_free(new_desc_str);
+ }
+
+ done:
+ hs_descriptor_free(desc1);
+ tor_free(desc1_str);
+}
+
+static void
+test_clean_as_dir(void *arg)
+{
+ size_t ret;
+ char *desc1_str = NULL;
+ time_t now = time(NULL);
+ hs_descriptor_t *desc1 = NULL;
+ ed25519_keypair_t signing_kp1;
+
+ (void) arg;
+
+ init_test();
+
+ /* Generate a valid descriptor with values. */
+ ret = ed25519_keypair_generate(&signing_kp1, 0);
+ tt_int_op(ret, OP_EQ, 0);
+ desc1 = hs_helper_build_hs_desc_with_ip(&signing_kp1);
+ tt_assert(desc1);
+ ret = hs_desc_encode_descriptor(desc1, &signing_kp1, &desc1_str);
+ tt_int_op(ret, OP_EQ, 0);
+ ret = hs_cache_store_as_dir(desc1_str);
+ tt_int_op(ret, OP_EQ, 0);
+
+ /* With the lifetime being 3 hours, a cleanup shouldn't remove it. */
+ ret = cache_clean_v3_as_dir(now, 0);
+ tt_int_op(ret, OP_EQ, 0);
+ /* Should be present after clean up. */
+ ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), NULL);
+ tt_int_op(ret, OP_EQ, 1);
+ /* Set a cutoff 100 seconds in the past. It should not remove the entry
+ * since the entry is still recent enough. */
+ ret = cache_clean_v3_as_dir(now, now - 100);
+ tt_int_op(ret, OP_EQ, 0);
+ /* Should be present after clean up. */
+ ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), NULL);
+ tt_int_op(ret, OP_EQ, 1);
+ /* Set a cutoff of 100 seconds in the future. It should remove the entry
+ * that we've just added since it's not too old for the cutoff. */
+ ret = cache_clean_v3_as_dir(now, now + 100);
+ tt_int_op(ret, OP_GT, 0);
+ /* Shouldn't be present after clean up. */
+ ret = hs_cache_lookup_as_dir(3, helper_get_hsdir_query(desc1), NULL);
+ tt_int_op(ret, OP_EQ, 0);
+
+ done:
+ hs_descriptor_free(desc1);
+ tor_free(desc1_str);
+}
+
+/* Test helper: Fetch an HS descriptor from an HSDir (for the hidden service
+ with <b>blinded_key</b>. Return the received descriptor string. */
+static char *
+helper_fetch_desc_from_hsdir(const ed25519_public_key_t *blinded_key)
+{
+ int retval;
+
+ char *received_desc = NULL;
+ char *hsdir_query_str = NULL;
+
+ /* The dir conn we are going to simulate */
+ dir_connection_t *conn = NULL;
+
+ /* First extract the blinded public key that we are going to use in our
+ query, and then build the actual query string. */
+ {
+ char hsdir_cache_key[ED25519_BASE64_LEN+1];
+
+ retval = ed25519_public_to_base64(hsdir_cache_key,
+ blinded_key);
+ tt_int_op(retval, OP_EQ, 0);
+ tor_asprintf(&hsdir_query_str, GET("/tor/hs/3/%s"), hsdir_cache_key);
+ }
+
+ /* Simulate an HTTP GET request to the HSDir */
+ conn = dir_connection_new(AF_INET);
+ tor_addr_from_ipv4h(&conn->base_.addr, 0x7f000001);
+ TO_CONN(conn)->linked = 1;/* Pretend the conn is encrypted :) */
+ retval = directory_handle_command_get(conn, hsdir_query_str,
+ NULL, 0);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /* Read the descriptor that the HSDir just served us */
+ {
+ char *headers = NULL;
+ size_t body_used = 0;
+
+ fetch_from_buf_http(TO_CONN(conn)->outbuf, &headers, MAX_HEADERS_SIZE,
+ &received_desc, &body_used, HS_DESC_MAX_LEN, 0);
+ tor_free(headers);
+ }
+
+ done:
+ tor_free(hsdir_query_str);
+ if (conn)
+ connection_free_(TO_CONN(conn));
+
+ return received_desc;
+}
+
+/* Publish a descriptor to the HSDir, then fetch it. Check that the received
+ descriptor matches the published one. */
+static void
+test_upload_and_download_hs_desc(void *arg)
+{
+ int retval;
+ hs_descriptor_t *published_desc = NULL;
+
+ char *published_desc_str = NULL;
+ char *received_desc_str = NULL;
+
+ (void) arg;
+
+ /* Initialize HSDir cache subsystem */
+ init_test();
+
+ /* Test a descriptor not found in the directory cache. */
+ {
+ ed25519_public_key_t blinded_key;
+ memset(&blinded_key.pubkey, 'A', sizeof(blinded_key.pubkey));
+ received_desc_str = helper_fetch_desc_from_hsdir(&blinded_key);
+ tt_int_op(strlen(received_desc_str), OP_EQ, 0);
+ tor_free(received_desc_str);
+ }
+
+ /* Generate a valid descriptor with normal values. */
+ {
+ ed25519_keypair_t signing_kp;
+ retval = ed25519_keypair_generate(&signing_kp, 0);
+ tt_int_op(retval, OP_EQ, 0);
+ published_desc = hs_helper_build_hs_desc_with_ip(&signing_kp);
+ tt_assert(published_desc);
+ retval = hs_desc_encode_descriptor(published_desc, &signing_kp,
+ &published_desc_str);
+ tt_int_op(retval, OP_EQ, 0);
+ }
+
+ /* Publish descriptor to the HSDir */
+ {
+ retval = handle_post_hs_descriptor("/tor/hs/3/publish",published_desc_str);
+ tt_int_op(retval, OP_EQ, 200);
+ }
+
+ /* Simulate a fetch of the previously published descriptor */
+ {
+ const ed25519_public_key_t *blinded_key;
+ blinded_key = &published_desc->plaintext_data.blinded_pubkey;
+ received_desc_str = helper_fetch_desc_from_hsdir(blinded_key);
+ }
+
+ /* Verify we received the exact same descriptor we published earlier */
+ tt_str_op(received_desc_str, OP_EQ, published_desc_str);
+ tor_free(received_desc_str);
+
+ /* With a valid descriptor in the directory cache, try again an invalid. */
+ {
+ ed25519_public_key_t blinded_key;
+ memset(&blinded_key.pubkey, 'A', sizeof(blinded_key.pubkey));
+ received_desc_str = helper_fetch_desc_from_hsdir(&blinded_key);
+ tt_int_op(strlen(received_desc_str), OP_EQ, 0);
+ }
+
+ done:
+ tor_free(received_desc_str);
+ tor_free(published_desc_str);
+ hs_descriptor_free(published_desc);
+}
+
+/* Test that HSDirs reject outdated descriptors based on their revision
+ * counter. Also test that HSDirs correctly replace old descriptors with newer
+ * descriptors. */
+static void
+test_hsdir_revision_counter_check(void *arg)
+{
+ int retval;
+
+ ed25519_keypair_t signing_kp;
+
+ hs_descriptor_t *published_desc = NULL;
+ char *published_desc_str = NULL;
+
+ uint8_t subcredential[DIGEST256_LEN];
+ char *received_desc_str = NULL;
+ hs_descriptor_t *received_desc = NULL;
+
+ (void) arg;
+
+ /* Initialize HSDir cache subsystem */
+ init_test();
+
+ /* Generate a valid descriptor with normal values. */
+ {
+ retval = ed25519_keypair_generate(&signing_kp, 0);
+ tt_int_op(retval, OP_EQ, 0);
+ published_desc = hs_helper_build_hs_desc_with_ip(&signing_kp);
+ tt_assert(published_desc);
+ retval = hs_desc_encode_descriptor(published_desc, &signing_kp,
+ &published_desc_str);
+ tt_int_op(retval, OP_EQ, 0);
+ }
+
+ /* Publish descriptor to the HSDir */
+ {
+ retval = handle_post_hs_descriptor("/tor/hs/3/publish",published_desc_str);
+ tt_int_op(retval, OP_EQ, 200);
+ }
+
+ /* Try publishing again with the same revision counter: Should fail. */
+ {
+ retval = handle_post_hs_descriptor("/tor/hs/3/publish",published_desc_str);
+ tt_int_op(retval, OP_EQ, 400);
+ }
+
+ /* Fetch the published descriptor and validate the revision counter. */
+ {
+ const ed25519_public_key_t *blinded_key;
+
+ blinded_key = &published_desc->plaintext_data.blinded_pubkey;
+ hs_get_subcredential(&signing_kp.pubkey, blinded_key, subcredential);
+ received_desc_str = helper_fetch_desc_from_hsdir(blinded_key);
+
+ retval = hs_desc_decode_descriptor(received_desc_str,
+ subcredential, &received_desc);
+ tt_int_op(retval, OP_EQ, 0);
+ tt_assert(received_desc);
+
+ /* Check that the revision counter is correct */
+ tt_u64_op(received_desc->plaintext_data.revision_counter, OP_EQ, 42);
+
+ hs_descriptor_free(received_desc);
+ received_desc = NULL;
+ tor_free(received_desc_str);
+ }
+
+ /* Increment the revision counter and try again. Should work. */
+ {
+ published_desc->plaintext_data.revision_counter = 1313;
+ tor_free(published_desc_str);
+ retval = hs_desc_encode_descriptor(published_desc, &signing_kp,
+ &published_desc_str);
+ tt_int_op(retval, OP_EQ, 0);
+
+ retval = handle_post_hs_descriptor("/tor/hs/3/publish",published_desc_str);
+ tt_int_op(retval, OP_EQ, 200);
+ }
+
+ /* Again, fetch the published descriptor and perform the revision counter
+ validation. The revision counter must have changed. */
+ {
+ const ed25519_public_key_t *blinded_key;
+
+ blinded_key = &published_desc->plaintext_data.blinded_pubkey;
+ received_desc_str = helper_fetch_desc_from_hsdir(blinded_key);
+
+ retval = hs_desc_decode_descriptor(received_desc_str,
+ subcredential, &received_desc);
+ tt_int_op(retval, OP_EQ, 0);
+ tt_assert(received_desc);
+
+ /* Check that the revision counter is the latest */
+ tt_u64_op(received_desc->plaintext_data.revision_counter, OP_EQ, 1313);
+ }
+
+ done:
+ hs_descriptor_free(published_desc);
+ hs_descriptor_free(received_desc);
+ tor_free(received_desc_str);
+ tor_free(published_desc_str);
+}
+
+static networkstatus_t mock_ns;
+
+static networkstatus_t *
+mock_networkstatus_get_live_consensus(time_t now)
+{
+ (void) now;
+ return &mock_ns;
+}
+
+/** Test that we can store HS descriptors in the client HS cache. */
+static void
+test_client_cache(void *arg)
+{
+ int retval;
+ ed25519_keypair_t signing_kp;
+ hs_descriptor_t *published_desc = NULL;
+ char *published_desc_str = NULL;
+ uint8_t wanted_subcredential[DIGEST256_LEN];
+ response_handler_args_t *args = NULL;
+ dir_connection_t *conn = NULL;
+
+ (void) arg;
+
+ /* Initialize HSDir cache subsystem */
+ init_test();
+
+ MOCK(networkstatus_get_live_consensus,
+ mock_networkstatus_get_live_consensus);
+
+ /* Set consensus time */
+ parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC",
+ &mock_ns.valid_after);
+ parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC",
+ &mock_ns.fresh_until);
+ parse_rfc1123_time("Sat, 26 Oct 1985 16:00:00 UTC",
+ &mock_ns.valid_until);
+
+ /* Generate a valid descriptor with normal values. */
+ {
+ retval = ed25519_keypair_generate(&signing_kp, 0);
+ tt_int_op(retval, OP_EQ, 0);
+ published_desc = hs_helper_build_hs_desc_with_ip(&signing_kp);
+ tt_assert(published_desc);
+ retval = hs_desc_encode_descriptor(published_desc, &signing_kp,
+ &published_desc_str);
+ tt_int_op(retval, OP_EQ, 0);
+ memcpy(wanted_subcredential, published_desc->subcredential, DIGEST256_LEN);
+ tt_assert(!tor_mem_is_zero((char*)wanted_subcredential, DIGEST256_LEN));
+ }
+
+ /* Test handle_response_fetch_hsdesc_v3() */
+ {
+ args = tor_malloc_zero(sizeof(response_handler_args_t));
+ args->status_code = 200;
+ args->reason = NULL;
+ args->body = published_desc_str;
+ args->body_len = strlen(published_desc_str);
+
+ conn = tor_malloc_zero(sizeof(dir_connection_t));
+ conn->hs_ident = tor_malloc_zero(sizeof(hs_ident_dir_conn_t));
+ ed25519_pubkey_copy(&conn->hs_ident->identity_pk, &signing_kp.pubkey);
+ }
+
+ /* store the descriptor! */
+ retval = handle_response_fetch_hsdesc_v3(conn, args);
+ tt_int_op(retval, == , 0);
+
+ /* Progress time a bit and attempt to clean cache: our desc should not be
+ * cleaned since we still in the same TP. */
+ {
+ parse_rfc1123_time("Sat, 27 Oct 1985 02:00:00 UTC",
+ &mock_ns.valid_after);
+ parse_rfc1123_time("Sat, 27 Oct 1985 03:00:00 UTC",
+ &mock_ns.fresh_until);
+ parse_rfc1123_time("Sat, 27 Oct 1985 05:00:00 UTC",
+ &mock_ns.valid_until);
+
+ /* fetch the descriptor and make sure it's there */
+ const hs_descriptor_t *cached_desc = NULL;
+ cached_desc = hs_cache_lookup_as_client(&signing_kp.pubkey);
+ tt_assert(cached_desc);
+ tt_mem_op(cached_desc->subcredential, OP_EQ, wanted_subcredential,
+ DIGEST256_LEN);
+ }
+
+ /* Progress time to next TP and check that desc was cleaned */
+ {
+ parse_rfc1123_time("Sat, 27 Oct 1985 12:00:00 UTC",
+ &mock_ns.valid_after);
+ parse_rfc1123_time("Sat, 27 Oct 1985 13:00:00 UTC",
+ &mock_ns.fresh_until);
+ parse_rfc1123_time("Sat, 27 Oct 1985 15:00:00 UTC",
+ &mock_ns.valid_until);
+
+ const hs_descriptor_t *cached_desc = NULL;
+ cached_desc = hs_cache_lookup_as_client(&signing_kp.pubkey);
+ tt_assert(!cached_desc);
+ }
+
+ done:
+ tor_free(args);
+ hs_descriptor_free(published_desc);
+ tor_free(published_desc_str);
+ if (conn) {
+ tor_free(conn->hs_ident);
+ tor_free(conn);
+ }
+}
+
+struct testcase_t hs_cache[] = {
+ /* Encoding tests. */
+ { "directory", test_directory, TT_FORK,
+ NULL, NULL },
+ { "clean_as_dir", test_clean_as_dir, TT_FORK,
+ NULL, NULL },
+ { "hsdir_revision_counter_check", test_hsdir_revision_counter_check, TT_FORK,
+ NULL, NULL },
+ { "upload_and_download_hs_desc", test_upload_and_download_hs_desc, TT_FORK,
+ NULL, NULL },
+ { "client_cache", test_client_cache, TT_FORK,
+ NULL, NULL },
+
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_hs_cell.c b/src/test/test_hs_cell.c
new file mode 100644
index 0000000000..1b3c788a67
--- /dev/null
+++ b/src/test/test_hs_cell.c
@@ -0,0 +1,130 @@
+/* Copyright (c) 2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file test_hs_cell.c
+ * \brief Test hidden service cell functionality.
+ */
+
+#define HS_INTROPOINT_PRIVATE
+#define HS_SERVICE_PRIVATE
+
+#include "test.h"
+#include "test_helpers.h"
+#include "log_test_helpers.h"
+
+#include "crypto_ed25519.h"
+#include "hs_cell.h"
+#include "hs_intropoint.h"
+#include "hs_service.h"
+
+/* Trunnel. */
+#include "hs/cell_establish_intro.h"
+
+/** We simulate the creation of an outgoing ESTABLISH_INTRO cell, and then we
+ * parse it from the receiver side. */
+static void
+test_gen_establish_intro_cell(void *arg)
+{
+ (void) arg;
+ ssize_t ret;
+ char circ_nonce[DIGEST_LEN] = {0};
+ uint8_t buf[RELAY_PAYLOAD_SIZE];
+ trn_cell_establish_intro_t *cell_in = NULL;
+
+ crypto_rand(circ_nonce, sizeof(circ_nonce));
+
+ /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we
+ attempt to parse it. */
+ {
+ /* We only need the auth key pair here. */
+ hs_service_intro_point_t *ip = service_intro_point_new(NULL, 0);
+ /* Auth key pair is generated in the constructor so we are all set for
+ * using this IP object. */
+ ret = hs_cell_build_establish_intro(circ_nonce, ip, buf);
+ service_intro_point_free(ip);
+ tt_u64_op(ret, OP_GT, 0);
+ }
+
+ /* Check the contents of the cell */
+ {
+ /* First byte is the auth key type: make sure its correct */
+ tt_int_op(buf[0], OP_EQ, HS_INTRO_AUTH_KEY_TYPE_ED25519);
+ /* Next two bytes is auth key len */
+ tt_int_op(ntohs(get_uint16(buf+1)), OP_EQ, ED25519_PUBKEY_LEN);
+ /* Skip to the number of extensions: no extensions */
+ tt_int_op(buf[35], OP_EQ, 0);
+ /* Skip to the sig len. Make sure it's the size of an ed25519 sig */
+ tt_int_op(ntohs(get_uint16(buf+35+1+32)), OP_EQ, ED25519_SIG_LEN);
+ }
+
+ /* Parse it as the receiver */
+ {
+ ret = trn_cell_establish_intro_parse(&cell_in, buf, sizeof(buf));
+ tt_u64_op(ret, OP_GT, 0);
+
+ ret = verify_establish_intro_cell(cell_in,
+ (const uint8_t *) circ_nonce,
+ sizeof(circ_nonce));
+ tt_u64_op(ret, OP_EQ, 0);
+ }
+
+ done:
+ trn_cell_establish_intro_free(cell_in);
+}
+
+/* Mocked ed25519_sign_prefixed() function that always fails :) */
+static int
+mock_ed25519_sign_prefixed(ed25519_signature_t *signature_out,
+ const uint8_t *msg, size_t msg_len,
+ const char *prefix_str,
+ const ed25519_keypair_t *keypair) {
+ (void) signature_out;
+ (void) msg;
+ (void) msg_len;
+ (void) prefix_str;
+ (void) keypair;
+ return -1;
+}
+
+/** We simulate a failure to create an ESTABLISH_INTRO cell */
+static void
+test_gen_establish_intro_cell_bad(void *arg)
+{
+ (void) arg;
+ ssize_t cell_len = 0;
+ trn_cell_establish_intro_t *cell = NULL;
+ char circ_nonce[DIGEST_LEN] = {0};
+ hs_service_intro_point_t *ip = NULL;
+
+ MOCK(ed25519_sign_prefixed, mock_ed25519_sign_prefixed);
+
+ crypto_rand(circ_nonce, sizeof(circ_nonce));
+
+ setup_full_capture_of_logs(LOG_WARN);
+ /* Easiest way to make that function fail is to mock the
+ ed25519_sign_prefixed() function and make it fail. */
+ cell = trn_cell_establish_intro_new();
+ tt_assert(cell);
+ ip = service_intro_point_new(NULL, 0);
+ cell_len = hs_cell_build_establish_intro(circ_nonce, ip, NULL);
+ service_intro_point_free(ip);
+ expect_log_msg_containing("Unable to make signature for "
+ "ESTABLISH_INTRO cell.");
+ teardown_capture_of_logs();
+ tt_i64_op(cell_len, OP_EQ, -1);
+
+ done:
+ trn_cell_establish_intro_free(cell);
+ UNMOCK(ed25519_sign_prefixed);
+}
+
+struct testcase_t hs_cell_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 },
+
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_hs_client.c b/src/test/test_hs_client.c
new file mode 100644
index 0000000000..750920fac0
--- /dev/null
+++ b/src/test/test_hs_client.c
@@ -0,0 +1,599 @@
+/* Copyright (c) 2016-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file test_hs_client.c
+ * \brief Test prop224 HS client functionality.
+ */
+
+#define CRYPTO_PRIVATE
+#define MAIN_PRIVATE
+#define HS_CLIENT_PRIVATE
+#define TOR_CHANNEL_INTERNAL_
+#define CIRCUITBUILD_PRIVATE
+#define CIRCUITLIST_PRIVATE
+#define CONNECTION_PRIVATE
+
+#include "test.h"
+#include "test_helpers.h"
+#include "log_test_helpers.h"
+#include "rend_test_helpers.h"
+#include "hs_test_helpers.h"
+
+#include "config.h"
+#include "crypto.h"
+#include "channeltls.h"
+#include "main.h"
+#include "nodelist.h"
+#include "routerset.h"
+
+#include "hs_circuit.h"
+#include "hs_client.h"
+#include "hs_ident.h"
+#include "hs_cache.h"
+#include "circuitlist.h"
+#include "circuitbuild.h"
+#include "connection.h"
+#include "connection_edge.h"
+#include "networkstatus.h"
+
+static int
+mock_connection_ap_handshake_send_begin(entry_connection_t *ap_conn)
+{
+ (void) ap_conn;
+ return 0;
+}
+
+static networkstatus_t mock_ns;
+
+/* Always return NULL. */
+static networkstatus_t *
+mock_networkstatus_get_live_consensus_false(time_t now)
+{
+ (void) now;
+ return NULL;
+}
+
+static networkstatus_t *
+mock_networkstatus_get_live_consensus(time_t now)
+{
+ (void) now;
+ return &mock_ns;
+}
+
+/* Test helper function: Setup a circuit and a stream with the same hidden
+ * service destination, and put them in <b>circ_out</b> and
+ * <b>conn_out</b>. Make the stream wait for circuits to be established to the
+ * hidden service. */
+static int
+helper_get_circ_and_stream_for_test(origin_circuit_t **circ_out,
+ connection_t **conn_out,
+ int is_legacy)
+{
+ int retval;
+ channel_tls_t *n_chan=NULL;
+ rend_data_t *conn_rend_data = NULL;
+ origin_circuit_t *or_circ = NULL;
+ connection_t *conn = NULL;
+ ed25519_public_key_t service_pk;
+
+ /* Make a dummy connection stream and make it wait for our circuit */
+ conn = test_conn_get_connection(AP_CONN_STATE_CIRCUIT_WAIT,
+ CONN_TYPE_AP /* ??? */,
+ 0);
+ if (is_legacy) {
+ /* Legacy: Setup rend_data of stream */
+ char service_id[REND_SERVICE_ID_LEN_BASE32+1] = {0};
+ TO_EDGE_CONN(conn)->rend_data = mock_rend_data(service_id);
+ conn_rend_data = TO_EDGE_CONN(conn)->rend_data;
+ } else {
+ /* prop224: Setup hs conn identifier on the stream */
+ ed25519_secret_key_t sk;
+ tt_int_op(0, OP_EQ, ed25519_secret_key_generate(&sk, 0));
+ tt_int_op(0, OP_EQ, ed25519_public_key_generate(&service_pk, &sk));
+
+ /* Setup hs_conn_identifier of stream */
+ TO_EDGE_CONN(conn)->hs_ident = hs_ident_edge_conn_new(&service_pk);
+ }
+
+ /* Make it wait for circuit */
+ connection_ap_mark_as_pending_circuit(TO_ENTRY_CONN(conn));
+
+ /* This is needed to silence a BUG warning from
+ connection_edge_update_circuit_isolation() */
+ TO_ENTRY_CONN(conn)->original_dest_address =
+ tor_strdup(TO_ENTRY_CONN(conn)->socks_request->address);
+
+ /****************************************************/
+
+ /* Now make dummy circuit */
+ or_circ = origin_circuit_new();
+
+ or_circ->base_.purpose = CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED;
+
+ or_circ->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
+ or_circ->build_state->is_internal = 1;
+
+ if (is_legacy) {
+ /* Legacy: Setup rend data and final cpath */
+ or_circ->build_state->pending_final_cpath =
+ tor_malloc_zero(sizeof(crypt_path_t));
+ or_circ->build_state->pending_final_cpath->magic = CRYPT_PATH_MAGIC;
+ or_circ->build_state->pending_final_cpath->rend_dh_handshake_state =
+ crypto_dh_new(DH_TYPE_REND);
+ tt_assert(
+ or_circ->build_state->pending_final_cpath->rend_dh_handshake_state);
+ retval = crypto_dh_generate_public(
+ or_circ->build_state->pending_final_cpath->rend_dh_handshake_state);
+ tt_int_op(retval, OP_EQ, 0);
+ or_circ->rend_data = rend_data_dup(conn_rend_data);
+ } else {
+ /* prop224: Setup hs ident on the circuit */
+ or_circ->hs_ident = hs_ident_circuit_new(&service_pk,
+ HS_IDENT_CIRCUIT_RENDEZVOUS);
+ }
+
+ TO_CIRCUIT(or_circ)->state = CIRCUIT_STATE_OPEN;
+
+ /* fake n_chan */
+ n_chan = tor_malloc_zero(sizeof(channel_tls_t));
+ n_chan->base_.global_identifier = 1;
+ or_circ->base_.n_chan = &(n_chan->base_);
+
+ *circ_out = or_circ;
+ *conn_out = conn;
+
+ return 0;
+
+ done:
+ /* something failed */
+ return -1;
+}
+
+/* Test: Ensure that setting up legacy e2e rendezvous circuits works
+ * correctly. */
+static void
+test_e2e_rend_circuit_setup_legacy(void *arg)
+{
+ ssize_t retval;
+ origin_circuit_t *or_circ = NULL;
+ connection_t *conn = NULL;
+
+ (void) arg;
+
+ /** In this test we create a v2 legacy HS stream and a circuit with the same
+ * hidden service destination. We make the stream wait for circuits to be
+ * established to the hidden service, and then we complete the circuit using
+ * the hs_circuit_setup_e2e_rend_circ_legacy_client() function. We then
+ * check that the end-to-end cpath was setup correctly and that the stream
+ * was attached to the circuit as expected. */
+
+ MOCK(connection_ap_handshake_send_begin,
+ mock_connection_ap_handshake_send_begin);
+
+ /* Setup */
+ retval = helper_get_circ_and_stream_for_test( &or_circ, &conn, 1);
+ tt_int_op(retval, OP_EQ, 0);
+ tt_assert(or_circ);
+ tt_assert(conn);
+
+ /* Check number of hops */
+ retval = cpath_get_n_hops(&or_circ->cpath);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /* Check that our stream is not attached on any circuits */
+ tt_ptr_op(TO_EDGE_CONN(conn)->on_circuit, OP_EQ, NULL);
+
+ /********************************************** */
+
+ /* Make a good RENDEZVOUS1 cell body because it needs to pass key exchange
+ * digest verification... */
+ uint8_t rend_cell_body[DH_KEY_LEN+DIGEST_LEN] = {2};
+ {
+ char keys[DIGEST_LEN+CPATH_KEY_MATERIAL_LEN];
+ crypto_dh_t *dh_state =
+ or_circ->build_state->pending_final_cpath->rend_dh_handshake_state;
+ /* compute and overwrite digest of cell body with the right value */
+ retval = crypto_dh_compute_secret(LOG_PROTOCOL_WARN, dh_state,
+ (char*)rend_cell_body, DH_KEY_LEN,
+ keys, DIGEST_LEN+CPATH_KEY_MATERIAL_LEN);
+ tt_int_op(retval, OP_GT, 0);
+ memcpy(rend_cell_body+DH_KEY_LEN, keys, DIGEST_LEN);
+ }
+
+ /* Setup the circuit */
+ retval = hs_circuit_setup_e2e_rend_circ_legacy_client(or_circ,
+ rend_cell_body);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /**********************************************/
+
+ /* See that a hop was added to the circuit's cpath */
+ retval = cpath_get_n_hops(&or_circ->cpath);
+ tt_int_op(retval, OP_EQ, 1);
+
+ /* Check the digest algo */
+ tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->f_digest),
+ OP_EQ, DIGEST_SHA1);
+ tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->b_digest),
+ OP_EQ, DIGEST_SHA1);
+ tt_assert(or_circ->cpath->f_crypto);
+ tt_assert(or_circ->cpath->b_crypto);
+
+ /* Ensure that circ purpose was changed */
+ tt_int_op(or_circ->base_.purpose, OP_EQ, CIRCUIT_PURPOSE_C_REND_JOINED);
+
+ /* Test that stream got attached */
+ tt_ptr_op(TO_EDGE_CONN(conn)->on_circuit, OP_EQ, TO_CIRCUIT(or_circ));
+
+ done:
+ connection_free_(conn);
+ if (or_circ)
+ tor_free(TO_CIRCUIT(or_circ)->n_chan);
+ circuit_free(TO_CIRCUIT(or_circ));
+}
+
+/* Test: Ensure that setting up v3 rendezvous circuits works correctly. */
+static void
+test_e2e_rend_circuit_setup(void *arg)
+{
+ uint8_t ntor_key_seed[DIGEST256_LEN] = {0};
+ origin_circuit_t *or_circ = NULL;
+ int retval;
+ connection_t *conn = NULL;
+
+ (void) arg;
+
+ /** In this test we create a prop224 v3 HS stream and a circuit with the same
+ * hidden service destination. We make the stream wait for circuits to be
+ * established to the hidden service, and then we complete the circuit using
+ * the hs_circuit_setup_e2e_rend_circ() function. We then check that the
+ * end-to-end cpath was setup correctly and that the stream was attached to
+ * the circuit as expected. */
+
+ MOCK(connection_ap_handshake_send_begin,
+ mock_connection_ap_handshake_send_begin);
+
+ /* Setup */
+ retval = helper_get_circ_and_stream_for_test( &or_circ, &conn, 0);
+ tt_int_op(retval, OP_EQ, 0);
+ tt_assert(or_circ);
+ tt_assert(conn);
+
+ /* Check number of hops: There should be no hops yet to this circ */
+ retval = cpath_get_n_hops(&or_circ->cpath);
+ tt_int_op(retval, OP_EQ, 0);
+ tt_ptr_op(or_circ->cpath, OP_EQ, NULL);
+
+ /* Check that our stream is not attached on any circuits */
+ tt_ptr_op(TO_EDGE_CONN(conn)->on_circuit, OP_EQ, NULL);
+
+ /**********************************************/
+
+ /* Setup the circuit */
+ retval = hs_circuit_setup_e2e_rend_circ(or_circ,
+ ntor_key_seed, sizeof(ntor_key_seed),
+ 0);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /**********************************************/
+
+ /* See that a hop was added to the circuit's cpath */
+ retval = cpath_get_n_hops(&or_circ->cpath);
+ tt_int_op(retval, OP_EQ, 1);
+
+ /* Check that the crypt path has prop224 algorithm parameters */
+ tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->f_digest),
+ OP_EQ, DIGEST_SHA3_256);
+ tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->b_digest),
+ OP_EQ, DIGEST_SHA3_256);
+ tt_assert(or_circ->cpath->f_crypto);
+ tt_assert(or_circ->cpath->b_crypto);
+
+ /* Ensure that circ purpose was changed */
+ tt_int_op(or_circ->base_.purpose, OP_EQ, CIRCUIT_PURPOSE_C_REND_JOINED);
+
+ /* Test that stream got attached */
+ tt_ptr_op(TO_EDGE_CONN(conn)->on_circuit, OP_EQ, TO_CIRCUIT(or_circ));
+
+ done:
+ connection_free_(conn);
+ if (or_circ)
+ tor_free(TO_CIRCUIT(or_circ)->n_chan);
+ circuit_free(TO_CIRCUIT(or_circ));
+}
+
+/** Test client logic for picking intro points from a descriptor. Also test how
+ * ExcludeNodes and intro point failures affect picking intro points. */
+static void
+test_client_pick_intro(void *arg)
+{
+ int ret;
+ ed25519_keypair_t service_kp;
+ hs_descriptor_t *desc = NULL;
+
+ MOCK(networkstatus_get_live_consensus,
+ mock_networkstatus_get_live_consensus);
+
+ (void) arg;
+
+ hs_init();
+
+ /* Generate service keypair */
+ tt_int_op(0, OP_EQ, ed25519_keypair_generate(&service_kp, 0));
+
+ /* Set time */
+ ret = parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC",
+ &mock_ns.valid_after);
+ tt_int_op(ret, OP_EQ, 0);
+ ret = parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC",
+ &mock_ns.fresh_until);
+ tt_int_op(ret, OP_EQ, 0);
+
+ update_approx_time(mock_ns.fresh_until-10);
+ time_t now = approx_time();
+
+ /* Test logic:
+ *
+ * 1) Add our desc with intro points to the HS cache.
+ *
+ * 2) Mark all descriptor intro points except _the chosen one_ as
+ * failed. Then query the desc to get a random intro: check that we got
+ * _the chosen one_. Then fail the chosen one as well, and see that no
+ * intros are returned.
+ *
+ * 3) Then clean the intro state cache and get an intro point.
+ *
+ * 4) Try fetching an intro with the wrong service key: shouldn't work
+ *
+ * 5) Set StrictNodes and put all our intro points in ExcludeNodes: see that
+ * nothing is returned.
+ */
+
+ /* 1) Add desc to HS cache */
+ {
+ char *encoded = NULL;
+ desc = hs_helper_build_hs_desc_with_ip(&service_kp);
+ ret = hs_desc_encode_descriptor(desc, &service_kp, &encoded);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_assert(encoded);
+
+ /* store it */
+ hs_cache_store_as_client(encoded, &service_kp.pubkey);
+
+ /* fetch it to make sure it works */
+ const hs_descriptor_t *fetched_desc =
+ hs_cache_lookup_as_client(&service_kp.pubkey);
+ tt_assert(fetched_desc);
+ tt_mem_op(fetched_desc->subcredential, OP_EQ, desc->subcredential,
+ DIGEST256_LEN);
+ tt_assert(!tor_mem_is_zero((char*)fetched_desc->subcredential,
+ DIGEST256_LEN));
+ tor_free(encoded);
+ }
+
+ /* 2) Mark all intro points except _the chosen one_ as failed. Then query the
+ * desc and get a random intro: check that we got _the chosen one_. */
+ {
+ /* Pick the chosen intro point and get its ei */
+ hs_desc_intro_point_t *chosen_intro_point =
+ smartlist_get(desc->encrypted_data.intro_points, 0);
+ extend_info_t *chosen_intro_ei =
+ desc_intro_point_to_extend_info(chosen_intro_point);
+ tt_assert(chosen_intro_point);
+ tt_assert(chosen_intro_ei);
+
+ /* Now mark all other intro points as failed */
+ SMARTLIST_FOREACH_BEGIN(desc->encrypted_data.intro_points,
+ hs_desc_intro_point_t *, ip) {
+ /* Skip the chosen intro point */
+ if (ip == chosen_intro_point) {
+ continue;
+ }
+ ed25519_public_key_t *intro_auth_key = &ip->auth_key_cert->signed_key;
+ hs_cache_client_intro_state_note(&service_kp.pubkey,
+ intro_auth_key,
+ INTRO_POINT_FAILURE_GENERIC);
+ } SMARTLIST_FOREACH_END(ip);
+
+ /* Try to get a random intro: Should return the chosen one! */
+ extend_info_t *ip = client_get_random_intro(&service_kp.pubkey);
+ tor_assert(ip);
+ tt_assert(!tor_mem_is_zero((char*)ip->identity_digest, DIGEST_LEN));
+ tt_mem_op(ip->identity_digest, OP_EQ, chosen_intro_ei->identity_digest,
+ DIGEST_LEN);
+
+ extend_info_free(chosen_intro_ei);
+ extend_info_free(ip);
+
+ /* Now also mark the chosen one as failed: See that we can't get any intro
+ points anymore. */
+ hs_cache_client_intro_state_note(&service_kp.pubkey,
+ &chosen_intro_point->auth_key_cert->signed_key,
+ INTRO_POINT_FAILURE_TIMEOUT);
+ ip = client_get_random_intro(&service_kp.pubkey);
+ tor_assert(!ip);
+ }
+
+ /* 3) Clean the intro state cache and get an intro point */
+ {
+ /* Pretend we are 5 mins in the future and order a cleanup of the intro
+ * state. This should clean up the intro point failures and allow us to get
+ * an intro. */
+ hs_cache_client_intro_state_clean(now + 5*60);
+
+ /* Get an intro. It should work! */
+ extend_info_t *ip = client_get_random_intro(&service_kp.pubkey);
+ tor_assert(ip);
+ extend_info_free(ip);
+ }
+
+ /* 4) Try fetching an intro with the wrong service key: shouldn't work */
+ {
+ ed25519_keypair_t dummy_kp;
+ tt_int_op(0, OP_EQ, ed25519_keypair_generate(&dummy_kp, 0));
+ extend_info_t *ip = client_get_random_intro(&dummy_kp.pubkey);
+ tor_assert(!ip);
+ }
+
+ /* 5) Set StrictNodes and put all our intro points in ExcludeNodes: see that
+ * nothing is returned. */
+ {
+ get_options_mutable()->ExcludeNodes = routerset_new();
+ get_options_mutable()->StrictNodes = 1;
+ SMARTLIST_FOREACH_BEGIN(desc->encrypted_data.intro_points,
+ hs_desc_intro_point_t *, ip) {
+ extend_info_t *intro_ei = desc_intro_point_to_extend_info(ip);
+ if (intro_ei) {
+ const char *ptr;
+ char ip_addr[TOR_ADDR_BUF_LEN];
+ /* We need to decorate in case it is an IPv6 else routerset_parse()
+ * doesn't like it. */
+ ptr = tor_addr_to_str(ip_addr, &intro_ei->addr, sizeof(ip_addr), 1);
+ tt_assert(ptr == ip_addr);
+ ret = routerset_parse(get_options_mutable()->ExcludeNodes,
+ ip_addr, "");
+ tt_int_op(ret, OP_EQ, 0);
+ extend_info_free(intro_ei);
+ }
+ } SMARTLIST_FOREACH_END(ip);
+
+ extend_info_t *ip = client_get_random_intro(&service_kp.pubkey);
+ tt_assert(!ip);
+ }
+
+ done:
+ hs_descriptor_free(desc);
+}
+
+static int
+mock_router_have_minimum_dir_info_false(void)
+{
+ return 0;
+}
+static int
+mock_router_have_minimum_dir_info_true(void)
+{
+ return 1;
+}
+
+static hs_client_fetch_status_t
+mock_fetch_v3_desc_error(const ed25519_public_key_t *key)
+{
+ (void) key;
+ return HS_CLIENT_FETCH_ERROR;
+}
+
+static void
+mock_connection_mark_unattached_ap_(entry_connection_t *conn, int endreason,
+ int line, const char *file)
+{
+ (void) line;
+ (void) file;
+ conn->edge_.end_reason = endreason;
+}
+
+static void
+test_descriptor_fetch(void *arg)
+{
+ int ret;
+ entry_connection_t *ec = NULL;
+ ed25519_public_key_t service_pk;
+ ed25519_secret_key_t service_sk;
+
+ (void) arg;
+
+ hs_init();
+ memset(&service_sk, 'A', sizeof(service_sk));
+ ret = ed25519_public_key_generate(&service_pk, &service_sk);
+ tt_int_op(ret, OP_EQ, 0);
+
+ /* Initialize this so get_voting_interval() doesn't freak out. */
+ ret = parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC",
+ &mock_ns.valid_after);
+ tt_int_op(ret, OP_EQ, 0);
+ ret = parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC",
+ &mock_ns.fresh_until);
+ tt_int_op(ret, OP_EQ, 0);
+
+ ec = entry_connection_new(CONN_TYPE_AP, AF_INET);
+ tt_assert(ec);
+ ENTRY_TO_EDGE_CONN(ec)->hs_ident = hs_ident_edge_conn_new(&service_pk);
+ tt_assert(ENTRY_TO_EDGE_CONN(ec)->hs_ident);
+ TO_CONN(ENTRY_TO_EDGE_CONN(ec))->state = AP_CONN_STATE_RENDDESC_WAIT;
+ smartlist_add(get_connection_array(), &ec->edge_.base_);
+
+ /* 1. FetchHidServDescriptors is false so we shouldn't be able to fetch. */
+ get_options_mutable()->FetchHidServDescriptors = 0;
+ ret = hs_client_refetch_hsdesc(&service_pk);
+ tt_int_op(ret, OP_EQ, HS_CLIENT_FETCH_NOT_ALLOWED);
+ get_options_mutable()->FetchHidServDescriptors = 1;
+
+ /* 2. We don't have a live consensus. */
+ MOCK(networkstatus_get_live_consensus,
+ mock_networkstatus_get_live_consensus_false);
+ ret = hs_client_refetch_hsdesc(&service_pk);
+ UNMOCK(networkstatus_get_live_consensus);
+ tt_int_op(ret, OP_EQ, HS_CLIENT_FETCH_MISSING_INFO);
+
+ /* From now on, return a live consensus. */
+ MOCK(networkstatus_get_live_consensus,
+ mock_networkstatus_get_live_consensus);
+
+ /* 3. Not enough dir information. */
+ MOCK(router_have_minimum_dir_info,
+ mock_router_have_minimum_dir_info_false);
+ ret = hs_client_refetch_hsdesc(&service_pk);
+ UNMOCK(router_have_minimum_dir_info);
+ tt_int_op(ret, OP_EQ, HS_CLIENT_FETCH_MISSING_INFO);
+
+ /* From now on, we do have enough directory information. */
+ MOCK(router_have_minimum_dir_info,
+ mock_router_have_minimum_dir_info_true);
+
+ /* 4. We do have a pending directory request. */
+ {
+ dir_connection_t *dir_conn = dir_connection_new(AF_INET);
+ dir_conn->hs_ident = tor_malloc_zero(sizeof(hs_ident_dir_conn_t));
+ TO_CONN(dir_conn)->purpose = DIR_PURPOSE_FETCH_HSDESC;
+ ed25519_pubkey_copy(&dir_conn->hs_ident->identity_pk, &service_pk);
+ smartlist_add(get_connection_array(), TO_CONN(dir_conn));
+ ret = hs_client_refetch_hsdesc(&service_pk);
+ smartlist_remove(get_connection_array(), TO_CONN(dir_conn));
+ connection_free_(TO_CONN(dir_conn));
+ tt_int_op(ret, OP_EQ, HS_CLIENT_FETCH_PENDING);
+ }
+
+ /* 5. We'll trigger an error on the fetch_desc_v3 and force to close all
+ * pending SOCKS request. */
+ MOCK(router_have_minimum_dir_info,
+ mock_router_have_minimum_dir_info_true);
+ MOCK(fetch_v3_desc, mock_fetch_v3_desc_error);
+ MOCK(connection_mark_unattached_ap_,
+ mock_connection_mark_unattached_ap_);
+ ret = hs_client_refetch_hsdesc(&service_pk);
+ UNMOCK(fetch_v3_desc);
+ UNMOCK(connection_mark_unattached_ap_);
+ tt_int_op(ret, OP_EQ, HS_CLIENT_FETCH_ERROR);
+ /* The close waiting for descriptor function has been called. */
+ tt_int_op(ec->edge_.end_reason, OP_EQ, END_STREAM_REASON_RESOLVEFAILED);
+
+ done:
+ connection_free_(ENTRY_TO_CONN(ec));
+ UNMOCK(networkstatus_get_live_consensus);
+ UNMOCK(router_have_minimum_dir_info);
+ hs_free_all();
+}
+
+struct testcase_t hs_client_tests[] = {
+ { "e2e_rend_circuit_setup_legacy", test_e2e_rend_circuit_setup_legacy,
+ TT_FORK, NULL, NULL },
+ { "e2e_rend_circuit_setup", test_e2e_rend_circuit_setup,
+ TT_FORK, NULL, NULL },
+ { "client_pick_intro", test_client_pick_intro,
+ TT_FORK, NULL, NULL },
+ { "descriptor_fetch", test_descriptor_fetch,
+ TT_FORK, NULL, NULL },
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_hs_common.c b/src/test/test_hs_common.c
new file mode 100644
index 0000000000..3ae623ed0a
--- /dev/null
+++ b/src/test/test_hs_common.c
@@ -0,0 +1,1827 @@
+/* Copyright (c) 2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file test_hs_common.c
+ * \brief Test hidden service common functionalities.
+ */
+
+#define HS_COMMON_PRIVATE
+#define HS_CLIENT_PRIVATE
+#define HS_SERVICE_PRIVATE
+#define NODELIST_PRIVATE
+
+#include "test.h"
+#include "test_helpers.h"
+#include "log_test_helpers.h"
+#include "hs_test_helpers.h"
+
+#include "connection_edge.h"
+#include "hs_common.h"
+#include "hs_client.h"
+#include "hs_service.h"
+#include "config.h"
+#include "networkstatus.h"
+#include "directory.h"
+#include "dirvote.h"
+#include "nodelist.h"
+#include "routerlist.h"
+#include "statefile.h"
+#include "circuitlist.h"
+#include "shared_random.h"
+#include "util.h"
+
+/** Test the validation of HS v3 addresses */
+static void
+test_validate_address(void *arg)
+{
+ int ret;
+
+ (void) arg;
+
+ /* Address too short and too long. */
+ setup_full_capture_of_logs(LOG_WARN);
+ ret = hs_address_is_valid("blah");
+ tt_int_op(ret, OP_EQ, 0);
+ expect_log_msg_containing("has an invalid length");
+ teardown_capture_of_logs();
+
+ setup_full_capture_of_logs(LOG_WARN);
+ ret = hs_address_is_valid(
+ "p3xnclpu4mu22dwaurjtsybyqk4xfjmcfz6z62yl24uwmhjatiwnlnadb");
+ tt_int_op(ret, OP_EQ, 0);
+ expect_log_msg_containing("has an invalid length");
+ teardown_capture_of_logs();
+
+ /* Invalid checksum (taken from prop224) */
+ setup_full_capture_of_logs(LOG_WARN);
+ ret = hs_address_is_valid(
+ "l5satjgud6gucryazcyvyvhuxhr74u6ygigiuyixe3a6ysis67ororad");
+ tt_int_op(ret, OP_EQ, 0);
+ expect_log_msg_containing("invalid checksum");
+ teardown_capture_of_logs();
+
+ setup_full_capture_of_logs(LOG_WARN);
+ ret = hs_address_is_valid(
+ "btojiu7nu5y5iwut64eufevogqdw4wmqzugnoluw232r4t3ecsfv37ad");
+ tt_int_op(ret, OP_EQ, 0);
+ expect_log_msg_containing("invalid checksum");
+ teardown_capture_of_logs();
+
+ /* Non base32 decodable string. */
+ setup_full_capture_of_logs(LOG_WARN);
+ ret = hs_address_is_valid(
+ "????????????????????????????????????????????????????????");
+ tt_int_op(ret, OP_EQ, 0);
+ expect_log_msg_containing("can't be decoded");
+ teardown_capture_of_logs();
+
+ /* Valid address. */
+ ret = hs_address_is_valid(
+ "25njqamcweflpvkl73j4szahhihoc4xt3ktcgjnpaingr5yhkenl5sid");
+ tt_int_op(ret, OP_EQ, 1);
+
+ done:
+ ;
+}
+
+static int
+mock_write_str_to_file(const char *path, const char *str, int bin)
+{
+ (void)bin;
+ tt_str_op(path, OP_EQ, "/double/five"PATH_SEPARATOR"squared");
+ tt_str_op(str, OP_EQ,
+ "25njqamcweflpvkl73j4szahhihoc4xt3ktcgjnpaingr5yhkenl5sid.onion\n");
+
+ done:
+ return 0;
+}
+
+/** Test building HS v3 onion addresses. Uses test vectors from the
+ * ./hs_build_address.py script. */
+static void
+test_build_address(void *arg)
+{
+ int ret;
+ char onion_addr[HS_SERVICE_ADDR_LEN_BASE32 + 1];
+ ed25519_public_key_t pubkey;
+ /* hex-encoded ed25519 pubkey used in hs_build_address.py */
+ char pubkey_hex[] =
+ "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a";
+ hs_service_t *service = NULL;
+
+ (void) arg;
+
+ MOCK(write_str_to_file, mock_write_str_to_file);
+
+ /* The following has been created with hs_build_address.py script that
+ * follows proposal 224 specification to build an onion address. */
+ static const char *test_addr =
+ "25njqamcweflpvkl73j4szahhihoc4xt3ktcgjnpaingr5yhkenl5sid";
+
+ /* Let's try to build the same onion address as the script */
+ base16_decode((char*)pubkey.pubkey, sizeof(pubkey.pubkey),
+ pubkey_hex, strlen(pubkey_hex));
+ hs_build_address(&pubkey, HS_VERSION_THREE, onion_addr);
+ tt_str_op(test_addr, OP_EQ, onion_addr);
+ /* Validate that address. */
+ ret = hs_address_is_valid(onion_addr);
+ tt_int_op(ret, OP_EQ, 1);
+
+ service = tor_malloc_zero(sizeof(hs_service_t));
+ memcpy(service->onion_address, onion_addr, sizeof(service->onion_address));
+ tor_asprintf(&service->config.directory_path, "/double/five");
+ ret = write_address_to_file(service, "squared");
+ tt_int_op(ret, OP_EQ, 0);
+
+ done:
+ hs_service_free(service);
+}
+
+/** 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, correct_time, start_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, OP_EQ, 0);
+
+ /* Check that the time period number is right */
+ tn = hs_get_time_period_num(fake_time);
+ tt_u64_op(tn, OP_EQ, 16903);
+
+ /* Increase current time to 11:59:59 UTC and check that the time period
+ number is still the same */
+ fake_time += 3599;
+ tn = hs_get_time_period_num(fake_time);
+ tt_u64_op(tn, OP_EQ, 16903);
+
+ { /* Check start time of next time period */
+ retval = parse_rfc1123_time("Wed, 13 Apr 2016 12:00:00 UTC",
+ &correct_time);
+ tt_int_op(retval, OP_EQ, 0);
+
+ start_time = hs_get_start_time_of_next_time_period(fake_time);
+ tt_int_op(start_time, OP_EQ, correct_time);
+ }
+
+ /* Now take time to 12:00:00 UTC and check that the time period rotated */
+ fake_time += 1;
+ tn = hs_get_time_period_num(fake_time);
+ tt_u64_op(tn, OP_EQ, 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, OP_EQ, 16905);
+
+ { /* Check start time of next time period again */
+ retval = parse_rfc1123_time("Wed, 14 Apr 2016 12:00:00 UTC",
+ &correct_time);
+ tt_int_op(retval, OP_EQ, 0);
+
+ start_time = hs_get_start_time_of_next_time_period(fake_time);
+ tt_int_op(start_time, OP_EQ, correct_time);
+ }
+
+ /* Now do another sanity check: The time period number at the start of the
+ * next time period, must be the same time period number as the one returned
+ * from hs_get_next_time_period_num() */
+ {
+ time_t next_tp_start = hs_get_start_time_of_next_time_period(fake_time);
+ tt_u64_op(hs_get_time_period_num(next_tp_start), OP_EQ,
+ hs_get_next_time_period_num(fake_time));
+ }
+
+ done:
+ ;
+}
+
+/** Test that we can correctly find the start time of the next time period */
+static void
+test_start_time_of_next_time_period(void *arg)
+{
+ (void) arg;
+ int retval;
+ time_t fake_time;
+ char tbuf[ISO_TIME_LEN + 1];
+ time_t next_tp_start_time;
+
+ /* Do some basic tests */
+ retval = parse_rfc1123_time("Wed, 13 Apr 2016 11:00:00 UTC",
+ &fake_time);
+ tt_int_op(retval, OP_EQ, 0);
+ next_tp_start_time = hs_get_start_time_of_next_time_period(fake_time);
+ /* Compare it with the correct result */
+ format_iso_time(tbuf, next_tp_start_time);
+ tt_str_op("2016-04-13 12:00:00", OP_EQ, tbuf);
+
+ /* Another test with an edge-case time (start of TP) */
+ retval = parse_rfc1123_time("Wed, 13 Apr 2016 12:00:00 UTC",
+ &fake_time);
+ tt_int_op(retval, OP_EQ, 0);
+ next_tp_start_time = hs_get_start_time_of_next_time_period(fake_time);
+ format_iso_time(tbuf, next_tp_start_time);
+ tt_str_op("2016-04-14 12:00:00", OP_EQ, tbuf);
+
+ {
+ /* Now pretend we are on a testing network and alter the voting schedule to
+ be every 10 seconds. This means that a time period has length 10*24
+ seconds (4 minutes). It also means that we apply a rotational offset of
+ 120 seconds to the time period, so that it starts at 00:02:00 instead of
+ 00:00:00. */
+ or_options_t *options = get_options_mutable();
+ options->TestingTorNetwork = 1;
+ options->V3AuthVotingInterval = 10;
+ options->TestingV3AuthInitialVotingInterval = 10;
+
+ retval = parse_rfc1123_time("Wed, 13 Apr 2016 00:00:00 UTC",
+ &fake_time);
+ tt_int_op(retval, OP_EQ, 0);
+ next_tp_start_time = hs_get_start_time_of_next_time_period(fake_time);
+ /* Compare it with the correct result */
+ format_iso_time(tbuf, next_tp_start_time);
+ tt_str_op("2016-04-13 00:02:00", OP_EQ, tbuf);
+
+ retval = parse_rfc1123_time("Wed, 13 Apr 2016 00:02:00 UTC",
+ &fake_time);
+ tt_int_op(retval, OP_EQ, 0);
+ next_tp_start_time = hs_get_start_time_of_next_time_period(fake_time);
+ /* Compare it with the correct result */
+ format_iso_time(tbuf, next_tp_start_time);
+ tt_str_op("2016-04-13 00:06:00", OP_EQ, tbuf);
+ }
+
+ done:
+ ;
+}
+
+/* Cleanup the global nodelist. It also frees the "md" in the node_t because
+ * we allocate the memory in helper_add_hsdir_to_networkstatus(). */
+static void
+cleanup_nodelist(void)
+{
+ smartlist_t *nodelist = nodelist_get_list();
+ SMARTLIST_FOREACH_BEGIN(nodelist, node_t *, node) {
+ tor_free(node->md);
+ node->md = NULL;
+ } SMARTLIST_FOREACH_END(node);
+ nodelist_free_all();
+}
+
+static void
+helper_add_hsdir_to_networkstatus(networkstatus_t *ns,
+ int identity_idx,
+ const char *nickname,
+ int is_hsdir)
+{
+ routerstatus_t *rs = tor_malloc_zero(sizeof(routerstatus_t));
+ routerinfo_t *ri = tor_malloc_zero(sizeof(routerinfo_t));
+ uint8_t identity[DIGEST_LEN];
+ tor_addr_t ipv4_addr;
+ node_t *node = NULL;
+
+ memset(identity, identity_idx, sizeof(identity));
+
+ memcpy(rs->identity_digest, identity, DIGEST_LEN);
+ rs->is_hs_dir = is_hsdir;
+ rs->supports_v3_hsdir = 1;
+ strlcpy(rs->nickname, nickname, sizeof(rs->nickname));
+ tor_addr_parse(&ipv4_addr, "1.2.3.4");
+ ri->addr = tor_addr_to_ipv4h(&ipv4_addr);
+ rs->addr = tor_addr_to_ipv4h(&ipv4_addr);
+ ri->nickname = tor_strdup(nickname);
+ ri->protocol_list = tor_strdup("HSDir=1-2 LinkAuth=3");
+ memcpy(ri->cache_info.identity_digest, identity, DIGEST_LEN);
+ ri->cache_info.signing_key_cert = tor_malloc_zero(sizeof(tor_cert_t));
+ /* Needed for the HSDir index computation. */
+ memset(&ri->cache_info.signing_key_cert->signing_key,
+ identity_idx, ED25519_PUBKEY_LEN);
+ tt_assert(nodelist_set_routerinfo(ri, NULL));
+
+ node = node_get_mutable_by_id(ri->cache_info.identity_digest);
+ tt_assert(node);
+ node->rs = rs;
+ /* We need this to exist for node_has_descriptor() to return true. */
+ node->md = tor_malloc_zero(sizeof(microdesc_t));
+ /* Do this now the nodelist_set_routerinfo() function needs a "rs" to set
+ * the indexes which it doesn't have when it is called. */
+ node_set_hsdir_index(node, ns);
+ node->ri = NULL;
+ smartlist_add(ns->routerstatus_list, rs);
+
+ done:
+ if (node == NULL)
+ routerstatus_free(rs);
+
+ routerinfo_free(ri);
+}
+
+static networkstatus_t *mock_ns = NULL;
+
+static networkstatus_t *
+mock_networkstatus_get_latest_consensus(void)
+{
+ time_t now = approx_time();
+
+ /* If initialized, return it */
+ if (mock_ns) {
+ return mock_ns;
+ }
+
+ /* Initialize fake consensus */
+ mock_ns = tor_malloc_zero(sizeof(networkstatus_t));
+
+ /* This consensus is live */
+ mock_ns->valid_after = now-1;
+ mock_ns->fresh_until = now+1;
+ mock_ns->valid_until = now+2;
+ /* Create routerstatus list */
+ mock_ns->routerstatus_list = smartlist_new();
+ mock_ns->type = NS_TYPE_CONSENSUS;
+
+ return mock_ns;
+}
+
+static networkstatus_t *
+mock_networkstatus_get_live_consensus(time_t now)
+{
+ (void) now;
+
+ tt_assert(mock_ns);
+
+ done:
+ return mock_ns;
+}
+
+/** Test the responsible HSDirs calculation function */
+static void
+test_responsible_hsdirs(void *arg)
+{
+ time_t now = approx_time();
+ smartlist_t *responsible_dirs = smartlist_new();
+ networkstatus_t *ns = NULL;
+ int retval;
+
+ (void) arg;
+
+ hs_init();
+
+ MOCK(networkstatus_get_latest_consensus,
+ mock_networkstatus_get_latest_consensus);
+
+ ns = networkstatus_get_latest_consensus();
+
+ { /* First router: HSdir */
+ helper_add_hsdir_to_networkstatus(ns, 1, "igor", 1);
+ }
+
+ { /* Second HSDir */
+ helper_add_hsdir_to_networkstatus(ns, 2, "victor", 1);
+ }
+
+ { /* Third relay but not HSDir */
+ helper_add_hsdir_to_networkstatus(ns, 3, "spyro", 0);
+ }
+
+ ed25519_keypair_t kp;
+ retval = ed25519_keypair_generate(&kp, 0);
+ tt_int_op(retval, OP_EQ , 0);
+
+ uint64_t time_period_num = hs_get_time_period_num(now);
+ hs_get_responsible_hsdirs(&kp.pubkey, time_period_num,
+ 0, 0, responsible_dirs);
+
+ /* Make sure that we only found 2 responsible HSDirs.
+ * The third relay was not an hsdir! */
+ tt_int_op(smartlist_len(responsible_dirs), OP_EQ, 2);
+
+ /** TODO: Build a bigger network and do more tests here */
+
+ done:
+ SMARTLIST_FOREACH(ns->routerstatus_list,
+ routerstatus_t *, rs, routerstatus_free(rs));
+ smartlist_free(responsible_dirs);
+ smartlist_clear(ns->routerstatus_list);
+ networkstatus_vote_free(mock_ns);
+ cleanup_nodelist();
+}
+
+static void
+mock_directory_initiate_request(directory_request_t *req)
+{
+ (void)req;
+ return;
+}
+
+static int
+mock_hs_desc_encode_descriptor(const hs_descriptor_t *desc,
+ const ed25519_keypair_t *signing_kp,
+ char **encoded_out)
+{
+ (void)desc;
+ (void)signing_kp;
+
+ tor_asprintf(encoded_out, "lulu");
+ return 0;
+}
+
+static or_state_t dummy_state;
+
+/* Mock function to get fake or state (used for rev counters) */
+static or_state_t *
+get_or_state_replacement(void)
+{
+ return &dummy_state;
+}
+
+static int
+mock_router_have_minimum_dir_info(void)
+{
+ return 1;
+}
+
+/** Test that we correctly detect when the HSDir hash ring changes so that we
+ * reupload our descriptor. */
+static void
+test_desc_reupload_logic(void *arg)
+{
+ networkstatus_t *ns = NULL;
+
+ (void) arg;
+
+ hs_init();
+
+ MOCK(router_have_minimum_dir_info,
+ mock_router_have_minimum_dir_info);
+ MOCK(get_or_state,
+ get_or_state_replacement);
+ MOCK(networkstatus_get_latest_consensus,
+ mock_networkstatus_get_latest_consensus);
+ MOCK(directory_initiate_request,
+ mock_directory_initiate_request);
+ MOCK(hs_desc_encode_descriptor,
+ mock_hs_desc_encode_descriptor);
+
+ ns = networkstatus_get_latest_consensus();
+
+ /** Test logic:
+ * 1) Upload descriptor to HSDirs
+ * CHECK that previous_hsdirs list was populated.
+ * 2) Then call router_dir_info_changed() without an HSDir set change.
+ * CHECK that no reuplod occurs.
+ * 3) Now change the HSDir set, and call dir_info_changed() again.
+ * CHECK that reupload occurs.
+ * 4) Finally call service_desc_schedule_upload().
+ * CHECK that previous_hsdirs list was cleared.
+ **/
+
+ /* Let's start by building our descriptor and service */
+ hs_service_descriptor_t *desc = service_descriptor_new();
+ hs_service_t *service = NULL;
+ /* hex-encoded ed25519 pubkey used in hs_build_address.py */
+ char pubkey_hex[] =
+ "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a";
+ char onion_addr[HS_SERVICE_ADDR_LEN_BASE32 + 1];
+ ed25519_public_key_t pubkey;
+ base16_decode((char*)pubkey.pubkey, sizeof(pubkey.pubkey),
+ pubkey_hex, strlen(pubkey_hex));
+ hs_build_address(&pubkey, HS_VERSION_THREE, onion_addr);
+ service = tor_malloc_zero(sizeof(hs_service_t));
+ memcpy(service->onion_address, onion_addr, sizeof(service->onion_address));
+ ed25519_secret_key_generate(&service->keys.identity_sk, 0);
+ ed25519_public_key_generate(&service->keys.identity_pk,
+ &service->keys.identity_sk);
+ service->desc_current = desc;
+ /* Also add service to service map */
+ hs_service_ht *service_map = get_hs_service_map();
+ tt_assert(service_map);
+ tt_int_op(hs_service_get_num_services(), OP_EQ, 0);
+ register_service(service_map, service);
+ tt_int_op(hs_service_get_num_services(), OP_EQ, 1);
+
+ /* Now let's create our hash ring: */
+ {
+ helper_add_hsdir_to_networkstatus(ns, 1, "dingus", 1);
+ helper_add_hsdir_to_networkstatus(ns, 2, "clive", 1);
+ helper_add_hsdir_to_networkstatus(ns, 3, "aaron", 1);
+ helper_add_hsdir_to_networkstatus(ns, 4, "lizzie", 1);
+ helper_add_hsdir_to_networkstatus(ns, 5, "daewon", 1);
+ helper_add_hsdir_to_networkstatus(ns, 6, "clarke", 1);
+ }
+
+ /* Now let's upload our desc to all hsdirs */
+ upload_descriptor_to_all(service, desc);
+ /* Check that previous hsdirs were populated */
+ tt_int_op(smartlist_len(desc->previous_hsdirs), OP_EQ, 6);
+
+ /* Poison next upload time so that we can see if it was changed by
+ * router_dir_info_changed(). No changes in hash ring so far, so the upload
+ * time should stay as is. */
+ desc->next_upload_time = 42;
+ router_dir_info_changed();
+ tt_int_op(desc->next_upload_time, OP_EQ, 42);
+
+ /* Now change the HSDir hash ring by swapping nora for aaron.
+ * Start by clearing the hash ring */
+ {
+ SMARTLIST_FOREACH(ns->routerstatus_list,
+ routerstatus_t *, rs, routerstatus_free(rs));
+ smartlist_clear(ns->routerstatus_list);
+ cleanup_nodelist();
+ routerlist_free_all();
+ }
+
+ { /* Now add back all the nodes */
+ helper_add_hsdir_to_networkstatus(ns, 1, "dingus", 1);
+ helper_add_hsdir_to_networkstatus(ns, 2, "clive", 1);
+ helper_add_hsdir_to_networkstatus(ns, 4, "lizzie", 1);
+ helper_add_hsdir_to_networkstatus(ns, 5, "daewon", 1);
+ helper_add_hsdir_to_networkstatus(ns, 6, "clarke", 1);
+ helper_add_hsdir_to_networkstatus(ns, 7, "nora", 1);
+ }
+
+ /* Now call service_desc_hsdirs_changed() and see that it detected the hash
+ ring change */
+ time_t now = approx_time();
+ tt_assert(now);
+ tt_int_op(service_desc_hsdirs_changed(service, desc), OP_EQ, 1);
+ tt_int_op(smartlist_len(desc->previous_hsdirs), OP_EQ, 6);
+
+ /* Now order another upload and see that we keep having 6 prev hsdirs */
+ upload_descriptor_to_all(service, desc);
+ /* Check that previous hsdirs were populated */
+ tt_int_op(smartlist_len(desc->previous_hsdirs), OP_EQ, 6);
+
+ /* Now restore the HSDir hash ring to its original state by swapping back
+ aaron for nora */
+ /* First clear up the hash ring */
+ {
+ SMARTLIST_FOREACH(ns->routerstatus_list,
+ routerstatus_t *, rs, routerstatus_free(rs));
+ smartlist_clear(ns->routerstatus_list);
+ cleanup_nodelist();
+ routerlist_free_all();
+ }
+
+ { /* Now populate the hash ring again */
+ helper_add_hsdir_to_networkstatus(ns, 1, "dingus", 1);
+ helper_add_hsdir_to_networkstatus(ns, 2, "clive", 1);
+ helper_add_hsdir_to_networkstatus(ns, 3, "aaron", 1);
+ helper_add_hsdir_to_networkstatus(ns, 4, "lizzie", 1);
+ helper_add_hsdir_to_networkstatus(ns, 5, "daewon", 1);
+ helper_add_hsdir_to_networkstatus(ns, 6, "clarke", 1);
+ }
+
+ /* Check that our algorithm catches this change of hsdirs */
+ tt_int_op(service_desc_hsdirs_changed(service, desc), OP_EQ, 1);
+
+ /* Now pretend that the descriptor changed, and order a reupload to all
+ HSDirs. Make sure that the set of previous HSDirs was cleared. */
+ service_desc_schedule_upload(desc, now, 1);
+ tt_int_op(smartlist_len(desc->previous_hsdirs), OP_EQ, 0);
+
+ /* Now reupload again: see that the prev hsdir set got populated again. */
+ upload_descriptor_to_all(service, desc);
+ tt_int_op(smartlist_len(desc->previous_hsdirs), OP_EQ, 6);
+
+ done:
+ SMARTLIST_FOREACH(ns->routerstatus_list,
+ routerstatus_t *, rs, routerstatus_free(rs));
+ smartlist_clear(ns->routerstatus_list);
+ networkstatus_vote_free(ns);
+ cleanup_nodelist();
+ hs_free_all();
+}
+
+/** Test disaster SRV computation and caching */
+static void
+test_disaster_srv(void *arg)
+{
+ uint8_t *cached_disaster_srv_one = NULL;
+ uint8_t *cached_disaster_srv_two = NULL;
+ uint8_t srv_one[DIGEST256_LEN] = {0};
+ uint8_t srv_two[DIGEST256_LEN] = {0};
+ uint8_t srv_three[DIGEST256_LEN] = {0};
+ uint8_t srv_four[DIGEST256_LEN] = {0};
+ uint8_t srv_five[DIGEST256_LEN] = {0};
+
+ (void) arg;
+
+ /* Get the cached SRVs: we gonna use them later for verification */
+ cached_disaster_srv_one = get_first_cached_disaster_srv();
+ cached_disaster_srv_two = get_second_cached_disaster_srv();
+
+ /* Compute some srvs */
+ get_disaster_srv(1, srv_one);
+ get_disaster_srv(2, srv_two);
+
+ /* Check that the cached ones where updated */
+ tt_mem_op(cached_disaster_srv_one, OP_EQ, srv_one, DIGEST256_LEN);
+ tt_mem_op(cached_disaster_srv_two, OP_EQ, srv_two, DIGEST256_LEN);
+
+ /* Ask for an SRV that has already been computed */
+ get_disaster_srv(2, srv_two);
+ /* and check that the cache entries have not changed */
+ tt_mem_op(cached_disaster_srv_one, OP_EQ, srv_one, DIGEST256_LEN);
+ tt_mem_op(cached_disaster_srv_two, OP_EQ, srv_two, DIGEST256_LEN);
+
+ /* Ask for a new SRV */
+ get_disaster_srv(3, srv_three);
+ tt_mem_op(cached_disaster_srv_one, OP_EQ, srv_three, DIGEST256_LEN);
+ tt_mem_op(cached_disaster_srv_two, OP_EQ, srv_two, DIGEST256_LEN);
+
+ /* Ask for another SRV: none of the original SRVs should now be cached */
+ get_disaster_srv(4, srv_four);
+ tt_mem_op(cached_disaster_srv_one, OP_EQ, srv_three, DIGEST256_LEN);
+ tt_mem_op(cached_disaster_srv_two, OP_EQ, srv_four, DIGEST256_LEN);
+
+ /* Ask for yet another SRV */
+ get_disaster_srv(5, srv_five);
+ tt_mem_op(cached_disaster_srv_one, OP_EQ, srv_five, DIGEST256_LEN);
+ tt_mem_op(cached_disaster_srv_two, OP_EQ, srv_four, DIGEST256_LEN);
+
+ done:
+ ;
+}
+
+/** Test our HS descriptor request tracker by making various requests and
+ * checking whether they get tracked properly. */
+static void
+test_hid_serv_request_tracker(void *arg)
+{
+ (void) arg;
+ time_t retval;
+ routerstatus_t *hsdir = NULL, *hsdir2 = NULL, *hsdir3 = NULL;
+ time_t now = approx_time();
+
+ const char *req_key_str_first =
+ "vd4zb6zesaubtrjvdqcr2w7x7lhw2up4Xnw4526ThUNbL5o1go+EdUuEqlKxHkNbnK41pRzizzs";
+ const char *req_key_str_second =
+ "g53o7iavcd62oihswhr24u6czmqws5kpXnw4526ThUNbL5o1go+EdUuEqlKxHkNbnK41pRzizzs";
+ const char *req_key_str_small = "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ";
+
+ /*************************** basic test *******************************/
+
+ /* Get request tracker and make sure it's empty */
+ strmap_t *request_tracker = get_last_hid_serv_requests();
+ tt_int_op(strmap_size(request_tracker),OP_EQ, 0);
+
+ /* Let's register a hid serv request */
+ hsdir = tor_malloc_zero(sizeof(routerstatus_t));
+ memset(hsdir->identity_digest, 'Z', DIGEST_LEN);
+ retval = hs_lookup_last_hid_serv_request(hsdir, req_key_str_first,
+ now, 1);
+ tt_int_op(retval, OP_EQ, now);
+ tt_int_op(strmap_size(request_tracker),OP_EQ, 1);
+
+ /* Let's lookup a non-existent hidserv request */
+ retval = hs_lookup_last_hid_serv_request(hsdir, req_key_str_second,
+ now+1, 0);
+ tt_int_op(retval, OP_EQ, 0);
+ tt_int_op(strmap_size(request_tracker),OP_EQ, 1);
+
+ /* Let's lookup a real hidserv request */
+ retval = hs_lookup_last_hid_serv_request(hsdir, req_key_str_first,
+ now+2, 0);
+ tt_int_op(retval, OP_EQ, now); /* we got it */
+ tt_int_op(strmap_size(request_tracker),OP_EQ, 1);
+
+ /**********************************************************************/
+
+ /* Let's add another request for the same HS but on a different HSDir. */
+ hsdir2 = tor_malloc_zero(sizeof(routerstatus_t));
+ memset(hsdir2->identity_digest, 2, DIGEST_LEN);
+ retval = hs_lookup_last_hid_serv_request(hsdir2, req_key_str_first,
+ now+3, 1);
+ tt_int_op(retval, OP_EQ, now+3);
+ tt_int_op(strmap_size(request_tracker),OP_EQ, 2);
+
+ /* Check that we can clean the first request based on time */
+ hs_clean_last_hid_serv_requests(now+3+REND_HID_SERV_DIR_REQUERY_PERIOD);
+ tt_int_op(strmap_size(request_tracker),OP_EQ, 1);
+ /* Check that it doesn't exist anymore */
+ retval = hs_lookup_last_hid_serv_request(hsdir, req_key_str_first,
+ now+2, 0);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /* Now let's add a smaller req key str */
+ hsdir3 = tor_malloc_zero(sizeof(routerstatus_t));
+ memset(hsdir3->identity_digest, 3, DIGEST_LEN);
+ retval = hs_lookup_last_hid_serv_request(hsdir3, req_key_str_small,
+ now+4, 1);
+ tt_int_op(retval, OP_EQ, now+4);
+ tt_int_op(strmap_size(request_tracker),OP_EQ, 2);
+
+ /*************************** deleting entries **************************/
+
+ /* Add another request with very short key */
+ retval = hs_lookup_last_hid_serv_request(hsdir, "l", now, 1);
+ tt_int_op(retval, OP_EQ, now);
+ tt_int_op(strmap_size(request_tracker),OP_EQ, 3);
+
+ /* Try deleting entries with a dummy key. Check that our previous requests
+ * are still there */
+ tor_capture_bugs_(1);
+ hs_purge_hid_serv_from_last_hid_serv_requests("a");
+ tt_int_op(strmap_size(request_tracker),OP_EQ, 3);
+ tor_end_capture_bugs_();
+
+ /* Try another dummy key. Check that requests are still there */
+ {
+ char dummy[2000];
+ memset(dummy, 'Z', 2000);
+ dummy[1999] = '\x00';
+ hs_purge_hid_serv_from_last_hid_serv_requests(dummy);
+ tt_int_op(strmap_size(request_tracker),OP_EQ, 3);
+ }
+
+ /* Another dummy key! */
+ hs_purge_hid_serv_from_last_hid_serv_requests(req_key_str_second);
+ tt_int_op(strmap_size(request_tracker),OP_EQ, 3);
+
+ /* Now actually delete a request! */
+ hs_purge_hid_serv_from_last_hid_serv_requests(req_key_str_first);
+ tt_int_op(strmap_size(request_tracker),OP_EQ, 2);
+
+ /* Purge it all! */
+ hs_purge_last_hid_serv_requests();
+ request_tracker = get_last_hid_serv_requests();
+ tt_int_op(strmap_size(request_tracker),OP_EQ, 0);
+
+ done:
+ tor_free(hsdir);
+ tor_free(hsdir2);
+ tor_free(hsdir3);
+}
+
+static void
+test_parse_extended_hostname(void *arg)
+{
+ (void) arg;
+
+ char address1[] = "fooaddress.onion";
+ char address2[] = "aaaaaaaaaaaaaaaa.onion";
+ char address3[] = "fooaddress.exit";
+ char address4[] = "www.torproject.org";
+ char address5[] = "foo.abcdefghijklmnop.onion";
+ char address6[] = "foo.bar.abcdefghijklmnop.onion";
+ char address7[] = ".abcdefghijklmnop.onion";
+ char address8[] =
+ "www.25njqamcweflpvkl73j4szahhihoc4xt3ktcgjnpaingr5yhkenl5sid.onion";
+
+ tt_assert(BAD_HOSTNAME == parse_extended_hostname(address1));
+ tt_assert(ONION_V2_HOSTNAME == parse_extended_hostname(address2));
+ tt_str_op(address2,OP_EQ, "aaaaaaaaaaaaaaaa");
+ tt_assert(EXIT_HOSTNAME == parse_extended_hostname(address3));
+ tt_assert(NORMAL_HOSTNAME == parse_extended_hostname(address4));
+ tt_assert(ONION_V2_HOSTNAME == parse_extended_hostname(address5));
+ tt_str_op(address5,OP_EQ, "abcdefghijklmnop");
+ tt_assert(ONION_V2_HOSTNAME == parse_extended_hostname(address6));
+ tt_str_op(address6,OP_EQ, "abcdefghijklmnop");
+ tt_assert(BAD_HOSTNAME == parse_extended_hostname(address7));
+ tt_assert(ONION_V3_HOSTNAME == parse_extended_hostname(address8));
+ tt_str_op(address8, OP_EQ,
+ "25njqamcweflpvkl73j4szahhihoc4xt3ktcgjnpaingr5yhkenl5sid");
+
+ done: ;
+}
+
+static void
+test_time_between_tp_and_srv(void *arg)
+{
+ int ret;
+ networkstatus_t ns;
+ (void) arg;
+
+ /* This function should be returning true where "^" are:
+ *
+ * +------------------------------------------------------------------+
+ * | |
+ * | 00:00 12:00 00:00 12:00 00:00 12:00 |
+ * | SRV#1 TP#1 SRV#2 TP#2 SRV#3 TP#3 |
+ * | |
+ * | $==========|-----------$===========|-----------$===========| |
+ * | ^^^^^^^^^^^^ ^^^^^^^^^^^^ |
+ * | |
+ * +------------------------------------------------------------------+
+ */
+
+ ret = parse_rfc1123_time("Sat, 26 Oct 1985 00:00:00 UTC", &ns.valid_after);
+ tt_int_op(ret, OP_EQ, 0);
+ ret = parse_rfc1123_time("Sat, 26 Oct 1985 01:00:00 UTC", &ns.fresh_until);
+ tt_int_op(ret, OP_EQ, 0);
+ dirvote_recalculate_timing(get_options(), ns.valid_after);
+ ret = hs_in_period_between_tp_and_srv(&ns, 0);
+ tt_int_op(ret, OP_EQ, 0);
+
+ ret = parse_rfc1123_time("Sat, 26 Oct 1985 11:00:00 UTC", &ns.valid_after);
+ tt_int_op(ret, OP_EQ, 0);
+ ret = parse_rfc1123_time("Sat, 26 Oct 1985 12:00:00 UTC", &ns.fresh_until);
+ tt_int_op(ret, OP_EQ, 0);
+ dirvote_recalculate_timing(get_options(), ns.valid_after);
+ ret = hs_in_period_between_tp_and_srv(&ns, 0);
+ tt_int_op(ret, OP_EQ, 0);
+
+ ret = parse_rfc1123_time("Sat, 26 Oct 1985 12:00:00 UTC", &ns.valid_after);
+ tt_int_op(ret, OP_EQ, 0);
+ ret = parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC", &ns.fresh_until);
+ tt_int_op(ret, OP_EQ, 0);
+ dirvote_recalculate_timing(get_options(), ns.valid_after);
+ ret = hs_in_period_between_tp_and_srv(&ns, 0);
+ tt_int_op(ret, OP_EQ, 1);
+
+ ret = parse_rfc1123_time("Sat, 26 Oct 1985 23:00:00 UTC", &ns.valid_after);
+ tt_int_op(ret, OP_EQ, 0);
+ ret = parse_rfc1123_time("Sat, 27 Oct 1985 00:00:00 UTC", &ns.fresh_until);
+ tt_int_op(ret, OP_EQ, 0);
+ dirvote_recalculate_timing(get_options(), ns.valid_after);
+ ret = hs_in_period_between_tp_and_srv(&ns, 0);
+ tt_int_op(ret, OP_EQ, 1);
+
+ ret = parse_rfc1123_time("Sat, 27 Oct 1985 00:00:00 UTC", &ns.valid_after);
+ tt_int_op(ret, OP_EQ, 0);
+ ret = parse_rfc1123_time("Sat, 27 Oct 1985 01:00:00 UTC", &ns.fresh_until);
+ tt_int_op(ret, OP_EQ, 0);
+ dirvote_recalculate_timing(get_options(), ns.valid_after);
+ ret = hs_in_period_between_tp_and_srv(&ns, 0);
+ tt_int_op(ret, OP_EQ, 0);
+
+ done:
+ ;
+}
+
+/************ Reachability Test (it is huge) ****************/
+
+/* Simulate different consensus for client and service. Used by the
+ * reachability test. The SRV and responsible HSDir list are used by all
+ * reachability tests so make them common to simplify setup and teardown. */
+static networkstatus_t *mock_service_ns = NULL;
+static networkstatus_t *mock_client_ns = NULL;
+static sr_srv_t current_srv, previous_srv;
+static smartlist_t *service_responsible_hsdirs = NULL;
+static smartlist_t *client_responsible_hsdirs = NULL;
+
+static networkstatus_t *
+mock_networkstatus_get_live_consensus_service(time_t now)
+{
+ (void) now;
+
+ if (mock_service_ns) {
+ return mock_service_ns;
+ }
+
+ mock_service_ns = tor_malloc_zero(sizeof(networkstatus_t));
+ mock_service_ns->routerstatus_list = smartlist_new();
+ mock_service_ns->type = NS_TYPE_CONSENSUS;
+
+ return mock_service_ns;
+}
+
+static networkstatus_t *
+mock_networkstatus_get_latest_consensus_service(void)
+{
+ return mock_networkstatus_get_live_consensus_service(0);
+}
+
+static networkstatus_t *
+mock_networkstatus_get_live_consensus_client(time_t now)
+{
+ (void) now;
+
+ if (mock_client_ns) {
+ return mock_client_ns;
+ }
+
+ mock_client_ns = tor_malloc_zero(sizeof(networkstatus_t));
+ mock_client_ns->routerstatus_list = smartlist_new();
+ mock_client_ns->type = NS_TYPE_CONSENSUS;
+
+ return mock_client_ns;
+}
+
+static networkstatus_t *
+mock_networkstatus_get_latest_consensus_client(void)
+{
+ return mock_networkstatus_get_live_consensus_client(0);
+}
+
+/* Mock function because we are not trying to test the close circuit that does
+ * an awful lot of checks on the circuit object. */
+static void
+mock_circuit_mark_for_close(circuit_t *circ, int reason, int line,
+ const char *file)
+{
+ (void) circ;
+ (void) reason;
+ (void) line;
+ (void) file;
+ return;
+}
+
+/* Initialize a big HSDir V3 hash ring. */
+static void
+helper_initialize_big_hash_ring(networkstatus_t *ns)
+{
+ int ret;
+
+ /* Generate 250 hsdirs! :) */
+ for (int counter = 1 ; counter < 251 ; counter++) {
+ /* Let's generate random nickname for each hsdir... */
+ char nickname_binary[8];
+ char nickname_str[13] = {0};
+ crypto_rand(nickname_binary, sizeof(nickname_binary));
+ ret = base64_encode(nickname_str, sizeof(nickname_str),
+ nickname_binary, sizeof(nickname_binary), 0);
+ tt_int_op(ret, OP_EQ, 12);
+ helper_add_hsdir_to_networkstatus(ns, counter, nickname_str, 1);
+ }
+
+ /* Make sure we have 200 hsdirs in our list */
+ tt_int_op(smartlist_len(ns->routerstatus_list), OP_EQ, 250);
+
+ done:
+ ;
+}
+
+/** Initialize service and publish its descriptor as needed. Return the newly
+ * allocated service object to the caller. */
+static hs_service_t *
+helper_init_service(time_t now)
+{
+ int retval;
+ hs_service_t *service = hs_service_new(get_options());
+ tt_assert(service);
+ service->config.version = HS_VERSION_THREE;
+ ed25519_secret_key_generate(&service->keys.identity_sk, 0);
+ ed25519_public_key_generate(&service->keys.identity_pk,
+ &service->keys.identity_sk);
+ /* Register service to global map. */
+ retval = register_service(get_hs_service_map(), service);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /* Initialize service descriptor */
+ build_all_descriptors(now);
+ tt_assert(service->desc_current);
+ tt_assert(service->desc_next);
+
+ done:
+ return service;
+}
+
+/* Helper function to set the RFC 1123 time string into t. */
+static void
+set_consensus_times(const char *timestr, time_t *t)
+{
+ tt_assert(timestr);
+ tt_assert(t);
+
+ int ret = parse_rfc1123_time(timestr, t);
+ tt_int_op(ret, OP_EQ, 0);
+
+ done:
+ return;
+}
+
+/* Helper function to cleanup the mock consensus (client and service) */
+static void
+cleanup_mock_ns(void)
+{
+ if (mock_service_ns) {
+ SMARTLIST_FOREACH(mock_service_ns->routerstatus_list,
+ routerstatus_t *, rs, routerstatus_free(rs));
+ smartlist_clear(mock_service_ns->routerstatus_list);
+ mock_service_ns->sr_info.current_srv = NULL;
+ mock_service_ns->sr_info.previous_srv = NULL;
+ networkstatus_vote_free(mock_service_ns);
+ mock_service_ns = NULL;
+ }
+
+ if (mock_client_ns) {
+ SMARTLIST_FOREACH(mock_client_ns->routerstatus_list,
+ routerstatus_t *, rs, routerstatus_free(rs));
+ smartlist_clear(mock_client_ns->routerstatus_list);
+ mock_client_ns->sr_info.current_srv = NULL;
+ mock_client_ns->sr_info.previous_srv = NULL;
+ networkstatus_vote_free(mock_client_ns);
+ mock_client_ns = NULL;
+ }
+}
+
+/* Helper function to setup a reachability test. Once called, the
+ * cleanup_reachability_test MUST be called at the end. */
+static void
+setup_reachability_test(void)
+{
+ MOCK(circuit_mark_for_close_, mock_circuit_mark_for_close);
+ MOCK(get_or_state, get_or_state_replacement);
+
+ hs_init();
+
+ /* Baseline to start with. */
+ memset(&current_srv, 0, sizeof(current_srv));
+ memset(&previous_srv, 1, sizeof(previous_srv));
+
+ /* Initialize the consensuses. */
+ mock_networkstatus_get_latest_consensus_service();
+ mock_networkstatus_get_latest_consensus_client();
+
+ service_responsible_hsdirs = smartlist_new();
+ client_responsible_hsdirs = smartlist_new();
+}
+
+/* Helper function to cleanup a reachability test initial setup. */
+static void
+cleanup_reachability_test(void)
+{
+ smartlist_free(service_responsible_hsdirs);
+ service_responsible_hsdirs = NULL;
+ smartlist_free(client_responsible_hsdirs);
+ client_responsible_hsdirs = NULL;
+ hs_free_all();
+ cleanup_mock_ns();
+ UNMOCK(get_or_state);
+ UNMOCK(circuit_mark_for_close_);
+}
+
+/* A reachability test always check if the resulting service and client
+ * responsible HSDir for the given parameters are equal.
+ *
+ * Return true iff the same exact nodes are in both list. */
+static int
+are_responsible_hsdirs_equal(void)
+{
+ int count = 0;
+ tt_int_op(smartlist_len(client_responsible_hsdirs), OP_EQ, 6);
+ tt_int_op(smartlist_len(service_responsible_hsdirs), OP_EQ, 8);
+
+ SMARTLIST_FOREACH_BEGIN(client_responsible_hsdirs,
+ const routerstatus_t *, c_rs) {
+ SMARTLIST_FOREACH_BEGIN(service_responsible_hsdirs,
+ const routerstatus_t *, s_rs) {
+ if (tor_memeq(c_rs->identity_digest, s_rs->identity_digest,
+ DIGEST_LEN)) {
+ count++;
+ break;
+ }
+ } SMARTLIST_FOREACH_END(s_rs);
+ } SMARTLIST_FOREACH_END(c_rs);
+
+ done:
+ return (count == 6);
+}
+
+/* Tor doesn't use such a function to get the previous HSDir, it is only used
+ * in node_set_hsdir_index(). We need it here so we can test the reachability
+ * scenario 6 that requires the previous time period to compute the list of
+ * responsible HSDir because of the client state timing. */
+static uint64_t
+get_previous_time_period(time_t now)
+{
+ return hs_get_time_period_num(now) - 1;
+}
+
+/* Configuration of a reachability test scenario. */
+typedef struct reachability_cfg_t {
+ /* Consensus timings to be set. They have to be compliant with
+ * RFC 1123 time format. */
+ const char *service_valid_after;
+ const char *service_valid_until;
+ const char *client_valid_after;
+ const char *client_valid_until;
+
+ /* SRVs that the service and client should use. */
+ sr_srv_t *service_current_srv;
+ sr_srv_t *service_previous_srv;
+ sr_srv_t *client_current_srv;
+ sr_srv_t *client_previous_srv;
+
+ /* A time period function for the service to use for this scenario. For a
+ * successful reachability test, the client always use the current time
+ * period thus why no client function. */
+ uint64_t (*service_time_period_fn)(time_t);
+
+ /* Is the client and service expected to be in a new time period. After
+ * setting the consensus time, the reachability test checks
+ * hs_in_period_between_tp_and_srv() and test the returned value against
+ * this. */
+ unsigned int service_in_new_tp;
+ unsigned int client_in_new_tp;
+
+ /* Some scenario requires a hint that the client, because of its consensus
+ * time, will request the "next" service descriptor so this indicates if it
+ * is the case or not. */
+ unsigned int client_fetch_next_desc;
+} reachability_cfg_t;
+
+/* Some defines to help with semantic while reading a configuration below. */
+#define NOT_IN_NEW_TP 0
+#define IN_NEW_TP 1
+#define DONT_NEED_NEXT_DESC 0
+#define NEED_NEXT_DESC 1
+
+static reachability_cfg_t reachability_scenarios[] = {
+ /* Scenario 1
+ *
+ * +------------------------------------------------------------------+
+ * | |
+ * | 00:00 12:00 00:00 12:00 00:00 12:00 |
+ * | SRV#1 TP#1 SRV#2 TP#2 SRV#3 TP#3 |
+ * | |
+ * | $==========|-----------$===========|-----------$===========| |
+ * | ^ ^ |
+ * | S C |
+ * +------------------------------------------------------------------+
+ *
+ * S: Service, C: Client
+ *
+ * Service consensus valid_after time is set to 13:00 and client to 15:00,
+ * both are after TP#1 thus have access to SRV#1. Service and client should
+ * be using TP#1.
+ */
+
+ { "Sat, 26 Oct 1985 13:00:00 UTC", /* Service valid_after */
+ "Sat, 26 Oct 1985 14:00:00 UTC", /* Service valid_until */
+ "Sat, 26 Oct 1985 15:00:00 UTC", /* Client valid_after */
+ "Sat, 26 Oct 1985 16:00:00 UTC", /* Client valid_until. */
+ &current_srv, NULL, /* Service current and previous SRV */
+ &current_srv, NULL, /* Client current and previous SRV */
+ hs_get_time_period_num, /* Service time period function. */
+ IN_NEW_TP, /* Is service in new TP? */
+ IN_NEW_TP, /* Is client in new TP? */
+ NEED_NEXT_DESC },
+
+ /* Scenario 2
+ *
+ * +------------------------------------------------------------------+
+ * | |
+ * | 00:00 12:00 00:00 12:00 00:00 12:00 |
+ * | SRV#1 TP#1 SRV#2 TP#2 SRV#3 TP#3 |
+ * | |
+ * | $==========|-----------$===========|-----------$===========| |
+ * | ^ ^ |
+ * | S C |
+ * +------------------------------------------------------------------+
+ *
+ * S: Service, C: Client
+ *
+ * Service consensus valid_after time is set to 23:00 and client to 01:00,
+ * which makes the client after the SRV#2 and the service just before. The
+ * service should only be using TP#1. The client should be using TP#1.
+ */
+
+ { "Sat, 26 Oct 1985 23:00:00 UTC", /* Service valid_after */
+ "Sat, 27 Oct 1985 00:00:00 UTC", /* Service valid_until */
+ "Sat, 27 Oct 1985 01:00:00 UTC", /* Client valid_after */
+ "Sat, 27 Oct 1985 02:00:00 UTC", /* Client valid_until. */
+ &previous_srv, NULL, /* Service current and previous SRV */
+ &current_srv, &previous_srv, /* Client current and previous SRV */
+ hs_get_time_period_num, /* Service time period function. */
+ IN_NEW_TP, /* Is service in new TP? */
+ NOT_IN_NEW_TP, /* Is client in new TP? */
+ NEED_NEXT_DESC },
+
+ /* Scenario 3
+ *
+ * +------------------------------------------------------------------+
+ * | |
+ * | 00:00 12:00 00:00 12:00 00:00 12:00 |
+ * | SRV#1 TP#1 SRV#2 TP#2 SRV#3 TP#3 |
+ * | |
+ * | $==========|-----------$===========|----------$===========| |
+ * | ^ ^ |
+ * | S C |
+ * +------------------------------------------------------------------+
+ *
+ * S: Service, C: Client
+ *
+ * Service consensus valid_after time is set to 03:00 and client to 05:00,
+ * which makes both after SRV#2. The service should be using TP#1 as its
+ * current time period. The client should be using TP#1.
+ */
+
+ { "Sat, 27 Oct 1985 03:00:00 UTC", /* Service valid_after */
+ "Sat, 27 Oct 1985 04:00:00 UTC", /* Service valid_until */
+ "Sat, 27 Oct 1985 05:00:00 UTC", /* Client valid_after */
+ "Sat, 27 Oct 1985 06:00:00 UTC", /* Client valid_until. */
+ &current_srv, &previous_srv, /* Service current and previous SRV */
+ &current_srv, &previous_srv, /* Client current and previous SRV */
+ hs_get_time_period_num, /* Service time period function. */
+ NOT_IN_NEW_TP, /* Is service in new TP? */
+ NOT_IN_NEW_TP, /* Is client in new TP? */
+ DONT_NEED_NEXT_DESC },
+
+ /* Scenario 4
+ *
+ * +------------------------------------------------------------------+
+ * | |
+ * | 00:00 12:00 00:00 12:00 00:00 12:00 |
+ * | SRV#1 TP#1 SRV#2 TP#2 SRV#3 TP#3 |
+ * | |
+ * | $==========|-----------$===========|-----------$===========| |
+ * | ^ ^ |
+ * | S C |
+ * +------------------------------------------------------------------+
+ *
+ * S: Service, C: Client
+ *
+ * Service consensus valid_after time is set to 11:00 and client to 13:00,
+ * which makes the service before TP#2 and the client just after. The
+ * service should be using TP#1 as its current time period and TP#2 as the
+ * next. The client should be using TP#2 time period.
+ */
+
+ { "Sat, 27 Oct 1985 11:00:00 UTC", /* Service valid_after */
+ "Sat, 27 Oct 1985 12:00:00 UTC", /* Service valid_until */
+ "Sat, 27 Oct 1985 13:00:00 UTC", /* Client valid_after */
+ "Sat, 27 Oct 1985 14:00:00 UTC", /* Client valid_until. */
+ &current_srv, &previous_srv, /* Service current and previous SRV */
+ &current_srv, &previous_srv, /* Client current and previous SRV */
+ hs_get_next_time_period_num, /* Service time period function. */
+ NOT_IN_NEW_TP, /* Is service in new TP? */
+ IN_NEW_TP, /* Is client in new TP? */
+ NEED_NEXT_DESC },
+
+ /* Scenario 5
+ *
+ * +------------------------------------------------------------------+
+ * | |
+ * | 00:00 12:00 00:00 12:00 00:00 12:00 |
+ * | SRV#1 TP#1 SRV#2 TP#2 SRV#3 TP#3 |
+ * | |
+ * | $==========|-----------$===========|-----------$===========| |
+ * | ^ ^ |
+ * | C S |
+ * +------------------------------------------------------------------+
+ *
+ * S: Service, C: Client
+ *
+ * Service consensus valid_after time is set to 01:00 and client to 23:00,
+ * which makes the service after SRV#2 and the client just before. The
+ * service should be using TP#1 as its current time period and TP#2 as the
+ * next. The client should be using TP#1 time period.
+ */
+
+ { "Sat, 27 Oct 1985 01:00:00 UTC", /* Service valid_after */
+ "Sat, 27 Oct 1985 02:00:00 UTC", /* Service valid_until */
+ "Sat, 26 Oct 1985 23:00:00 UTC", /* Client valid_after */
+ "Sat, 27 Oct 1985 00:00:00 UTC", /* Client valid_until. */
+ &current_srv, &previous_srv, /* Service current and previous SRV */
+ &previous_srv, NULL, /* Client current and previous SRV */
+ hs_get_time_period_num, /* Service time period function. */
+ NOT_IN_NEW_TP, /* Is service in new TP? */
+ IN_NEW_TP, /* Is client in new TP? */
+ DONT_NEED_NEXT_DESC },
+
+ /* Scenario 6
+ *
+ * +------------------------------------------------------------------+
+ * | |
+ * | 00:00 12:00 00:00 12:00 00:00 12:00 |
+ * | SRV#1 TP#1 SRV#2 TP#2 SRV#3 TP#3 |
+ * | |
+ * | $==========|-----------$===========|-----------$===========| |
+ * | ^ ^ |
+ * | C S |
+ * +------------------------------------------------------------------+
+ *
+ * S: Service, C: Client
+ *
+ * Service consensus valid_after time is set to 13:00 and client to 11:00,
+ * which makes the service outside after TP#2 and the client just before.
+ * The service should be using TP#1 as its current time period and TP#2 as
+ * its next. The client should be using TP#1 time period.
+ */
+
+ { "Sat, 27 Oct 1985 13:00:00 UTC", /* Service valid_after */
+ "Sat, 27 Oct 1985 14:00:00 UTC", /* Service valid_until */
+ "Sat, 27 Oct 1985 11:00:00 UTC", /* Client valid_after */
+ "Sat, 27 Oct 1985 12:00:00 UTC", /* Client valid_until. */
+ &current_srv, &previous_srv, /* Service current and previous SRV */
+ &current_srv, &previous_srv, /* Client current and previous SRV */
+ get_previous_time_period, /* Service time period function. */
+ IN_NEW_TP, /* Is service in new TP? */
+ NOT_IN_NEW_TP, /* Is client in new TP? */
+ DONT_NEED_NEXT_DESC },
+
+ /* End marker. */
+ { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0}
+};
+
+/* Run a single reachability scenario. num_scenario is the corresponding
+ * scenario number from the documentation. It is used to log it in case of
+ * failure so we know which scenario fails. */
+static int
+run_reachability_scenario(const reachability_cfg_t *cfg, int num_scenario)
+{
+ int ret = -1;
+ hs_service_t *service;
+ uint64_t service_tp, client_tp;
+ ed25519_public_key_t service_blinded_pk, client_blinded_pk;
+
+ setup_reachability_test();
+
+ tt_assert(cfg);
+
+ /* Set service consensus time. */
+ set_consensus_times(cfg->service_valid_after,
+ &mock_service_ns->valid_after);
+ set_consensus_times(cfg->service_valid_until,
+ &mock_service_ns->valid_until);
+ set_consensus_times(cfg->service_valid_until,
+ &mock_service_ns->fresh_until);
+ dirvote_recalculate_timing(get_options(), mock_service_ns->valid_after);
+ /* Set client consensus time. */
+ set_consensus_times(cfg->client_valid_after,
+ &mock_client_ns->valid_after);
+ set_consensus_times(cfg->client_valid_until,
+ &mock_client_ns->valid_until);
+ set_consensus_times(cfg->client_valid_until,
+ &mock_client_ns->fresh_until);
+ dirvote_recalculate_timing(get_options(), mock_client_ns->valid_after);
+
+ /* New time period checks for this scenario. */
+ tt_int_op(hs_in_period_between_tp_and_srv(mock_service_ns, 0), OP_EQ,
+ cfg->service_in_new_tp);
+ tt_int_op(hs_in_period_between_tp_and_srv(mock_client_ns, 0), OP_EQ,
+ cfg->client_in_new_tp);
+
+ /* Set the SRVs for this scenario. */
+ mock_client_ns->sr_info.current_srv = cfg->client_current_srv;
+ mock_client_ns->sr_info.previous_srv = cfg->client_previous_srv;
+ mock_service_ns->sr_info.current_srv = cfg->service_current_srv;
+ mock_service_ns->sr_info.previous_srv = cfg->service_previous_srv;
+
+ /* Initialize a service to get keys. */
+ service = helper_init_service(time(NULL));
+
+ /*
+ * === Client setup ===
+ */
+
+ MOCK(networkstatus_get_live_consensus,
+ mock_networkstatus_get_live_consensus_client);
+ MOCK(networkstatus_get_latest_consensus,
+ mock_networkstatus_get_latest_consensus_client);
+
+ /* Make networkstatus_is_live() happy. */
+ update_approx_time(mock_client_ns->valid_after);
+ /* Initialize a big hashring for this consensus with the hsdir index set. */
+ helper_initialize_big_hash_ring(mock_client_ns);
+
+ /* Client ONLY use the current time period. This is the whole point of these
+ * reachability test that is to make sure the client can always reach the
+ * service using only its current time period. */
+ client_tp = hs_get_time_period_num(0);
+
+ hs_build_blinded_pubkey(&service->keys.identity_pk, NULL, 0,
+ client_tp, &client_blinded_pk);
+ hs_get_responsible_hsdirs(&client_blinded_pk, client_tp, 0, 1,
+ client_responsible_hsdirs);
+ /* Cleanup the nodelist so we can let the service computes its own set of
+ * node with its own hashring. */
+ cleanup_nodelist();
+ tt_int_op(smartlist_len(client_responsible_hsdirs), OP_EQ, 6);
+
+ UNMOCK(networkstatus_get_latest_consensus);
+ UNMOCK(networkstatus_get_live_consensus);
+
+ /*
+ * === Service setup ===
+ */
+
+ MOCK(networkstatus_get_live_consensus,
+ mock_networkstatus_get_live_consensus_service);
+ MOCK(networkstatus_get_latest_consensus,
+ mock_networkstatus_get_latest_consensus_service);
+
+ /* Make networkstatus_is_live() happy. */
+ update_approx_time(mock_service_ns->valid_after);
+ /* Initialize a big hashring for this consensus with the hsdir index set. */
+ helper_initialize_big_hash_ring(mock_service_ns);
+
+ service_tp = cfg->service_time_period_fn(0);
+
+ hs_build_blinded_pubkey(&service->keys.identity_pk, NULL, 0,
+ service_tp, &service_blinded_pk);
+
+ /* A service builds two lists of responsible HSDir, for the current and the
+ * next descriptor. Depending on the scenario, the client timing indicate if
+ * it is fetching the current or the next descriptor so we use the
+ * "client_fetch_next_desc" to know which one the client is trying to get to
+ * confirm that the service computes the same hashring for the same blinded
+ * key and service time period function. */
+ hs_get_responsible_hsdirs(&service_blinded_pk, service_tp,
+ cfg->client_fetch_next_desc, 0,
+ service_responsible_hsdirs);
+ cleanup_nodelist();
+ tt_int_op(smartlist_len(service_responsible_hsdirs), OP_EQ, 8);
+
+ UNMOCK(networkstatus_get_latest_consensus);
+ UNMOCK(networkstatus_get_live_consensus);
+
+ /* Some testing of the values we just got from the client and service. */
+ tt_mem_op(&client_blinded_pk, OP_EQ, &service_blinded_pk,
+ ED25519_PUBKEY_LEN);
+ tt_int_op(are_responsible_hsdirs_equal(), OP_EQ, 1);
+
+ /* Everything went well. */
+ ret = 0;
+
+ done:
+ cleanup_reachability_test();
+ if (ret == -1) {
+ /* Do this so we can know which scenario failed. */
+ char msg[32];
+ tor_snprintf(msg, sizeof(msg), "Scenario %d failed", num_scenario);
+ tt_fail_msg(msg);
+ }
+ return ret;
+}
+
+static void
+test_reachability(void *arg)
+{
+ (void) arg;
+
+ /* NOTE: An important axiom to understand here is that SRV#N must only be
+ * used with TP#N value. For example, SRV#2 with TP#1 should NEVER be used
+ * together. The HSDir index computation is based on this axiom.*/
+
+ for (int i = 0; reachability_scenarios[i].service_valid_after; ++i) {
+ int ret = run_reachability_scenario(&reachability_scenarios[i], i + 1);
+ if (ret < 0) {
+ return;
+ }
+ }
+}
+
+/** Pick an HSDir for service with <b>onion_identity_pk</b> as a client. Put
+ * its identity digest in <b>hsdir_digest_out</b>. */
+static void
+helper_client_pick_hsdir(const ed25519_public_key_t *onion_identity_pk,
+ char *hsdir_digest_out)
+{
+ tt_assert(onion_identity_pk);
+
+ routerstatus_t *client_hsdir = pick_hsdir_v3(onion_identity_pk);
+ tt_assert(client_hsdir);
+ digest_to_base64(hsdir_digest_out, client_hsdir->identity_digest);
+
+ done:
+ ;
+}
+
+static void
+test_hs_indexes(void *arg)
+{
+ int ret;
+ uint64_t period_num = 42;
+ ed25519_public_key_t pubkey;
+
+ (void) arg;
+
+ /* Build the hs_index */
+ {
+ uint8_t hs_index[DIGEST256_LEN];
+ const char *b32_test_vector =
+ "37e5cbbd56a22823714f18f1623ece5983a0d64c78495a8cfab854245e5f9a8a";
+ char test_vector[DIGEST256_LEN];
+ ret = base16_decode(test_vector, sizeof(test_vector), b32_test_vector,
+ strlen(b32_test_vector));
+ tt_int_op(ret, OP_EQ, sizeof(test_vector));
+ /* Our test vector uses a public key set to 32 bytes of \x42. */
+ memset(&pubkey, '\x42', sizeof(pubkey));
+ hs_build_hs_index(1, &pubkey, period_num, hs_index);
+ tt_mem_op(hs_index, OP_EQ, test_vector, sizeof(hs_index));
+ }
+
+ /* Build the hsdir_index */
+ {
+ uint8_t srv[DIGEST256_LEN];
+ uint8_t hsdir_index[DIGEST256_LEN];
+ const char *b32_test_vector =
+ "db475361014a09965e7e5e4d4a25b8f8d4b8f16cb1d8a7e95eed50249cc1a2d5";
+ char test_vector[DIGEST256_LEN];
+ ret = base16_decode(test_vector, sizeof(test_vector), b32_test_vector,
+ strlen(b32_test_vector));
+ tt_int_op(ret, OP_EQ, sizeof(test_vector));
+ /* Our test vector uses a public key set to 32 bytes of \x42. */
+ memset(&pubkey, '\x42', sizeof(pubkey));
+ memset(srv, '\x43', sizeof(srv));
+ hs_build_hsdir_index(&pubkey, srv, period_num, hsdir_index);
+ tt_mem_op(hsdir_index, OP_EQ, test_vector, sizeof(hsdir_index));
+ }
+
+ done:
+ ;
+}
+
+#define EARLY_IN_SRV_TO_TP 0
+#define LATE_IN_SRV_TO_TP 1
+#define EARLY_IN_TP_TO_SRV 2
+#define LATE_IN_TP_TO_SRV 3
+
+/** Set the consensus and system time based on <b>position</b>. See the
+ * following diagram for details:
+ *
+ * +------------------------------------------------------------------+
+ * | |
+ * | 00:00 12:00 00:00 12:00 00:00 12:00 |
+ * | SRV#1 TP#1 SRV#2 TP#2 SRV#3 TP#3 |
+ * | |
+ * | $==========|-----------$===========|----------$===========| |
+ * | |
+ * | |
+ * +------------------------------------------------------------------+
+ */
+static time_t
+helper_set_consensus_and_system_time(networkstatus_t *ns, int position)
+{
+ time_t real_time = 0;
+
+ /* The period between SRV#N and TP#N is from 00:00 to 12:00 UTC. Consensus
+ * valid_after is what matters here, the rest is just to specify the voting
+ * period correctly. */
+ if (position == LATE_IN_SRV_TO_TP) {
+ parse_rfc1123_time("Wed, 13 Apr 2016 11:00:00 UTC", &ns->valid_after);
+ parse_rfc1123_time("Wed, 13 Apr 2016 12:00:00 UTC", &ns->fresh_until);
+ parse_rfc1123_time("Wed, 13 Apr 2016 14:00:00 UTC", &ns->valid_until);
+ } else if (position == EARLY_IN_TP_TO_SRV) {
+ parse_rfc1123_time("Wed, 13 Apr 2016 13:00:00 UTC", &ns->valid_after);
+ parse_rfc1123_time("Wed, 13 Apr 2016 14:00:00 UTC", &ns->fresh_until);
+ parse_rfc1123_time("Wed, 13 Apr 2016 16:00:00 UTC", &ns->valid_until);
+ } else if (position == LATE_IN_TP_TO_SRV) {
+ parse_rfc1123_time("Wed, 13 Apr 2016 23:00:00 UTC", &ns->valid_after);
+ parse_rfc1123_time("Wed, 14 Apr 2016 00:00:00 UTC", &ns->fresh_until);
+ parse_rfc1123_time("Wed, 14 Apr 2016 02:00:00 UTC", &ns->valid_until);
+ } else if (position == EARLY_IN_SRV_TO_TP) {
+ parse_rfc1123_time("Wed, 14 Apr 2016 01:00:00 UTC", &ns->valid_after);
+ parse_rfc1123_time("Wed, 14 Apr 2016 02:00:00 UTC", &ns->fresh_until);
+ parse_rfc1123_time("Wed, 14 Apr 2016 04:00:00 UTC", &ns->valid_until);
+ } else {
+ tt_assert(0);
+ }
+ dirvote_recalculate_timing(get_options(), ns->valid_after);
+
+ /* Set system time: pretend to be just 2 minutes before consensus expiry */
+ real_time = ns->valid_until - 120;
+ update_approx_time(real_time);
+
+ done:
+ return real_time;
+}
+
+/** Helper function that carries out the actual test for
+ * test_client_service_sync() */
+static void
+helper_test_hsdir_sync(networkstatus_t *ns,
+ int service_position, int client_position,
+ int client_fetches_next_desc)
+{
+ hs_service_descriptor_t *desc;
+ int retval;
+
+ /** Test logic:
+ * 1) Initialize service time: consensus and system time.
+ * 1.1) Initialize service hash ring
+ * 2) Initialize service and publish descriptors.
+ * 3) Initialize client time: consensus and system time.
+ * 3.1) Initialize client hash ring
+ * 4) Try to fetch descriptor as client, and CHECK that the HSDir picked by
+ * the client was also picked by service.
+ */
+
+ /* 1) Initialize service time: consensus and real time */
+ time_t now = helper_set_consensus_and_system_time(ns, service_position);
+ helper_initialize_big_hash_ring(ns);
+
+ /* 2) Initialize service */
+ hs_service_t *service = helper_init_service(now);
+ desc = client_fetches_next_desc ? service->desc_next : service->desc_current;
+
+ /* Now let's upload our desc to all hsdirs */
+ upload_descriptor_to_all(service, desc);
+ /* Cleanup right now so we don't memleak on error. */
+ cleanup_nodelist();
+ /* Check that previous hsdirs were populated */
+ tt_int_op(smartlist_len(desc->previous_hsdirs), OP_EQ, 8);
+
+ /* 3) Initialize client time */
+ helper_set_consensus_and_system_time(ns, client_position);
+
+ cleanup_nodelist();
+ SMARTLIST_FOREACH(ns->routerstatus_list,
+ routerstatus_t *, rs, routerstatus_free(rs));
+ smartlist_clear(ns->routerstatus_list);
+ helper_initialize_big_hash_ring(ns);
+
+ /* 4) Pick 6 HSDirs as a client and check that they were also chosen by the
+ service. */
+ for (int y = 0 ; y < 6 ; y++) {
+ char client_hsdir_b64_digest[BASE64_DIGEST_LEN+1] = {0};
+ helper_client_pick_hsdir(&service->keys.identity_pk,
+ client_hsdir_b64_digest);
+
+ /* CHECK: Go through the hsdirs chosen by the service and make sure that it
+ * contains the one picked by the client! */
+ retval = smartlist_contains_string(desc->previous_hsdirs,
+ client_hsdir_b64_digest);
+ tt_int_op(retval, OP_EQ, 1);
+ }
+
+ /* Finally, try to pick a 7th hsdir and see that NULL is returned since we
+ * exhausted all of them: */
+ tt_assert(!pick_hsdir_v3(&service->keys.identity_pk));
+
+ done:
+ /* At the end: free all services and initialize the subsystem again, we will
+ * need it for next scenario. */
+ cleanup_nodelist();
+ hs_service_free_all();
+ hs_service_init();
+ SMARTLIST_FOREACH(ns->routerstatus_list,
+ routerstatus_t *, rs, routerstatus_free(rs));
+ smartlist_clear(ns->routerstatus_list);
+}
+
+/** This test ensures that client and service will pick the same HSDirs, under
+ * various timing scenarios:
+ * a) Scenario where both client and service are in the time segment between
+ * SRV#N and TP#N:
+ * b) Scenario where both client and service are in the time segment between
+ * TP#N and SRV#N+1.
+ * c) Scenario where service is between SRV#N and TP#N, but client is between
+ * TP#N and SRV#N+1.
+ * d) Scenario where service is between TP#N and SRV#N+1, but client is
+ * between SRV#N and TP#N.
+ *
+ * This test is important because it tests that upload_descriptor_to_all() is
+ * in synch with pick_hsdir_v3(). That's not the case for the
+ * test_reachability() test which only compares the responsible hsdir sets.
+ */
+static void
+test_client_service_hsdir_set_sync(void *arg)
+{
+ networkstatus_t *ns = NULL;
+
+ (void) arg;
+
+ MOCK(networkstatus_get_latest_consensus,
+ mock_networkstatus_get_latest_consensus);
+ MOCK(networkstatus_get_live_consensus,
+ mock_networkstatus_get_live_consensus);
+ MOCK(get_or_state,
+ get_or_state_replacement);
+ MOCK(hs_desc_encode_descriptor,
+ mock_hs_desc_encode_descriptor);
+ MOCK(directory_initiate_request,
+ mock_directory_initiate_request);
+
+ hs_init();
+
+ /* Initialize a big hash ring: we want it to be big so that client and
+ * service cannot accidentally select the same HSDirs */
+ ns = networkstatus_get_latest_consensus();
+ tt_assert(ns);
+
+ /** Now test the various synch scenarios. See the helper function for more
+ details: */
+
+ /* a) Scenario where both client and service are in the time segment between
+ * SRV#N and TP#N. At this time the client fetches the first HS desc:
+ *
+ * +------------------------------------------------------------------+
+ * | |
+ * | 00:00 12:00 00:00 12:00 00:00 12:00 |
+ * | SRV#1 TP#1 SRV#2 TP#2 SRV#3 TP#3 |
+ * | |
+ * | $==========|-----------$===========|----------$===========| |
+ * | ^ ^ |
+ * | S C |
+ * +------------------------------------------------------------------+
+ */
+ helper_test_hsdir_sync(ns, LATE_IN_SRV_TO_TP, LATE_IN_SRV_TO_TP, 0);
+
+ /* b) Scenario where both client and service are in the time segment between
+ * TP#N and SRV#N+1. At this time the client fetches the second HS
+ * desc:
+ *
+ * +------------------------------------------------------------------+
+ * | |
+ * | 00:00 12:00 00:00 12:00 00:00 12:00 |
+ * | SRV#1 TP#1 SRV#2 TP#2 SRV#3 TP#3 |
+ * | |
+ * | $==========|-----------$===========|-----------$===========| |
+ * | ^ ^ |
+ * | S C |
+ * +------------------------------------------------------------------+
+ */
+ helper_test_hsdir_sync(ns, LATE_IN_TP_TO_SRV, LATE_IN_TP_TO_SRV, 1);
+
+ /* c) Scenario where service is between SRV#N and TP#N, but client is
+ * between TP#N and SRV#N+1. Client is forward in time so it fetches the
+ * second HS desc.
+ *
+ * +------------------------------------------------------------------+
+ * | |
+ * | 00:00 12:00 00:00 12:00 00:00 12:00 |
+ * | SRV#1 TP#1 SRV#2 TP#2 SRV#3 TP#3 |
+ * | |
+ * | $==========|-----------$===========|-----------$===========| |
+ * | ^ ^ |
+ * | S C |
+ * +------------------------------------------------------------------+
+ */
+ helper_test_hsdir_sync(ns, LATE_IN_SRV_TO_TP, EARLY_IN_TP_TO_SRV, 1);
+
+ /* d) Scenario where service is between TP#N and SRV#N+1, but client is
+ * between SRV#N and TP#N. Client is backwards in time so it fetches the
+ * first HS desc.
+ *
+ * +------------------------------------------------------------------+
+ * | |
+ * | 00:00 12:00 00:00 12:00 00:00 12:00 |
+ * | SRV#1 TP#1 SRV#2 TP#2 SRV#3 TP#3 |
+ * | |
+ * | $==========|-----------$===========|-----------$===========| |
+ * | ^ ^ |
+ * | C S |
+ * +------------------------------------------------------------------+
+ */
+ helper_test_hsdir_sync(ns, EARLY_IN_TP_TO_SRV, LATE_IN_SRV_TO_TP, 0);
+
+ /* e) Scenario where service is between SRV#N and TP#N, but client is
+ * between TP#N-1 and SRV#3. Client is backwards in time so it fetches
+ * the first HS desc.
+ *
+ * +------------------------------------------------------------------+
+ * | |
+ * | 00:00 12:00 00:00 12:00 00:00 12:00 |
+ * | SRV#1 TP#1 SRV#2 TP#2 SRV#3 TP#3 |
+ * | |
+ * | $==========|-----------$===========|-----------$===========| |
+ * | ^ ^ |
+ * | C S |
+ * +------------------------------------------------------------------+
+ */
+ helper_test_hsdir_sync(ns, EARLY_IN_SRV_TO_TP, LATE_IN_TP_TO_SRV, 0);
+
+ /* f) Scenario where service is between TP#N and SRV#N+1, but client is
+ * between SRV#N+1 and TP#N+1. Client is forward in time so it fetches
+ * the second HS desc.
+ *
+ * +------------------------------------------------------------------+
+ * | |
+ * | 00:00 12:00 00:00 12:00 00:00 12:00 |
+ * | SRV#1 TP#1 SRV#2 TP#2 SRV#3 TP#3 |
+ * | |
+ * | $==========|-----------$===========|-----------$===========| |
+ * | ^ ^ |
+ * | S C |
+ * +------------------------------------------------------------------+
+ */
+ helper_test_hsdir_sync(ns, LATE_IN_TP_TO_SRV, EARLY_IN_SRV_TO_TP, 1);
+
+ done:
+ networkstatus_vote_free(ns);
+ nodelist_free_all();
+ hs_free_all();
+}
+
+struct testcase_t hs_common_tests[] = {
+ { "build_address", test_build_address, TT_FORK,
+ NULL, NULL },
+ { "validate_address", test_validate_address, TT_FORK,
+ NULL, NULL },
+ { "time_period", test_time_period, TT_FORK,
+ NULL, NULL },
+ { "start_time_of_next_time_period", test_start_time_of_next_time_period,
+ TT_FORK, NULL, NULL },
+ { "responsible_hsdirs", test_responsible_hsdirs, TT_FORK,
+ NULL, NULL },
+ { "desc_reupload_logic", test_desc_reupload_logic, TT_FORK,
+ NULL, NULL },
+ { "disaster_srv", test_disaster_srv, TT_FORK,
+ NULL, NULL },
+ { "hid_serv_request_tracker", test_hid_serv_request_tracker, TT_FORK,
+ NULL, NULL },
+ { "parse_extended_hostname", test_parse_extended_hostname, TT_FORK,
+ NULL, NULL },
+ { "time_between_tp_and_srv", test_time_between_tp_and_srv, TT_FORK,
+ NULL, NULL },
+ { "reachability", test_reachability, TT_FORK,
+ NULL, NULL },
+ { "client_service_hsdir_set_sync", test_client_service_hsdir_set_sync,
+ TT_FORK, NULL, NULL },
+ { "hs_indexes", test_hs_indexes, TT_FORK,
+ NULL, NULL },
+
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_hs_config.c b/src/test/test_hs_config.c
new file mode 100644
index 0000000000..a76be301d3
--- /dev/null
+++ b/src/test/test_hs_config.c
@@ -0,0 +1,487 @@
+/* Copyright (c) 2016, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file test_hs_config.c
+ * \brief Test hidden service configuration functionality.
+ */
+
+#define CONFIG_PRIVATE
+#define HS_SERVICE_PRIVATE
+
+#include "test.h"
+#include "test_helpers.h"
+#include "log_test_helpers.h"
+
+#include "config.h"
+#include "hs_common.h"
+#include "hs_config.h"
+#include "hs_service.h"
+#include "rendservice.h"
+
+static int
+helper_config_service(const char *conf, int validate_only)
+{
+ int ret = 0;
+ or_options_t *options = NULL;
+ tt_assert(conf);
+ options = helper_parse_options(conf);
+ tt_assert(options);
+ ret = hs_config_service_all(options, validate_only);
+ done:
+ or_options_free(options);
+ return ret;
+}
+
+static void
+test_invalid_service(void *arg)
+{
+ int ret;
+
+ (void) arg;
+
+ /* Try with a missing port configuration. */
+ {
+ const char *conf =
+ "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
+ "HiddenServiceVersion 1\n"; /* Wrong not supported version. */
+ setup_full_capture_of_logs(LOG_WARN);
+ ret = helper_config_service(conf, 1);
+ tt_int_op(ret, OP_EQ, -1);
+ expect_log_msg_containing("HiddenServiceVersion must be between 2 and 3");
+ teardown_capture_of_logs();
+ }
+
+ /* Bad value of HiddenServiceAllowUnknownPorts. */
+ {
+ const char *conf =
+ "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
+ "HiddenServiceVersion 2\n"
+ "HiddenServiceAllowUnknownPorts 2\n"; /* Should be 0 or 1. */
+ setup_full_capture_of_logs(LOG_WARN);
+ ret = helper_config_service(conf, 1);
+ tt_int_op(ret, OP_EQ, -1);
+ expect_log_msg_containing("HiddenServiceAllowUnknownPorts must be "
+ "between 0 and 1, not 2");
+ teardown_capture_of_logs();
+ }
+
+ /* Bad value of HiddenServiceDirGroupReadable */
+ {
+ const char *conf =
+ "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
+ "HiddenServiceVersion 2\n"
+ "HiddenServiceDirGroupReadable 2\n"; /* Should be 0 or 1. */
+ setup_full_capture_of_logs(LOG_WARN);
+ ret = helper_config_service(conf, 1);
+ tt_int_op(ret, OP_EQ, -1);
+ expect_log_msg_containing("HiddenServiceDirGroupReadable must be "
+ "between 0 and 1, not 2");
+ teardown_capture_of_logs();
+ }
+
+ /* Bad value of HiddenServiceMaxStreamsCloseCircuit */
+ {
+ const char *conf =
+ "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
+ "HiddenServiceVersion 2\n"
+ "HiddenServiceMaxStreamsCloseCircuit 2\n"; /* Should be 0 or 1. */
+ setup_full_capture_of_logs(LOG_WARN);
+ ret = helper_config_service(conf, 1);
+ tt_int_op(ret, OP_EQ, -1);
+ expect_log_msg_containing("HiddenServiceMaxStreamsCloseCircuit must "
+ "be between 0 and 1, not 2");
+ teardown_capture_of_logs();
+ }
+
+ /* Too much max streams. */
+ {
+ const char *conf =
+ "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
+ "HiddenServiceVersion 2\n"
+ "HiddenServicePort 80\n"
+ "HiddenServiceMaxStreams 65536\n"; /* One too many. */
+ setup_full_capture_of_logs(LOG_WARN);
+ ret = helper_config_service(conf, 1);
+ tt_int_op(ret, OP_EQ, -1);
+ expect_log_msg_containing("HiddenServiceMaxStreams must be between "
+ "0 and 65535, not 65536");
+ teardown_capture_of_logs();
+ }
+
+ /* Duplicate directory directive. */
+ {
+ const char *conf =
+ "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
+ "HiddenServiceVersion 2\n"
+ "HiddenServicePort 80\n"
+ "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
+ "HiddenServiceVersion 2\n"
+ "HiddenServicePort 81\n";
+ setup_full_capture_of_logs(LOG_WARN);
+ ret = helper_config_service(conf, 1);
+ tt_int_op(ret, OP_EQ, -1);
+ expect_log_msg_containing("Another hidden service is already "
+ "configured for directory");
+ teardown_capture_of_logs();
+ }
+
+ /* Bad port. */
+ {
+ const char *conf =
+ "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
+ "HiddenServiceVersion 2\n"
+ "HiddenServicePort 65536\n";
+ setup_full_capture_of_logs(LOG_WARN);
+ ret = helper_config_service(conf, 1);
+ tt_int_op(ret, OP_EQ, -1);
+ expect_log_msg_containing("Missing or invalid port");
+ teardown_capture_of_logs();
+ }
+
+ /* Out of order directives. */
+ {
+ const char *conf =
+ "HiddenServiceVersion 2\n"
+ "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
+ "HiddenServicePort 80\n";
+ setup_full_capture_of_logs(LOG_WARN);
+ ret = helper_config_service(conf, 1);
+ tt_int_op(ret, OP_EQ, -1);
+ expect_log_msg_containing("HiddenServiceVersion with no preceding "
+ "HiddenServiceDir directive");
+ teardown_capture_of_logs();
+ }
+
+ done:
+ ;
+}
+
+static void
+test_valid_service(void *arg)
+{
+ int ret;
+
+ (void) arg;
+
+ /* Mix of v2 and v3. Still valid. */
+ {
+ const char *conf =
+ "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
+ "HiddenServiceVersion 2\n"
+ "HiddenServicePort 80\n"
+ "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs2\n"
+ "HiddenServiceVersion 3\n"
+ "HiddenServicePort 81\n"
+ "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs3\n"
+ "HiddenServiceVersion 2\n"
+ "HiddenServicePort 82\n";
+ ret = helper_config_service(conf, 1);
+ tt_int_op(ret, OP_EQ, 0);
+ }
+
+ done:
+ ;
+}
+
+static void
+test_invalid_service_v2(void *arg)
+{
+ int validate_only = 1, ret;
+
+ (void) arg;
+
+ /* Try with a missing port configuration. */
+ {
+ const char *conf =
+ "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
+ "HiddenServiceVersion 2\n";
+ setup_full_capture_of_logs(LOG_WARN);
+ ret = helper_config_service(conf, validate_only);
+ tt_int_op(ret, OP_EQ, -1);
+ expect_log_msg_containing("with no ports configured.");
+ teardown_capture_of_logs();
+ }
+
+ /* Too many introduction points. */
+ {
+ const char *conf =
+ "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
+ "HiddenServiceVersion 2\n"
+ "HiddenServicePort 80\n"
+ "HiddenServiceNumIntroductionPoints 11\n"; /* One too many. */
+ setup_full_capture_of_logs(LOG_WARN);
+ ret = helper_config_service(conf, validate_only);
+ tt_int_op(ret, OP_EQ, -1);
+ expect_log_msg_containing("HiddenServiceNumIntroductionPoints should "
+ "be between 0 and 10, not 11");
+ teardown_capture_of_logs();
+ }
+
+ /* Too little introduction points. */
+ {
+ const char *conf =
+ "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
+ "HiddenServiceVersion 2\n"
+ "HiddenServicePort 80\n"
+ "HiddenServiceNumIntroductionPoints -1\n";
+ setup_full_capture_of_logs(LOG_WARN);
+ ret = helper_config_service(conf, validate_only);
+ tt_int_op(ret, OP_EQ, -1);
+ expect_log_msg_containing("HiddenServiceNumIntroductionPoints should "
+ "be between 0 and 10, not -1");
+ teardown_capture_of_logs();
+ }
+
+ /* Bad authorized client type. */
+ {
+ const char *conf =
+ "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
+ "HiddenServiceVersion 2\n"
+ "HiddenServicePort 80\n"
+ "HiddenServiceAuthorizeClient blah alice,bob\n"; /* blah is no good. */
+ setup_full_capture_of_logs(LOG_WARN);
+ ret = helper_config_service(conf, validate_only);
+ tt_int_op(ret, OP_EQ, -1);
+ expect_log_msg_containing("HiddenServiceAuthorizeClient contains "
+ "unrecognized auth-type");
+ teardown_capture_of_logs();
+ }
+
+ done:
+ ;
+}
+
+static void
+test_valid_service_v2(void *arg)
+{
+ int ret;
+
+ (void) arg;
+
+ /* Valid complex configuration. Basic client authorization. */
+ {
+ const char *conf =
+ "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
+ "HiddenServiceVersion 2\n"
+ "HiddenServicePort 80\n"
+ "HiddenServicePort 22 localhost:22\n"
+#ifdef HAVE_SYS_UN_H
+ "HiddenServicePort 42 unix:/path/to/socket\n"
+#endif
+ "HiddenServiceAuthorizeClient basic alice,bob,eve\n"
+ "HiddenServiceAllowUnknownPorts 1\n"
+ "HiddenServiceMaxStreams 42\n"
+ "HiddenServiceMaxStreamsCloseCircuit 0\n"
+ "HiddenServiceDirGroupReadable 1\n"
+ "HiddenServiceNumIntroductionPoints 7\n";
+ ret = helper_config_service(conf, 1);
+ tt_int_op(ret, OP_EQ, 0);
+ }
+
+ /* Valid complex configuration. Stealth client authorization. */
+ {
+ const char *conf =
+ "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs2\n"
+ "HiddenServiceVersion 2\n"
+ "HiddenServicePort 65535\n"
+ "HiddenServicePort 22 1.1.1.1:22\n"
+#ifdef HAVE_SYS_UN_H
+ "HiddenServicePort 9000 unix:/path/to/socket\n"
+#endif
+ "HiddenServiceAuthorizeClient stealth charlie,romeo\n"
+ "HiddenServiceAllowUnknownPorts 0\n"
+ "HiddenServiceMaxStreams 42\n"
+ "HiddenServiceMaxStreamsCloseCircuit 0\n"
+ "HiddenServiceDirGroupReadable 1\n"
+ "HiddenServiceNumIntroductionPoints 8\n";
+ ret = helper_config_service(conf, 1);
+ tt_int_op(ret, OP_EQ, 0);
+ }
+
+ done:
+ ;
+}
+
+static void
+test_invalid_service_v3(void *arg)
+{
+ int validate_only = 1, ret;
+
+ (void) arg;
+
+ /* Try with a missing port configuration. */
+ {
+ const char *conf =
+ "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
+ "HiddenServiceVersion 3\n";
+ setup_full_capture_of_logs(LOG_WARN);
+ ret = helper_config_service(conf, validate_only);
+ tt_int_op(ret, OP_EQ, -1);
+ expect_log_msg_containing("with no ports configured.");
+ teardown_capture_of_logs();
+ }
+
+ /* Too many introduction points. */
+ {
+ const char *conf =
+ "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
+ "HiddenServiceVersion 3\n"
+ "HiddenServicePort 80\n"
+ "HiddenServiceNumIntroductionPoints 21\n"; /* One too many. */
+ setup_full_capture_of_logs(LOG_WARN);
+ ret = helper_config_service(conf, validate_only);
+ tt_int_op(ret, OP_EQ, -1);
+ expect_log_msg_containing("HiddenServiceNumIntroductionPoints must "
+ "be between 3 and 20, not 21.");
+ teardown_capture_of_logs();
+ }
+
+ /* Too little introduction points. */
+ {
+ const char *conf =
+ "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
+ "HiddenServiceVersion 3\n"
+ "HiddenServicePort 80\n"
+ "HiddenServiceNumIntroductionPoints 1\n";
+ setup_full_capture_of_logs(LOG_WARN);
+ ret = helper_config_service(conf, validate_only);
+ tt_int_op(ret, OP_EQ, -1);
+ expect_log_msg_containing("HiddenServiceNumIntroductionPoints must "
+ "be between 3 and 20, not 1.");
+ teardown_capture_of_logs();
+ }
+
+ done:
+ ;
+}
+
+static void
+test_valid_service_v3(void *arg)
+{
+ int ret;
+
+ (void) arg;
+
+ /* Valid complex configuration. */
+ {
+ const char *conf =
+ "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
+ "HiddenServiceVersion 3\n"
+ "HiddenServicePort 80\n"
+ "HiddenServicePort 22 localhost:22\n"
+#ifdef HAVE_SYS_UN_H
+ "HiddenServicePort 42 unix:/path/to/socket\n"
+#endif
+ "HiddenServiceAllowUnknownPorts 1\n"
+ "HiddenServiceMaxStreams 42\n"
+ "HiddenServiceMaxStreamsCloseCircuit 0\n"
+ "HiddenServiceDirGroupReadable 1\n"
+ "HiddenServiceNumIntroductionPoints 7\n";
+ ret = helper_config_service(conf, 1);
+ tt_int_op(ret, OP_EQ, 0);
+ }
+
+ /* Valid complex configuration. */
+ {
+ const char *conf =
+ "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs2\n"
+ "HiddenServiceVersion 3\n"
+ "HiddenServicePort 65535\n"
+ "HiddenServicePort 22 1.1.1.1:22\n"
+#ifdef HAVE_SYS_UN_H
+ "HiddenServicePort 9000 unix:/path/to/socket\n"
+#endif
+ "HiddenServiceAllowUnknownPorts 0\n"
+ "HiddenServiceMaxStreams 42\n"
+ "HiddenServiceMaxStreamsCloseCircuit 0\n"
+ "HiddenServiceDirGroupReadable 1\n"
+ "HiddenServiceNumIntroductionPoints 20\n";
+ ret = helper_config_service(conf, 1);
+ tt_int_op(ret, OP_EQ, 0);
+ }
+
+ /* Mix of v2 and v3. Still valid. */
+ {
+ const char *conf =
+ "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs1\n"
+ "HiddenServiceVersion 2\n"
+ "HiddenServicePort 80\n"
+ "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs2\n"
+ "HiddenServiceVersion 3\n"
+ "HiddenServicePort 81\n"
+ "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs3\n"
+ "HiddenServiceVersion 2\n"
+ "HiddenServicePort 82\n";
+ ret = helper_config_service(conf, 1);
+ tt_int_op(ret, OP_EQ, 0);
+ }
+
+ done:
+ ;
+}
+
+static void
+test_staging_service_v3(void *arg)
+{
+ int ret;
+
+ (void) arg;
+
+ /* We don't validate a service object, this is the service test that are in
+ * charge of doing so. We just check for the stable state after
+ * registration. */
+
+ hs_init();
+
+ /* Time for a valid v3 service that should get staged. */
+ const char *conf =
+ "HiddenServiceDir /tmp/tor-test-hs-RANDOM/hs2\n"
+ "HiddenServiceVersion 3\n"
+ "HiddenServicePort 65535\n"
+ "HiddenServicePort 22 1.1.1.1:22\n"
+#ifdef HAVE_SYS_UN_H
+ "HiddenServicePort 9000 unix:/path/to/socket\n"
+#endif
+ "HiddenServiceAllowUnknownPorts 0\n"
+ "HiddenServiceMaxStreams 42\n"
+ "HiddenServiceMaxStreamsCloseCircuit 0\n"
+ "HiddenServiceDirGroupReadable 1\n"
+ "HiddenServiceNumIntroductionPoints 20\n";
+ ret = helper_config_service(conf, 0);
+ tt_int_op(ret, OP_EQ, 0);
+ /* Ok, we have a service in our map! Registration went well. */
+ tt_int_op(get_hs_service_staging_list_size(), OP_EQ, 1);
+ /* Make sure we don't have a magic v2 service out of this. */
+ tt_int_op(rend_num_services(), OP_EQ, 0);
+
+ done:
+ hs_free_all();
+}
+
+struct testcase_t hs_config_tests[] = {
+ /* Invalid service not specific to any version. */
+ { "invalid_service", test_invalid_service, TT_FORK,
+ NULL, NULL },
+ { "valid_service", test_valid_service, TT_FORK,
+ NULL, NULL },
+
+ /* Test case only for version 2. */
+ { "invalid_service_v2", test_invalid_service_v2, TT_FORK,
+ NULL, NULL },
+ { "valid_service_v2", test_valid_service_v2, TT_FORK,
+ NULL, NULL },
+
+ /* Test case only for version 3. */
+ { "invalid_service_v3", test_invalid_service_v3, TT_FORK,
+ NULL, NULL },
+ { "valid_service_v3", test_valid_service_v3, TT_FORK,
+ NULL, NULL },
+
+ /* Test service staging. */
+ { "staging_service_v3", test_staging_service_v3, TT_FORK,
+ NULL, NULL },
+
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_hs_descriptor.c b/src/test/test_hs_descriptor.c
new file mode 100644
index 0000000000..897b441888
--- /dev/null
+++ b/src/test/test_hs_descriptor.c
@@ -0,0 +1,897 @@
+/* Copyright (c) 2016-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file test_hs_descriptor.c
+ * \brief Test hidden service descriptor encoding and decoding.
+ */
+
+#define HS_DESCRIPTOR_PRIVATE
+
+#include "crypto_ed25519.h"
+#include "ed25519_cert.h"
+#include "or.h"
+#include "hs_descriptor.h"
+#include "test.h"
+#include "torcert.h"
+
+#include "hs_test_helpers.h"
+#include "test_helpers.h"
+#include "log_test_helpers.h"
+
+#ifdef HAVE_CFLAG_WOVERLENGTH_STRINGS
+DISABLE_GCC_WARNING(overlength-strings)
+/* We allow huge string constants in the unit tests, but not in the code
+ * at large. */
+#endif
+#include "test_hs_descriptor.inc"
+ENABLE_GCC_WARNING(overlength-strings)
+
+/* Test certificate encoding put in a descriptor. */
+static void
+test_cert_encoding(void *arg)
+{
+ int ret;
+ char *encoded = NULL;
+ time_t now = time(NULL);
+ ed25519_keypair_t kp;
+ ed25519_public_key_t signed_key;
+ ed25519_secret_key_t secret_key;
+ tor_cert_t *cert = NULL;
+
+ (void) arg;
+
+ ret = ed25519_keypair_generate(&kp, 0);
+ tt_int_op(ret, == , 0);
+ ret = ed25519_secret_key_generate(&secret_key, 0);
+ tt_int_op(ret, == , 0);
+ ret = ed25519_public_key_generate(&signed_key, &secret_key);
+ tt_int_op(ret, == , 0);
+
+ cert = tor_cert_create(&kp, CERT_TYPE_SIGNING_AUTH, &signed_key,
+ now, 3600 * 2, CERT_FLAG_INCLUDE_SIGNING_KEY);
+ tt_assert(cert);
+
+ /* Test the certificate encoding function. */
+ ret = tor_cert_encode_ed22519(cert, &encoded);
+ tt_int_op(ret, OP_EQ, 0);
+
+ /* Validated the certificate string. */
+ {
+ char *end, *pos = encoded;
+ char *b64_cert, buf[256];
+ size_t b64_cert_len;
+ tor_cert_t *parsed_cert;
+
+ tt_int_op(strcmpstart(pos, "-----BEGIN ED25519 CERT-----\n"), OP_EQ, 0);
+ pos += strlen("-----BEGIN ED25519 CERT-----\n");
+
+ /* Isolate the base64 encoded certificate and try to decode it. */
+ end = strstr(pos, "-----END ED25519 CERT-----");
+ tt_assert(end);
+ b64_cert = pos;
+ b64_cert_len = end - pos;
+ ret = base64_decode(buf, sizeof(buf), b64_cert, b64_cert_len);
+ tt_int_op(ret, OP_GT, 0);
+ /* Parseable? */
+ parsed_cert = tor_cert_parse((uint8_t *) buf, ret);
+ tt_assert(parsed_cert);
+ /* Signature is valid? */
+ ret = tor_cert_checksig(parsed_cert, &kp.pubkey, now + 10);
+ tt_int_op(ret, OP_EQ, 0);
+ ret = tor_cert_eq(cert, parsed_cert);
+ tt_int_op(ret, OP_EQ, 1);
+ /* The cert did have the signing key? */
+ ret= ed25519_pubkey_eq(&parsed_cert->signing_key, &kp.pubkey);
+ tt_int_op(ret, OP_EQ, 1);
+ tor_cert_free(parsed_cert);
+
+ /* Get to the end part of the certificate. */
+ pos += b64_cert_len;
+ tt_int_op(strcmpstart(pos, "-----END ED25519 CERT-----"), OP_EQ, 0);
+ pos += strlen("-----END ED25519 CERT-----");
+ tt_str_op(pos, OP_EQ, "");
+ }
+
+ done:
+ tor_cert_free(cert);
+ tor_free(encoded);
+}
+
+/* Test the descriptor padding. */
+static void
+test_descriptor_padding(void *arg)
+{
+ char *plaintext;
+ size_t plaintext_len, padded_len;
+ uint8_t *padded_plaintext = NULL;
+
+/* 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_SUPERENC_PLAINTEXT_PAD_MULTIPLE) * \
+ HS_DESC_SUPERENC_PLAINTEXT_PAD_MULTIPLE
+
+ (void) arg;
+
+ { /* test #1: no padding */
+ plaintext_len = HS_DESC_SUPERENC_PLAINTEXT_PAD_MULTIPLE;
+ plaintext = tor_malloc(plaintext_len);
+ padded_len = build_plaintext_padding(plaintext, plaintext_len,
+ &padded_plaintext);
+ tt_assert(padded_plaintext);
+ tor_free(plaintext);
+ /* Make sure our padding has been zeroed. */
+ tt_int_op(tor_mem_is_zero((char *) padded_plaintext + plaintext_len,
+ padded_len - plaintext_len), OP_EQ, 1);
+ tor_free(padded_plaintext);
+ /* Never never have a padded length smaller than the plaintext. */
+ tt_int_op(padded_len, OP_GE, plaintext_len);
+ tt_int_op(padded_len, OP_EQ, PADDING_EXPECTED_LEN(plaintext_len));
+ }
+
+ { /* test #2: one byte padding? */
+ 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,
+ &padded_plaintext);
+ tt_assert(padded_plaintext);
+ tor_free(plaintext);
+ /* Make sure our padding has been zeroed. */
+ tt_int_op(tor_mem_is_zero((char *) padded_plaintext + plaintext_len,
+ padded_len - plaintext_len), OP_EQ, 1);
+ tor_free(padded_plaintext);
+ /* Never never have a padded length smaller than the plaintext. */
+ tt_int_op(padded_len, OP_GE, plaintext_len);
+ tt_int_op(padded_len, OP_EQ, PADDING_EXPECTED_LEN(plaintext_len));
+ }
+
+ { /* test #3: Lots more bytes of padding? */
+ 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,
+ &padded_plaintext);
+ tt_assert(padded_plaintext);
+ tor_free(plaintext);
+ /* Make sure our padding has been zeroed. */
+ tt_int_op(tor_mem_is_zero((char *) padded_plaintext + plaintext_len,
+ padded_len - plaintext_len), OP_EQ, 1);
+ tor_free(padded_plaintext);
+ /* Never never have a padded length smaller than the plaintext. */
+ tt_int_op(padded_len, OP_GE, plaintext_len);
+ tt_int_op(padded_len, OP_EQ, PADDING_EXPECTED_LEN(plaintext_len));
+ }
+
+ done:
+ return;
+}
+
+static void
+test_link_specifier(void *arg)
+{
+ ssize_t ret;
+ hs_desc_link_specifier_t spec;
+ smartlist_t *link_specifiers = smartlist_new();
+ char buf[256];
+ char *b64 = NULL;
+ link_specifier_t *ls = NULL;
+
+ (void) arg;
+
+ /* Always this port. */
+ spec.u.ap.port = 42;
+ smartlist_add(link_specifiers, &spec);
+
+ /* Test IPv4 for starter. */
+ {
+ uint32_t ipv4;
+
+ spec.type = LS_IPV4;
+ ret = tor_addr_parse(&spec.u.ap.addr, "1.2.3.4");
+ tt_int_op(ret, OP_EQ, AF_INET);
+ b64 = encode_link_specifiers(link_specifiers);
+ tt_assert(b64);
+
+ /* Decode it and validate the format. */
+ ret = base64_decode(buf, sizeof(buf), b64, strlen(b64));
+ tt_int_op(ret, OP_GT, 0);
+ /* First byte is the number of link specifier. */
+ tt_int_op(get_uint8(buf), OP_EQ, 1);
+ ret = link_specifier_parse(&ls, (uint8_t *) buf + 1, ret - 1);
+ tt_int_op(ret, OP_EQ, 8);
+ /* Should be 2 bytes for port and 4 bytes for IPv4. */
+ tt_int_op(link_specifier_get_ls_len(ls), OP_EQ, 6);
+ ipv4 = link_specifier_get_un_ipv4_addr(ls);
+ tt_int_op(tor_addr_to_ipv4h(&spec.u.ap.addr), OP_EQ, ipv4);
+ tt_int_op(link_specifier_get_un_ipv4_port(ls), OP_EQ, spec.u.ap.port);
+
+ link_specifier_free(ls);
+ ls = NULL;
+ tor_free(b64);
+ }
+
+ /* Test IPv6. */
+ {
+ uint8_t ipv6[16];
+
+ spec.type = LS_IPV6;
+ ret = tor_addr_parse(&spec.u.ap.addr, "[1:2:3:4::]");
+ tt_int_op(ret, OP_EQ, AF_INET6);
+ b64 = encode_link_specifiers(link_specifiers);
+ tt_assert(b64);
+
+ /* Decode it and validate the format. */
+ ret = base64_decode(buf, sizeof(buf), b64, strlen(b64));
+ tt_int_op(ret, OP_GT, 0);
+ /* First byte is the number of link specifier. */
+ tt_int_op(get_uint8(buf), OP_EQ, 1);
+ ret = link_specifier_parse(&ls, (uint8_t *) buf + 1, ret - 1);
+ tt_int_op(ret, OP_EQ, 20);
+ /* Should be 2 bytes for port and 16 bytes for IPv6. */
+ tt_int_op(link_specifier_get_ls_len(ls), OP_EQ, 18);
+ for (unsigned int i = 0; i < sizeof(ipv6); i++) {
+ ipv6[i] = link_specifier_get_un_ipv6_addr(ls, i);
+ }
+ tt_mem_op(tor_addr_to_in6_addr8(&spec.u.ap.addr), OP_EQ, ipv6,
+ sizeof(ipv6));
+ tt_int_op(link_specifier_get_un_ipv6_port(ls), OP_EQ, spec.u.ap.port);
+
+ link_specifier_free(ls);
+ ls = NULL;
+ tor_free(b64);
+ }
+
+ /* Test legacy. */
+ {
+ uint8_t *id;
+
+ spec.type = LS_LEGACY_ID;
+ memset(spec.u.legacy_id, 'Y', sizeof(spec.u.legacy_id));
+ b64 = encode_link_specifiers(link_specifiers);
+ tt_assert(b64);
+
+ /* Decode it and validate the format. */
+ ret = base64_decode(buf, sizeof(buf), b64, strlen(b64));
+ tt_int_op(ret, OP_GT, 0);
+ /* First byte is the number of link specifier. */
+ tt_int_op(get_uint8(buf), OP_EQ, 1);
+ ret = link_specifier_parse(&ls, (uint8_t *) buf + 1, ret - 1);
+ /* 20 bytes digest + 1 byte type + 1 byte len. */
+ tt_int_op(ret, OP_EQ, 22);
+ tt_int_op(link_specifier_getlen_un_legacy_id(ls), OP_EQ, DIGEST_LEN);
+ /* Digest length is 20 bytes. */
+ tt_int_op(link_specifier_get_ls_len(ls), OP_EQ, DIGEST_LEN);
+ id = link_specifier_getarray_un_legacy_id(ls);
+ tt_mem_op(spec.u.legacy_id, OP_EQ, id, DIGEST_LEN);
+
+ link_specifier_free(ls);
+ ls = NULL;
+ tor_free(b64);
+ }
+
+ done:
+ link_specifier_free(ls);
+ tor_free(b64);
+ smartlist_free(link_specifiers);
+}
+
+static void
+test_encode_descriptor(void *arg)
+{
+ int ret;
+ char *encoded = NULL;
+ ed25519_keypair_t signing_kp;
+ hs_descriptor_t *desc = NULL;
+
+ (void) arg;
+
+ ret = ed25519_keypair_generate(&signing_kp, 0);
+ tt_int_op(ret, OP_EQ, 0);
+ desc = hs_helper_build_hs_desc_with_ip(&signing_kp);
+ ret = hs_desc_encode_descriptor(desc, &signing_kp, &encoded);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_assert(encoded);
+
+ done:
+ hs_descriptor_free(desc);
+ tor_free(encoded);
+}
+
+static void
+test_decode_descriptor(void *arg)
+{
+ int ret;
+ char *encoded = NULL;
+ ed25519_keypair_t signing_kp;
+ hs_descriptor_t *desc = NULL;
+ hs_descriptor_t *decoded = NULL;
+ hs_descriptor_t *desc_no_ip = NULL;
+ uint8_t subcredential[DIGEST256_LEN];
+
+ (void) arg;
+
+ ret = ed25519_keypair_generate(&signing_kp, 0);
+ tt_int_op(ret, OP_EQ, 0);
+ desc = hs_helper_build_hs_desc_with_ip(&signing_kp);
+
+ hs_helper_get_subcred_from_identity_keypair(&signing_kp,
+ subcredential);
+
+ /* Give some bad stuff to the decoding function. */
+ ret = hs_desc_decode_descriptor("hladfjlkjadf", subcredential, &decoded);
+ tt_int_op(ret, OP_EQ, -1);
+
+ ret = hs_desc_encode_descriptor(desc, &signing_kp, &encoded);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_assert(encoded);
+
+ ret = hs_desc_decode_descriptor(encoded, subcredential, &decoded);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_assert(decoded);
+
+ hs_helper_desc_equal(desc, decoded);
+
+ /* Decode a descriptor with _no_ introduction points. */
+ {
+ ed25519_keypair_t signing_kp_no_ip;
+ ret = ed25519_keypair_generate(&signing_kp_no_ip, 0);
+ tt_int_op(ret, OP_EQ, 0);
+ hs_helper_get_subcred_from_identity_keypair(&signing_kp_no_ip,
+ subcredential);
+ desc_no_ip = hs_helper_build_hs_desc_no_ip(&signing_kp_no_ip);
+ tt_assert(desc_no_ip);
+ tor_free(encoded);
+ ret = hs_desc_encode_descriptor(desc_no_ip, &signing_kp_no_ip, &encoded);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_assert(encoded);
+ hs_descriptor_free(decoded);
+ ret = hs_desc_decode_descriptor(encoded, subcredential, &decoded);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_assert(decoded);
+ }
+
+ done:
+ hs_descriptor_free(desc);
+ hs_descriptor_free(desc_no_ip);
+ hs_descriptor_free(decoded);
+ tor_free(encoded);
+}
+
+static void
+test_supported_version(void *arg)
+{
+ int ret;
+
+ (void) arg;
+
+ /* Unsupported. */
+ ret = hs_desc_is_supported_version(42);
+ tt_int_op(ret, OP_EQ, 0);
+ /* To early. */
+ ret = hs_desc_is_supported_version(HS_DESC_SUPPORTED_FORMAT_VERSION_MIN - 1);
+ tt_int_op(ret, OP_EQ, 0);
+ /* One too new. */
+ ret = hs_desc_is_supported_version(HS_DESC_SUPPORTED_FORMAT_VERSION_MAX + 1);
+ tt_int_op(ret, OP_EQ, 0);
+ /* Valid version. */
+ ret = hs_desc_is_supported_version(3);
+ tt_int_op(ret, OP_EQ, 1);
+
+ done:
+ ;
+}
+
+static void
+test_encrypted_data_len(void *arg)
+{
+ int ret;
+ size_t value;
+
+ (void) arg;
+
+ /* No length, error. */
+ ret = encrypted_data_length_is_valid(0);
+ tt_int_op(ret, OP_EQ, 0);
+ /* Valid value. */
+ value = HS_DESC_ENCRYPTED_SALT_LEN + DIGEST256_LEN + 1;
+ ret = encrypted_data_length_is_valid(value);
+ tt_int_op(ret, OP_EQ, 1);
+
+ done:
+ ;
+}
+
+static void
+test_decode_invalid_intro_point(void *arg)
+{
+ int ret;
+ char *encoded_ip = NULL;
+ size_t len_out;
+ hs_desc_intro_point_t *ip = NULL;
+ ed25519_keypair_t signing_kp;
+ hs_descriptor_t *desc = NULL;
+
+ (void) arg;
+
+ /* Seperate pieces of a valid encoded introduction point. */
+ const char *intro_point =
+ "introduction-point AQIUMDI5OUYyNjhGQ0E5RDU1Q0QxNTc=";
+ const char *auth_key =
+ "auth-key\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQkACOhAAQW8ltYZMIWpyrfyE/b4Iyi8CNybCwYs6ADk7XfBaxsFAQAgBAD3/BE4\n"
+ "XojGE/N2bW/wgnS9r2qlrkydGyuCKIGayYx3haZ39LD4ZTmSMRxwmplMAqzG/XNP\n"
+ "0Kkpg4p2/VnLFJRdU1SMFo1lgQ4P0bqw7Tgx200fulZ4KUM5z5V7m+a/mgY=\n"
+ "-----END ED25519 CERT-----";
+ const char *enc_key =
+ "enc-key ntor bpZKLsuhxP6woDQ3yVyjm5gUKSk7RjfAijT2qrzbQk0=";
+ const char *enc_key_cert =
+ "enc-key-cert\n"
+ "-----BEGIN ED25519 CERT-----\n"
+ "AQsACOhZAUpNvCZ1aJaaR49lS6MCdsVkhVGVrRqoj0Y2T4SzroAtAQAgBABFOcGg\n"
+ "lbTt1DF5nKTE/gU3Fr8ZtlCIOhu1A+F5LM7fqCUupfesg0KTHwyIZOYQbJuM5/he\n"
+ "/jDNyLy9woPJdjkxywaY2RPUxGjLYtMQV0E8PUxWyICV+7y52fTCYaKpYQw=\n"
+ "-----END ED25519 CERT-----";
+
+ /* Try to decode a junk string. */
+ {
+ hs_descriptor_free(desc);
+ desc = NULL;
+ ret = ed25519_keypair_generate(&signing_kp, 0);
+ tt_int_op(ret, OP_EQ, 0);
+ desc = hs_helper_build_hs_desc_with_ip(&signing_kp);
+ const char *junk = "this is not a descriptor";
+ ip = decode_introduction_point(desc, junk);
+ tt_ptr_op(ip, OP_EQ, NULL);
+ hs_desc_intro_point_free(ip);
+ ip = NULL;
+ }
+
+ /* Invalid link specifiers. */
+ {
+ smartlist_t *lines = smartlist_new();
+ const char *bad_line = "introduction-point blah";
+ smartlist_add(lines, (char *) bad_line);
+ smartlist_add(lines, (char *) auth_key);
+ smartlist_add(lines, (char *) enc_key);
+ smartlist_add(lines, (char *) enc_key_cert);
+ encoded_ip = smartlist_join_strings(lines, "\n", 0, &len_out);
+ tt_assert(encoded_ip);
+ ip = decode_introduction_point(desc, encoded_ip);
+ tt_ptr_op(ip, OP_EQ, NULL);
+ tor_free(encoded_ip);
+ smartlist_free(lines);
+ hs_desc_intro_point_free(ip);
+ ip = NULL;
+ }
+
+ /* Invalid auth key type. */
+ {
+ smartlist_t *lines = smartlist_new();
+ /* Try to put a valid object that our tokenize function will be able to
+ * parse but that has nothing to do with the auth_key. */
+ const char *bad_line =
+ "auth-key\n"
+ "-----BEGIN UNICORN CERT-----\n"
+ "MIGJAoGBAO4bATcW8kW4h6RQQAKEgg+aXCpF4JwbcO6vGZtzXTDB+HdPVQzwqkbh\n"
+ "XzFM6VGArhYw4m31wcP1Z7IwULir7UMnAFd7Zi62aYfU6l+Y1yAoZ1wzu1XBaAMK\n"
+ "ejpwQinW9nzJn7c2f69fVke3pkhxpNdUZ+vplSA/l9iY+y+v+415AgMBAAE=\n"
+ "-----END UNICORN CERT-----";
+ /* Build intro point text. */
+ smartlist_add(lines, (char *) intro_point);
+ smartlist_add(lines, (char *) bad_line);
+ smartlist_add(lines, (char *) enc_key);
+ smartlist_add(lines, (char *) enc_key_cert);
+ encoded_ip = smartlist_join_strings(lines, "\n", 0, &len_out);
+ tt_assert(encoded_ip);
+ ip = decode_introduction_point(desc, encoded_ip);
+ tt_ptr_op(ip, OP_EQ, NULL);
+ tor_free(encoded_ip);
+ smartlist_free(lines);
+ }
+
+ /* Invalid enc-key. */
+ {
+ smartlist_t *lines = smartlist_new();
+ const char *bad_line =
+ "enc-key unicorn bpZKLsuhxP6woDQ3yVyjm5gUKSk7RjfAijT2qrzbQk0=";
+ /* Build intro point text. */
+ smartlist_add(lines, (char *) intro_point);
+ smartlist_add(lines, (char *) auth_key);
+ smartlist_add(lines, (char *) bad_line);
+ smartlist_add(lines, (char *) enc_key_cert);
+ encoded_ip = smartlist_join_strings(lines, "\n", 0, &len_out);
+ tt_assert(encoded_ip);
+ ip = decode_introduction_point(desc, encoded_ip);
+ tt_ptr_op(ip, OP_EQ, NULL);
+ tor_free(encoded_ip);
+ smartlist_free(lines);
+ }
+
+ /* Invalid enc-key object. */
+ {
+ smartlist_t *lines = smartlist_new();
+ const char *bad_line = "enc-key ntor";
+ /* Build intro point text. */
+ smartlist_add(lines, (char *) intro_point);
+ smartlist_add(lines, (char *) auth_key);
+ smartlist_add(lines, (char *) bad_line);
+ smartlist_add(lines, (char *) enc_key_cert);
+ encoded_ip = smartlist_join_strings(lines, "\n", 0, &len_out);
+ tt_assert(encoded_ip);
+ ip = decode_introduction_point(desc, encoded_ip);
+ tt_ptr_op(ip, OP_EQ, NULL);
+ tor_free(encoded_ip);
+ smartlist_free(lines);
+ }
+
+ /* Invalid enc-key base64 curv25519 key. */
+ {
+ smartlist_t *lines = smartlist_new();
+ const char *bad_line = "enc-key ntor blah===";
+ /* Build intro point text. */
+ smartlist_add(lines, (char *) intro_point);
+ smartlist_add(lines, (char *) auth_key);
+ smartlist_add(lines, (char *) bad_line);
+ smartlist_add(lines, (char *) enc_key_cert);
+ encoded_ip = smartlist_join_strings(lines, "\n", 0, &len_out);
+ tt_assert(encoded_ip);
+ ip = decode_introduction_point(desc, encoded_ip);
+ tt_ptr_op(ip, OP_EQ, NULL);
+ tor_free(encoded_ip);
+ smartlist_free(lines);
+ }
+
+ /* Invalid enc-key invalid legacy. */
+ {
+ smartlist_t *lines = smartlist_new();
+ const char *bad_line = "legacy-key blah===";
+ /* Build intro point text. */
+ smartlist_add(lines, (char *) intro_point);
+ smartlist_add(lines, (char *) auth_key);
+ smartlist_add(lines, (char *) bad_line);
+ smartlist_add(lines, (char *) enc_key_cert);
+ encoded_ip = smartlist_join_strings(lines, "\n", 0, &len_out);
+ tt_assert(encoded_ip);
+ ip = decode_introduction_point(desc, encoded_ip);
+ tt_ptr_op(ip, OP_EQ, NULL);
+ tor_free(encoded_ip);
+ smartlist_free(lines);
+ }
+
+ done:
+ hs_descriptor_free(desc);
+ hs_desc_intro_point_free(ip);
+}
+
+/** Make sure we fail gracefully when decoding the bad desc from #23233. */
+static void
+test_decode_bad_signature(void *arg)
+{
+ hs_desc_plaintext_data_t desc_plaintext;
+ int ret;
+
+ (void) arg;
+
+ /* Update approx time to dodge cert expiration */
+ update_approx_time(1502661599);
+
+ setup_full_capture_of_logs(LOG_WARN);
+ ret = hs_desc_decode_plaintext(HS_DESC_BAD_SIG, &desc_plaintext);
+ tt_int_op(ret, OP_EQ, -1);
+ expect_log_msg_containing("Malformed signature line. Rejecting.");
+ teardown_capture_of_logs();
+
+ done:
+ desc_plaintext_data_free_contents(&desc_plaintext);
+}
+
+static void
+test_decode_plaintext(void *arg)
+{
+ int ret;
+ hs_desc_plaintext_data_t desc_plaintext;
+ const char *bad_value = "unicorn";
+
+ (void) arg;
+
+#define template \
+ "hs-descriptor %s\n" \
+ "descriptor-lifetime %s\n" \
+ "descriptor-signing-key-cert\n" \
+ "-----BEGIN ED25519 CERT-----\n" \
+ "AQgABjvPAQaG3g+dc6oV/oJV4ODAtkvx56uBnPtBT9mYVuHVOhn7AQAgBABUg3mQ\n" \
+ "myBr4bu5LCr53wUEbW2EXui01CbUgU7pfo9LvJG3AcXRojj6HlfsUs9BkzYzYdjF\n" \
+ "A69Apikgu0ewHYkFFASt7Il+gB3w6J8YstQJZT7dtbtl+doM7ug8B68Qdg8=\n" \
+ "-----END ED25519 CERT-----\n" \
+ "revision-counter %s\n" \
+ "encrypted\n" \
+ "-----BEGIN %s-----\n" \
+ "UNICORN\n" \
+ "-----END MESSAGE-----\n" \
+ "signature m20WJH5agqvwhq7QeuEZ1mYyPWQDO+eJOZUjLhAiKu8DbL17DsDfJE6kXbWy" \
+ "HimbNj2we0enV3cCOOAsmPOaAw\n"
+
+ /* Invalid version. */
+ {
+ char *plaintext;
+ tor_asprintf(&plaintext, template, bad_value, "180", "42", "MESSAGE");
+ ret = hs_desc_decode_plaintext(plaintext, &desc_plaintext);
+ tor_free(plaintext);
+ tt_int_op(ret, OP_EQ, -1);
+ }
+
+ /* Missing fields. */
+ {
+ const char *plaintext = "hs-descriptor 3\n";
+ ret = hs_desc_decode_plaintext(plaintext, &desc_plaintext);
+ tt_int_op(ret, OP_EQ, -1);
+ }
+
+ /* Max length. */
+ {
+ size_t big = 64000;
+ /* Must always be bigger than HS_DESC_MAX_LEN. */
+ tt_int_op(HS_DESC_MAX_LEN, OP_LT, big);
+ char *plaintext = tor_malloc_zero(big);
+ memset(plaintext, 'a', big);
+ plaintext[big - 1] = '\0';
+ ret = hs_desc_decode_plaintext(plaintext, &desc_plaintext);
+ tor_free(plaintext);
+ tt_int_op(ret, OP_EQ, -1);
+ }
+
+ /* Bad lifetime value. */
+ {
+ char *plaintext;
+ tor_asprintf(&plaintext, template, "3", bad_value, "42", "MESSAGE");
+ ret = hs_desc_decode_plaintext(plaintext, &desc_plaintext);
+ tor_free(plaintext);
+ tt_int_op(ret, OP_EQ, -1);
+ }
+
+ /* Huge lifetime value. */
+ {
+ char *plaintext;
+ tor_asprintf(&plaintext, template, "3", "7181615", "42", "MESSAGE");
+ ret = hs_desc_decode_plaintext(plaintext, &desc_plaintext);
+ tor_free(plaintext);
+ tt_int_op(ret, OP_EQ, -1);
+ }
+
+ /* Invalid encrypted section. */
+ {
+ char *plaintext;
+ tor_asprintf(&plaintext, template, "3", "180", "42", bad_value);
+ ret = hs_desc_decode_plaintext(plaintext, &desc_plaintext);
+ tor_free(plaintext);
+ tt_int_op(ret, OP_EQ, -1);
+ }
+
+ /* Invalid revision counter. */
+ {
+ char *plaintext;
+ tor_asprintf(&plaintext, template, "3", "180", bad_value, "MESSAGE");
+ ret = hs_desc_decode_plaintext(plaintext, &desc_plaintext);
+ tor_free(plaintext);
+ tt_int_op(ret, OP_EQ, -1);
+ }
+
+ done:
+ ;
+}
+
+static void
+test_validate_cert(void *arg)
+{
+ int ret;
+ time_t now = time(NULL);
+ ed25519_keypair_t kp;
+ tor_cert_t *cert = NULL;
+
+ (void) arg;
+
+ ret = ed25519_keypair_generate(&kp, 0);
+ tt_int_op(ret, OP_EQ, 0);
+
+ /* Cert of type CERT_TYPE_AUTH_HS_IP_KEY. */
+ cert = tor_cert_create(&kp, CERT_TYPE_AUTH_HS_IP_KEY,
+ &kp.pubkey, now, 3600,
+ CERT_FLAG_INCLUDE_SIGNING_KEY);
+ tt_assert(cert);
+ /* Test with empty certificate. */
+ ret = cert_is_valid(NULL, CERT_TYPE_AUTH_HS_IP_KEY, "unicorn");
+ tt_int_op(ret, OP_EQ, 0);
+ /* Test with a bad type. */
+ ret = cert_is_valid(cert, CERT_TYPE_SIGNING_HS_DESC, "unicorn");
+ tt_int_op(ret, OP_EQ, 0);
+ /* Normal validation. */
+ ret = cert_is_valid(cert, CERT_TYPE_AUTH_HS_IP_KEY, "unicorn");
+ tt_int_op(ret, OP_EQ, 1);
+ /* Break signing key so signature verification will fails. */
+ memset(&cert->signing_key, 0, sizeof(cert->signing_key));
+ ret = cert_is_valid(cert, CERT_TYPE_AUTH_HS_IP_KEY, "unicorn");
+ tt_int_op(ret, OP_EQ, 0);
+ tor_cert_free(cert);
+
+ /* Try a cert without including the signing key. */
+ cert = tor_cert_create(&kp, CERT_TYPE_AUTH_HS_IP_KEY, &kp.pubkey, now,
+ 3600, 0);
+ tt_assert(cert);
+ /* Test with a bad type. */
+ ret = cert_is_valid(cert, CERT_TYPE_AUTH_HS_IP_KEY, "unicorn");
+ tt_int_op(ret, OP_EQ, 0);
+
+ done:
+ tor_cert_free(cert);
+}
+
+static void
+test_desc_signature(void *arg)
+{
+ int ret;
+ char *data = NULL, *desc = NULL;
+ char sig_b64[ED25519_SIG_BASE64_LEN + 1];
+ ed25519_keypair_t kp;
+ ed25519_signature_t sig;
+
+ (void) arg;
+
+ ed25519_keypair_generate(&kp, 0);
+ /* Setup a phoony descriptor but with a valid signature token that is the
+ * signature is verifiable. */
+ tor_asprintf(&data, "This is a signed descriptor\n");
+ ret = ed25519_sign_prefixed(&sig, (const uint8_t *) data, strlen(data),
+ "Tor onion service descriptor sig v3", &kp);
+ tt_int_op(ret, OP_EQ, 0);
+ ret = ed25519_signature_to_base64(sig_b64, &sig);
+ tt_int_op(ret, OP_EQ, 0);
+ /* Build the descriptor that should be valid. */
+ tor_asprintf(&desc, "%ssignature %s\n", data, sig_b64);
+ ret = desc_sig_is_valid(sig_b64, &kp.pubkey, desc, strlen(desc));
+ tt_int_op(ret, OP_EQ, 1);
+ /* Junk signature. */
+ ret = desc_sig_is_valid("JUNK", &kp.pubkey, desc, strlen(desc));
+ tt_int_op(ret, OP_EQ, 0);
+
+ done:
+ tor_free(desc);
+ 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, OP_EQ, 0);
+ tt_ptr_op(encrypted_out, OP_EQ, NULL);
+ 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, OP_EQ, 0);
+ tt_ptr_op(encrypted_out, OP_EQ, NULL);
+ 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, OP_EQ, 0);
+ tt_ptr_op(encrypted_out, OP_EQ, NULL);
+ 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, OP_EQ, 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,
+ NULL, NULL },
+ { "link_specifier", test_link_specifier, TT_FORK,
+ NULL, NULL },
+ { "encode_descriptor", test_encode_descriptor, TT_FORK,
+ NULL, NULL },
+ { "descriptor_padding", test_descriptor_padding, TT_FORK,
+ NULL, NULL },
+
+ /* Decoding tests. */
+ { "decode_descriptor", test_decode_descriptor, TT_FORK,
+ NULL, NULL },
+ { "encrypted_data_len", test_encrypted_data_len, TT_FORK,
+ NULL, NULL },
+ { "decode_invalid_intro_point", test_decode_invalid_intro_point, TT_FORK,
+ NULL, NULL },
+ { "decode_plaintext", test_decode_plaintext, TT_FORK,
+ NULL, NULL },
+ { "decode_bad_signature", test_decode_bad_signature, TT_FORK,
+ NULL, NULL },
+
+ /* Misc. */
+ { "version", test_supported_version, TT_FORK,
+ NULL, NULL },
+ { "validate_cert", test_validate_cert, TT_FORK,
+ NULL, NULL },
+ { "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_descriptor.inc b/src/test/test_hs_descriptor.inc
new file mode 100644
index 0000000000..70a2c7c2f7
--- /dev/null
+++ b/src/test/test_hs_descriptor.inc
@@ -0,0 +1,224 @@
+static const char* HS_DESC_BAD_SIG =
+"hs-descriptor 3\n"
+"descriptor-lifetime 180\n"
+"descriptor-signing-key-cert\n"
+"-----BEGIN ED25519 CERT-----\n"
+"AQgABl5+AQoPXRnCGEOxIup3AcjQXb8npNiUFm2Qv7A6JKk/K+EuAQAgBAD18iUD\n"
+"nbkUblnUvTHzipq4bcr6aPyFVB42Ptobg4xr8s3VjHiJtjs9MDEdr6nXS7UlyhEl\n"
+"78vsuFEvLp7cvAgGxYY1xGXdn5RdHMCdi8W9yZLKMQX9OuJckmp1C6q+cA4=\n"
+"-----END ED25519 CERT-----\n"
+"revision-counter 42\n"
+"superencrypted\n"
+"-----BEGIN MESSAGE-----\n"
+"BxzghAOjM4De6Z6eGTvBrTP2SJDdQOYV/u9qtvlFsa2FRQWk20Adv3zJ/AI10CQO\n"
+"mUP4DNXM8FWQYGTvmD7wGz2/cXGjKwBXg1qO7zF5eP/D/My1sXsIfCcb41mkheNt\n"
+"xn1I5eKXcnghtd4lw7OkPVjSb/Z+VARUMmf+0qSNgmHLgEVnAoGJsn8W8B4qtIay\n"
+"4h4PuV0jPPlqJx6jMFOOEW72uqnfmqeNvClENXXW60xhnaxsf0up62fuW8ktu6Wf\n"
+"lnX/lvTstBFZZQ8/XI1+G+BPf8TZf7mxu0WYVg1s/KWYasYMSw46as59nkqdq2Ii\n"
+"qJnqHX/R20mWBhgpLse6wO0aNpky/rozEnikaPqyO1DShf6a6jXY8ADBg7spnK2/\n"
+"h7sf1+F1xfi2dy2WGxc1EUMP1kTVUmbft7kOo2nA7+3YZwQuSJHaN/66HrzU2x5z\n"
+"ayRUJ8+qDtfpEf17xthc/Uh253blFK96IoJJiqBfI6xt3IqOdHJq0OOC9zBbF6Rj\n"
+"vKMsaxmc/nc6uOB2WePYSgkZ0qs/dRKBJs6+Ahn1KdGkadyd8mDKL86Oe8lncHdB\n"
+"m/6sQjhKqFgngkCDOIlEJyWizqfN84AGqD5Zyxq0rbsN+9KLsHFfEbCRjgqjO5nS\n"
+"FYSFtuKgCZl2gaYEslL1pIEYE6BD2Whjn/HWTRyWiULJr6SuavgcbxeNEQDuVCC+\n"
+"fm0X7Z+qERaMAMR0vTMJK/NzT4GifrDpgmgbxc+34CtNBF5TriM8aXTNZZlsW00k\n"
+"d0XRxFbbbtiT5VOaEHbny7R3MdTVutEc9E/BhLBvjSSrGX7vrryh6Oj++nthIIzm\n"
+"F4M7I11S0TyA+UE06qF1C8rKmhcqU9MWy1SiccJ9KOWhJ5xwlsXBIID7wVygUhVl\n"
+"ovzfKkDDPfRoBch6NdVkxNJx3gb63CUmC2TzfwOMh973nntMVzqqw9A7jYkro9ln\n"
+"217kHUwMk3e83UgFL4nn7NCf3Kj0zhJ4jSfAsuQpV6e7dhzrlNya0lqrUsY2zFXP\n"
+"xv8wUtg6Vo1KewgVQas4oElkgFjDN8RJ7uBAwfuE/b9NnYJoQd76G8DHei/1PHbu\n"
+"tbtwN9I5RHaTvEOfetsJFnIAkCG6O4CQpzwHu1DdvEP4s6/el10b/4awBJ4VwOVZ\n"
+"YHSe4X0DStTV4Cu6aLh5OvrOmGbieRj6HdGQ6syYCaEBTuxbBUUpjIAfVlReAIph\n"
+"6aOrY6HNcCmeVmL5qm4dKr2XXOREsnUFuMqmfQuQd9pN3zlmS+RqCgSJuFrguFpd\n"
+"mjo6UxZvbjE7yJjtCih38HRe5BaigP5RDRkXmiXjqJ4koLJpyjQh19k3BYGcdxUC\n"
+"RCcYXydbGF7qHlnoaX9HnX7y6ZRsyKQpt91PMTGOUsB4fS8NhsqPpl2gdp4poLNs\n"
+"+hqjWZJ3uuLotXBcgM39Dtq9tqqu9vM12T80UAfWnVEHrBphmukh49EhEr2sx/la\n"
+"kAzRoTbLyTdlGVei8hI7/RtZIaIcOkzlhcFI5zmBlydyrv6/79vzt6WI/w9GVGpM\n"
+"OuSM0NS2CDJ7Iw412nz3CV1pEXB551ZBmbme6NHUe4EtEsDbgkP1Z201H4j51yVz\n"
+"wNoIksE5Bh5XRKuu4We5f9KZb+AEG9kxKJ5DbJk2YGJEQFTyfv0H68pl9urstPXD\n"
+"aMQF806COe2uhGm5gV/skvPVTeEvStE3K8DxZgcWNcTMVk8ZjrUHNfguVVToP8hT\n"
+"Fl4Iqo3r+JZEAGXnAbTpxUVC2Xxspf3jsT5xhUfB/NOexZxrXWnQZ+pscsbow0ba\n"
+"GATtakD3TF2WBqq5WscmOex+lrJcBCWVIzVWdwi5ngAtm1S7efkJlFUvmi4OuYnN\n"
+"RyZfxVIpoer8f2/xPXvxkOWFminDy5sFEvlh2/pnymfKOUV+CKih9ZApt+izlRJn\n"
+"+sMIOW6Jhf/WYyjeN6KQpwi6CDpclQJXA1SVoOVVL5A3lotLjs0x7ThIcBoxCZBq\n"
+"rFBhBu1gJgJ8guMySAHssIvhHHwXJsYEwzWCVAg/zIUXy4PLwIkgHApl+vGcldGv\n"
+"Br5HNCuqQ2pD9z2RvzNneB/LrYB214i+BP2piO5HbmeJBhby93blGXVfQewQT6aF\n"
+"dBlK8/jQM0rvb+LkmvQm2ypOttRpX2kyQXooJHYTTusaUr4jVmgngCvGtgqAQVqD\n"
+"HULXfHWvugZbAh6dXF7gKnnsyDOWwAgy4OJRi8i0jCaZ8aWSFRUjeGKT26dg/ayB\n"
+"U4QfMb8vL8tMdXVBfQLGcBgvrzQYrY69//pV6bX3SbLfUfWXV9eqUVWVPqVyPEwa\n"
+"Tz/aGVnGv/dY8h2cVnrgSXJGlOO+mCwSl+k9nk7VcEaKYuNlaOP3ZlKJvVj1LefM\n"
+"FODh4qTDBo5NkyfKu5fcZcOqDMBeGWXZzltE7CmvY7fOpDNMsuAoXYWI7q9gK82F\n"
+"w+nS0tVFCIWYa9DgGMv9GKTOk4Ia9elkbWypdRE/4oz4QxmHsArEsK4gDI+wmcp7\n"
+"/NsAZeuy96r2YDIUam4uASKOiAqrEfCv6B6cYctdYwZbAEXdo4fkGrCIjNRZmZGv\n"
+"kcZzHzIymnAmKRTkPt/LQ7Rx27Qd/Vt++B3zt2ORFuopqowOP0ocGZtkm0daK3Fc\n"
+"YDXMwIpf6Z8PwvvsG1bQHcSR+cUZi7vK7+hj/LGhMPafHM7HmFUbAxpJYr5CvR6y\n"
+"V1pZQYltT8xWayCeMHlLAAg10RgDkqCnY4dHnrY4GdwI2O7Wpxomni7qVHMjn+cN\n"
+"UTrd7EeVw+dxAIYosuqG7ua7ee3VGoOs+XMLrscAqHahfGbyYC+j+6Tow4qwWBdU\n"
+"/W3NJXnRWaHTXFHllpClnxggPRQx4yPtgTOmBBVl/O0T6i4Bv0ygsJeZAqC3VmAJ\n"
+"QodQTzGf2jwqsZf4uHKQa0EKGQvTGjFVgAFNpHmAuzyqh0b1pq5JeXiFERGsKC3j\n"
+"xcJilq1XeIx4SL38YNuCxi4pnyJyLnGGHpNjdjeFO5lvgCaKPegsPo4hpNpTvBJ1\n"
+"D7+o3E5CqxzjRt9kQmtwBbuH/SQX2T0x8aQ6vhwjj8ftDfw+FbjpMR9zfU0Lf8V7\n"
+"UjVGIl2yiVBGScBZu1nSD83PxjFy3XdFtBYoU5OrlXwBEYQs91jwK7UCiGtjI2Ao\n"
+"ZGkJaBd4AqP6voyJiGnC3LWFcmeMyzfExgiclQwfhFqqf762TX5JwG6xGqtdcNKS\n"
+"k54LlcI/RfvJw3ncSs9YsodZr6Jz5irpRTHX5WwCrX9mLukP96SXo29bIXEZAqEr\n"
+"ZxEcF0zlYE+km5bRfRCRcVVrScugCshSNLOdQp6fOAtHCl7rdQ/8Rz7oHuqieLVi\n"
+"UldRsAmpk9fIfRLphXj4j24jRP0VtL/LoJwakWTa0xO8K7eBAMVITI+HgFfN4wSO\n"
+"Yh1B+bGD5WKxFsWSgBMmW+YLF5ZtxVmmbg7wK2dIpJs4pjg2YO/MTO7SifJ9kjcb\n"
+"bCc74Tjs5mLLGGjGCIoXfda6WXbt2it40XhFk2zUAcPPsgjbctftkaWph7JSZpmZ\n"
+"fVcPqKdhmA1U0LA2XEOMTxGyCAeseH6pJXZm9LdBozc1CwyWP8XEDHHJf35vfPKY\n"
+"JDe2PanFepIOHaoRTgE7ZkGWKzOIKlS0Ucr1ezVfcxiFgQUNM+MYXXbUz51BVVq1\n"
+"Dulg4VvX104nt/ULijcfa/TsE+uklEnkyk1mhavH337NQg38XF4cAngNlUF4nSW/\n"
+"j0jizbAtaSx1f7q6xqPm3zPRlHrGQizHXLyl+SLzDUVPOXbPwcoeev97YeeyB6h5\n"
+"NBbIK9hmekNDmYIwI0bmlrg6IXhC5pyvRe8sQlV+9wBY2liF0M1mq5onW3a55afp\n"
+"+ynxXfQucb1HxZLXvRIGMBgWSQ7HfIPASqSE90Vu6qQCfkOW5PDqONr4BM65V4+g\n"
+"AYsVEgaosgHw9CF7yKgkvmZpToOtGpCHVcdUeeY2/rrQnAQeSy19gj/baJ+OKl6Q\n"
+"i1EGU8Yqo2r0d4XDFp/eKgC4sv57qp1PwkYQ/HKqoelJ09IAZL2sQWc05BGwt1A0\n"
+"11qDIEdkZBjzK3qUnY3QlOuoZtALZrnPg56SlF1RGDOPqbcF+3opqsvzBoiikh4V\n"
+"WV5OUYjRDMUDLQqf/OkuktdYf5N3RcbYP0XsAvY0ZWG3Gp068b3p8peCpkDzrF9p\n"
+"bQ2ZvS304tN7+p0hif3+JyZy5/sxl17RxTeg5I3mo2+J0ptQDYwF/WadONO8r7uU\n"
+"YlRltFtQfyMzyVzHON4NHGjZh7dDGtWp0MGeHRBHQsC8bEChhvWme19VXhgZoWpl\n"
+"dUIZkSuvRwiURXjhKbZrEdJbVmr9FX6zoyOahv3VnmcEARoR+umxzvo3hGQPbHyH\n"
+"jTsQtSBjs75/9fCxcYmBWkh3JHVDVsCbV+z+5KZpk3m50J4Y1hC8hvepC9CaBqOM\n"
+"DjfyXh58x1yKiueEbcjSWsRuF7CjcrYnFUBHOs9U1j9WytCI3fhOWPMgR4UZpGuU\n"
+"WlcR1BXg1wYxX273xOS/jYn9MLAVlbRpPTUMIH9VRP+sc8+XaxKpJSCl4C+vcwNY\n"
+"1YdKD2QiuoBJ3fXGtqMVRtn9eZvatSJuY9CnRKRbf0hWmFD4D5RkiwE0WkdtwoHR\n"
+"uEXJ47RlF0/JDU1fY1mXBkq3usvB4Absy78qL06vh45xkk9bHbdf+7Ao1RQKmqiB\n"
+"NL5XnjBu+YX535WG7t7Su3mTCJXYHvn72ATxry8yhSLgWqt81STkRwc14HmrOGG8\n"
+"Gw7bz7y5vikj/rnPyr7ry+QRgNNDDayAqenAu2vEAzWir0RQC/iZ9rc/r7YQWGgL\n"
+"Xrd4TQ6rTZePARhwB3VomnLDDvLvi2oq/jPzLKSYM2a7qj/vBSbJ/NnNaDW5Ccew\n"
+"RjMI1lIHeedqYTVAW/CKoSEPcFSAzi/Ija0gcWLgX5xsFDGIYBepAX0KS9426kMu\n"
+"0r/V66zmPMusMilqRTx7KW+jZMVxXVc2zClcdmohMmtjsbqLkczprfSbdGswMv9Q\n"
+"I1ktHJHIRD0vPeZXnvKZsRKZw3sKb0ltZi33ZxCJFQPeGGtM5aAFthj6awcXy6Tt\n"
+"DPUQdCU/vh1zmGRAX17/Xb0irfvN+GhQLEl42pzhigJXc/rCG3a4Na8wT+xAIZVf\n"
+"WUI7hMslx5wA+iB4lrAjCq0YIrjINI/lHYpotXUZGmz5wz0jOciTmXMSx9du4cpk\n"
+"fIQJfR+fr5tG3fjHMgSP+p+RewHkd/7RUAmHC2k3cuk5pCJvUVJrhUIqsi1fa0LG\n"
+"GA0UU6Nr9tpYdNr1WkbKQjxTg0D//AXe61jmUS5XUU4AQf6zQVfN0TMtmuYeacbK\n"
+"4r6Z1CSIRbsgcnL1BN8GSd4KddkCqSk941aJUCoX+77ou4t0btVSB9FnLKipigtE\n"
+"E/Rpmv+81lA4fLiIag62/pcJ3uppsZ9aaHdR10SMmuCjAVLYHqhJfrHHn32dyqLK\n"
+"UI8kEZJ6GQzHLUXcGbbdnk1Qm6JwO8TeF/oQvh9y9py+oAyFy0qzP2UeUMUI2yRQ\n"
+"mlWSy+wX1DbVDQ3UHwJjWp65CgyYXuW8eCB0AbyF0kF4KGf7/7Ae7tEGbmYSm5MA\n"
+"71z+Azxtv5gRyRb787V2dyo0wcmbRlL7iUBVXNM/czQo31tAZIwLc+lKNp0SPH6g\n"
+"gJ2yX/GeDSFNAeEVUZ/f4KZIa7QQsnGWrUr+agSnQFkySmIjWYjwC/abJwah0v0d\n"
+"ulwr3tECaaXtoWVdYXa3utEclBz9umBwMJ9MQCm4Kx7dTYUWFT3bMM/ESTkGPcfm\n"
+"m+C4FsqFBs80WY0ududu50vTDSdJt1RqZ7Sg6DNH6acBvWyXOpT5mPJKUjnSFwyG\n"
+"oVLgv0aDDx7lLZdCkhyz/Ff5LNmBgQsjGllPszJ2gTZxZ5LD68S4kUirQG/qtzlS\n"
+"PGfDOC79SMZGgsoAnr4wV3RUTxsTVFlxVHsBMB+EXOFHAr3wHTVxUGBbGzxBlQ9w\n"
+"I/jlu8LIIexXAU75HS5KCGGfg0Z7BLqEzqpMKqcBQC7BD7GnCXrDSQ2DCXnl7bLN\n"
+"lIrQ/z2Y8AgSdED46R40MqyyN6CPPNiOCjONHZ30fLEXuEgCp4R/+x0WWsWpjGk2\n"
+"Ydkc03cx/X6moUYxB5HTqTodBmAQuWMX0rxFDrnR0SWghWjdWth9gjd+dvZ82tt1\n"
+"UMUywDPhcYchtUi2lnqnYJm5p00GN9Mk14MC5ZC5qP57IJVqxu0ktOMpks+CLPnz\n"
+"qp9OBpI4sIzd0y0aUJC2Gd+E9aAhlREIiicyBDmxLdk1i37QeeCralI3eubLNmE+\n"
+"CjDjD8t8FUGPpKglSD3lfLTqbp2TUvyWfvJC6ulFPNsAbeLHTnPnpyPQmWxhMNGt\n"
+"h67B9tbYww2TvNwqIgmB4+YIR4/pSs15TpAqvuUvjpmRwGklqgiSmrQrlIxCxux/\n"
+"mfsaL3KE97wm8BsaMpMkjUL7ByTIFhFZ/gHPTxaFpbqTZ4G+lABLgp3bIsB9Dl/P\n"
+"ovoqX+qL2Mq9T0GrVJGfRBuA5hISw63hx5zdsj2Cj3A3khHPqR+GRN/rVYUuOpLm\n"
+"z3v5pU/74vZRmNMAIhyhmweSEPNtyVkgSdgbFErqvhxN0om2Cd/7cWh2g5BXHyUL\n"
+"PBr7ZkgfsE9TnuDH7Z0JoBqXJki+MO6nqz73oH2Mm86yxcXp6O/ieKTollrUJ3yQ\n"
+"P6hLcEbYPzUV99del7Va5Wi0nn0wbRXCGVQdwY+iWc7pT+VVlncyg0TvLXi0OtOt\n"
+"O8xbT2DAzVXxMwOsKV9ZgS/0dtwzwICpnTzBI/47V8GYhHbOUNTBPZ52GaXMeWlX\n"
+"cuRGb0+7OkKWuriyOQ5z5xaASCVfqgnOwSZYiAk0gcDoK+JHdr64/sMoJhH87R4i\n"
+"2TO90whkScgiGR7A06Ba42bT1nJtI6pxvzdB2b4BDAs2Lr2OdcB3BY1dtzKjFkw/\n"
+"qfIw3F55UQwcs84ZEFQDAB/tmfNHajblDFpXR4N5QvU/PdWVWJUub7oNyhIX6ruu\n"
+"ln4H7lpTUHJZ7jkr1qpnvkztZtHGlpJ0QdUHgyMYER1xU58Hg77yzIW3EdAa2PyK\n"
+"1t4udKbQKChShlShIMzwzj57ss/69QobrpYAHYi6IRMaMUGBfipGBACK3yeXsXz0\n"
+"c3Q2J5vI6QbxNsiJ5t7Ry1IqotbJcU7HND/yVUAUbEg5CpEDOSeSOW/ulyLuFxEV\n"
+"lRTwIO/68BoIoR7umlP23/1N5OYzaBHhH2nThILBovHeJRXnGXSgeFfwSj7LIYEV\n"
+"c1MdDSg/HzoADPXyEPLzqFzHRHeNiqEolmOPnFh0hRzbMZ0W5TQPDGWJdF21g816\n"
+"vA0WW4UQjLM+vnX9kKKLA1ut+9JWk1dGKsmWtdWUDfJjUP/L6dS4OYEl6O6+SjM9\n"
+"GcyGvHTiC5OpJllYpvELP/NjtTf9or8Bmruuga/axeOuS5ocYLK/sGRlmO6Z96da\n"
+"QSlyGWEQAnM2D1cDmdd4CetPslOVIcQ41+coWCi2xg3UjO/bFK1CA4R1rb4ekXfs\n"
+"s5U2XChyHhUPgl57y1r0ILXRXWJTJ0/F9hhu4aYQVFeIV/IuzJbmTKKkAcCOH6ys\n"
+"qnu2BXz8Pm2tU10JFfRcuZ8rHuUyUErA40ESsLijON98GMwL4Rat9ZSCNS5hlK7y\n"
+"yRJdr0ITp8oTbduAoulgWOvtcw1L87QBVojWz3cbhXra+WITirYuGNbzfmZn1WQM\n"
+"kukEZUEHSypGOrHr1XiuY4Rw/DBaJSLyZ+VybEOfXqXkDBh5s1ayypBvzrzFZCIn\n"
+"PJxIVsvrkhrpEbTJ9d7zLWjhOa9ZWw8lAubllbGm+7qCfdHmGsfBtvJdzx6zhB1Y\n"
+"otL/PCis2XVTBEDJeB8pGqKFOZjNz8PC5qP+ymtAfy2ktl/u4HsFlxV7CsEKGYPm\n"
+"p3LqnhPUy5M5gin4E4uPPyzzD2kcM3way49FKWUKlblQU0SyWtHRmMB3vcVmyT85\n"
+"BRULXF7jgog7XR/EMltwQyJI6GcUCrnWZu+G0BEwXG+CsgCzE7assDavc1NSGLZM\n"
+"rmzXiFFyfk7CE6lW2Lm+oWaFwKdvpmNZJFGGX8ZHRE9ZvkFMnfw9MYf2W7xa0jf7\n"
+"k3c6X5wMuk9mznVtq5itNFVXh1mT1ujeWOiiqyH5UhQQjj6O+ZXt4gqt/jT6dd1i\n"
+"jRuhhxaUGOlhpVBW/ySXhZ+HgOy9aCJ/bgjRGaqGixogk4f4rcgigHruwTpOQuDn\n"
+"xDZ3Xns70S40WtHSYN+Gbl9nIh4yl78aNnA4FVtTAuLlVKEKlMJi9OBFuP5TEczG\n"
+"+0HTwL/VPSCI+8FUZBhlz3YwecYq6dY5mS46+luPW+5Wl+5jtzb8V9oxVnRx2hQq\n"
+"B5HJsM5FOOhHDHMXoCsevj7N/ufK7cU7Wbr0DkgYRwvb0ZJB5WYgcaQ0W7aduhGb\n"
+"MQsandhP8Ajb2cmLobi3mHHPbcEkvjT8JP9Sim5xtfF+oCMMB5ByA5bI2aIFybZm\n"
+"jX9e/V8wNgtpDKDVKPjB3+9dj5gU1N5JsrjQwQDB0kVRMWdpJCtD4hZ2+T/QE3SI\n"
+"f8Rdk8pj8qBzRPbnhW6qsoWZdjMRC8qixZqHw4jol09UF7Ab9hjEF5ZDTfNGXwy8\n"
+"/hz8su+mr8hhrlCrOF2vBYUayAA96zhbDWfg3Pdxo9bTn3/DmyAngL4J5Gu679xK\n"
+"rWN4j7uQG4bzTa8WJb09/lW49UzWvmrz0c6/yexk3T//xDD067FafdnP5pYs4Cvp\n"
+"rCoHpXbKjxx99DJmb5iXW0JRLSpFSCbf1HPHbmzST3minSXap5FCWDJcSgExKIJp\n"
+"DXZ9rk0LMnQA74MWC5gjjM+5t0AHKuNRhJbQSwYWTKqeApXho53T/COlfDlSs2tb\n"
+"Vz1Ia5z7IOfu1QheE93huNAHT3Ob+mSmUq782SqFPr6uwud/l5uP3HpcuwugdlFm\n"
+"Jw8uBBOQ53W4lLbYfQYTVgieClVhmYMu7Ye0xYZ5B2jf714sjZRMa0LCbsyj58xH\n"
+"uzs8ddNN1fLMzb0JRBE8JWj5PbxhA/sTwMkD7SnEMBUTtP0obmuQ982aTfyvQCH/\n"
+"ve8OUPtYf5XWNv18mpR+h+riMt1Y8Eb6BJzTMFNWagMJAe3JV6A6upHroNFo2FxY\n"
+"1XPRM1Rt0zKo7GD+oXnixfpl1aG8yqZhYo1ZC9buaHwH6zvM+xoiGD0iujeDtpVy\n"
+"Vp6cAqqaGmrNwcPVBLc7hNKrJnbFKyhjL5/xp9j6jQov1aWQ8HsaNvh0p2ljmlwb\n"
+"daTYZcwLgSgPna7HhiqnOSAmXZ7St/qe/b9TqBtIVzwzmtevgMyG98QV0syFP5X6\n"
+"2Jc1g9733sTZp7njq4Cu07JhpICpinhLWR3nkODJbjk/mpLcQZgtV6W749AUo8oT\n"
+"jRVEJ8MpCo1h0bVDxsRnA3DrMneD88L8/b10aHs+bPm1HKbCmT+kJAFaUQNa8JvJ\n"
+"pReN37qTWvZCte7vaPAIP5cboATMu/J4t3izpm+YJoJlWcIegGx3kQ+17P4MbgDl\n"
+"S93U4sOLvTk9+MoyPo9yGWU/zHgzcQ6wCFdzWMDRswuh+/4TJ2+yg6maq3iBtj39\n"
+"gNLMR+sRgGGvYisqE9bfvNQy5IWrABBKcSBTXeTM1DmW6jv3TI8DoCzCbpjqcIwT\n"
+"u2J+7k8wJEHPcAwnBjlyWphVvwNwM0cXqOnlJZ/4z7OGgjiNEem7TMuvxk+YkiXK\n"
+"OzftdTjeIpzBwsGRP8/teMBpjS95M7GloKtxO+muBVxXbmsq8GBRC9vtNJ2Ma/xP\n"
+"bXvd+7caytD3ob6ZfOzCpi4ZS8uByEfIMxlgZ5Sn3jhgEkcIU+YW9b3teMZOuWdA\n"
+"QpDCoMpXaHVyRqwVV59JjmftiBnNBEo1/QzRj2UxRi7fHMfmNxL5LRM4CHSLUSCq\n"
+"Y3A3pkxvBHUzemhynSFvtCPa8GHiUpe9so0V/2hlgaENAVELPjMlWytaYufRllgy\n"
+"tUnCd32C5PrrmYzMKnxKRPXLcxLgziruJGSks9vIspoPk0pWgkZm+M9fRpJKlWHF\n"
+"yT9OOGBW2yynw/yvXssxJmdUDxVcWL4uS2bZc4s0Zc6RSL9uQPjZVX0JLj+cXfx4\n"
+"93Gn5bDhMgm+CGM6j3RiAAD7tT5V0sytNFjXd1A4U1u8yj3wzhKqOtZpDmuGUlMn\n"
+"EODu7I5KtWxOTPThy7TecI5r+F/6KL+2MOtRhj2PmlT/Xed6PaAmDkQeiXGps08x\n"
+"u0JIpuB61axvT4PAsKZNUd4ExbzNxRDAARUMgY8krpmyKZyHVFIQ19uHM2lGl9/i\n"
+"h3PKlLHYI8RsHutHElzq+F5tWd5AA99LVRZX4axAVIQNiqRg8IMSoCwUaCCbjUMz\n"
+"sJCo2t36GYk5S2BRnfrCqYoZRHw+ENYN0tDEMhXq1OqjvNHW3TzL3DsUhM6EZU5n\n"
+"cRR4ynUvPqqWFphLefRW10vCtaW9roJQZyFYf9kd8xgW/BhcDNbTTaQ1U6xCHgX+\n"
+"78DKee/NvY1WIEBR8X0iVk5XlSJb14eRtxNawXFyebVdmC/DiMNgnTBncMbePnZi\n"
+"KCl1r5xqo7tSIoJ6Z0l6qINd89T9fcg9mujTVwsfQ+5/kdEy0Iw7CQcTOGvMaoPX\n"
+"IAJlWSVeZ8eu8kmsD1Z8ewoPufMKiY4cPRAK5bCDgsrK6bAExOlCwPnNNM8Ym1Hz\n"
+"aYFeGs5sW468Qww+Nbl5xcNFKtwUKZ6EebRHjwttiyTgCdAhv9wL1u2WFydWWgkG\n"
+"rwUbNpSLKls+pijCeJAscvxzbZz96iOaYrY8IyzGBFwfgFAESfnzBc8SQjZzMzoO\n"
+"vmYIRon2m/5w5AZA2IjQ4VxXJDK6XExD/ZLsxNXzMnROD++hE+s8DvPlRPmN4egF\n"
+"gAzJs/9t7IyE/dDf7gSSBqzEBbwduD8ozzYHwELUc4ERdRzjEdBM0azT61g7Yilr\n"
+"iT5Hy+2iw/pNwiqVOYiAbj2lwcoMlFZmdxviD4IMXdsNVWsCAVJL0PqIh1UDDb3z\n"
+"Urv3idBJeSBuuFr6AFS6kAgvrwV/pEGoBoHuyii/rZxVugGKeuMynKEvSHuFNuQU\n"
+"qIHcNgqQR34v2Ut5pQ1R8s7K3Rae/AhE5GncJa6FJmB9TF8MYMu9PlSZV/eGv8UL\n"
+"IDWQ7sY3NdhZini//xtwPqIw29yOeZ0X6Aqsek9tfh21UwKSpHb7T+PwXYmoB+23\n"
+"p3FXkP/rv4AGRq1xJqFYzKJvwsXqTFuNFWP74yhTg6rC90w2p5TeH1rJMAnv4u0L\n"
+"hGtG/NL+D1Tzdf00TYAjno5Ia5dQJDd/eO+Ygqnhl6hAqGtS6r9JhIEXw1nQD7SC\n"
+"lj96ZuKdUWO8rpIiAtvHAsn++xvMVPm/S1SwA8oE049iVwS8/eNNiMKoSlTlYc7o\n"
+"pusBZQrVF4We4HHYFjysBbcXlvoXDd8LkZ8Nh63VQPnoIGNKH2U6aXCnQcJ8dZqO\n"
+"DNxL4uyM4A578FUUR6vxqt2asnLHQ0Z7pPE4uqtz/WgbiHI/i2oHS8oe1clsifCw\n"
+"3ZY33kflqLftkTNka1oiftDb0OqFLjkS7/AUorqHazw53gM3gqJY5EXA3Px9+nhu\n"
+"NzxSK/t41JoCfgQJHMkIWb3yUcO4OFZeGCeAxIJY95hv/brt6/WNielXjNaohYvc\n"
+"lsSUHEJRHwVxQmWK0LS+g13HAgOI7cNt3MA8sSkzTneHGFgEvmrSyb0wCEmushC9\n"
+"mjQThvaxfQk9douA/cR2bHr7axXqv9vjztmxUr0a30a7lvLMBQbJmFtJJylW+tJe\n"
+"v/vKNOB+9mK793cttr2JFnMhwUKFKWiFDQJtxw/eLQWY4BJ19Rs2x4BJgmV+u1jB\n"
+"zR8uvxuArG/cqVEJsoC6uuSzhAWSwdvumijO6yuyWF6nHY6aAcy8dyFQlDFHAd+/\n"
+"J05Lrbzj4N9lcI7hPalh0uMdERGvtUdT8QRm5ebP1zogYEkZk/1GOU29dMawkAt/\n"
+"SWhp2yWdjLt8f5HQKu72vUF/yyTfzfdqQqJwfthP7+vp+sHDO85AMF45uU9g3pxW\n"
+"IbXSbZ4fFGC1/41db/2GOHFgaheMXj0SIWHqQE1jtihr3BBBO4b3Ccz5QCnrn48J\n"
+"8L+QRdh4a/cAx4ty/oHEiXwpSBBSFRl5+y2NijC8GITA5dRjCRWP+Y0zuTrJ7j1a\n"
+"h+3kGs1kxqskhaEuhXnXyknGLjXrU+ewRGhHzP23o5betVhX+c1XjVqmJNZ5OPn/\n"
+"wrqx/XwoIl/3F5lMmGDG9mPtyg0E227nKl9Sy0Vbwx2tu1unjOlzSCa7lpoD4TIX\n"
+"PBJ5+Zb0CE6HEt3V0ec1m4uUe/xObAnzyr4UbzdqLaMy8vTcF/qsncXyPBjwqdjR\n"
+"ReDAtt99bAPY4roPKGt8dgKUPE0t/XoY+SlmUp75TkZDXrOIJXpEW0GpLPf53T+W\n"
+"Ex3KtfLAnZzrw8+dIageY7IgoQ85h3sYE7uEI8QlcO/o4udqUzTp4Sn4sWvdTLrx\n"
+"W7ImvK2rsU5ubVdsEaFKM7+7nxGn2JyMpIWFz0SbP34CkXHhrXxyRD+GhMIDHFxV\n"
+"uBnZnjJsw+ooIm1rL4I7/VMWEwmVegreT6w9Gsmb5igw+zu9v2YBgTOhysA9XZd4\n"
+"7O3VjqKkhTXcBqdpRWuz8gPQ+4rfwij28Gg2alG04Eh3G3868NOCFJhhaHVmwYR2\n"
+"ygRm6N9eDW1bHhYSN75HSEb6aIebk+1AT4S1QtJaPSH0EduIXO++JYAs+jIFKy2c\n"
+"jCVFlO/LbXl7iCdXurJHpSbMNmZFNUri6zEolENODLwke836jBOKiVrWzLnEMxHI\n"
+"WDDTpLTYhR3C7sEprpEQm9SX2Eik3WxVb4ZTb7SZFU1y1d4tWnjGu3U1D+vO9wVq\n"
+"Sss9lDipbkhQ9k4j1/Pqozaxvi8lYLbh3WEjK3Iwpr66Bk6Ai2oRg4b+7vzV4o+6\n"
+"L47JPJhajdHac0CIlmupyA4eejECS6OpoLDf5Wr/616k3dxM//3kAWGUnXVw9GSo\n"
+"UF5W8AaKlaGZ6EZk09NyGSFRjEs18z+g5ckviGF0EhZI7ZPWQQmlqWUsL9O0S4GO\n"
+"ZZ9f0UhNmHEspcugbs7e1yfjwGVyxIBkrmxpkmfHE4Gb47UGlJevg2OvZOPT3wMH\n"
+"vOds2BtqdT3tuss9k+7hsISGse7isEOb7TN5MHb6yyzqnCUZhp5m3Iag7TUkiyfU\n"
+"jKH5R13tHqKUoJ2rofWoLO2H5xSfp/lqF9sLd4rJ+Pbjhiuvfwz5copYsuTNL4kB\n"
+"SPUikHlTxSOgTBYNV77qxpsqOI3+iziCrSqHsxNdlaA1T3fiq6SeZBNdD822AYm9\n"
+"L5hbcgpDPEEwT/n5kWNbRNueerJkJwboaOnT1ZX1601Pwj5QDi+YM1NYy5PsdWxb\n"
+"bPGpQyZ+uf917q9gV7Ykr5cic10YD11khAghr0n6fYfb8Ijc22uP6m47KItDqQc1\n"
+"eFym149F56B0yg5FR85Arg==\n"
+"-----END MESSAGE-----\n"
+" signature Of+jvQKzH9ot2NV5twlDO2CFbzLSB4absWTwG58TCHb+TWgQi3z6SZIoTnGGY/uicJgEkCN++bZZR49GiyHyCQ\n";
diff --git a/src/test/test_hs_intropoint.c b/src/test/test_hs_intropoint.c
new file mode 100644
index 0000000000..b2d2700f8b
--- /dev/null
+++ b/src/test/test_hs_intropoint.c
@@ -0,0 +1,928 @@
+/* Copyright (c) 2016-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file test_hs_service.c
+ * \brief Test hidden service functionality.
+ */
+
+#define HS_SERVICE_PRIVATE
+#define HS_INTROPOINT_PRIVATE
+#define RENDSERVICE_PRIVATE
+#define CIRCUITLIST_PRIVATE
+
+#include "test.h"
+#include "log_test_helpers.h"
+#include "crypto.h"
+#include "log_test_helpers.h"
+
+#include "or.h"
+#include "circuitlist.h"
+#include "circuituse.h"
+#include "ht.h"
+#include "relay.h"
+#include "rendservice.h"
+
+#include "hs_cell.h"
+#include "hs_circuitmap.h"
+#include "hs_common.h"
+#include "hs_intropoint.h"
+#include "hs_service.h"
+
+/* Trunnel. */
+#include "hs/cell_establish_intro.h"
+#include "hs/cell_introduce1.h"
+#include "hs/cell_common.h"
+
+static size_t
+new_establish_intro_cell(const char *circ_nonce,
+ trn_cell_establish_intro_t **cell_out)
+{
+ ssize_t cell_len = 0;
+ uint8_t buf[RELAY_PAYLOAD_SIZE] = {0};
+ trn_cell_establish_intro_t *cell = NULL;
+ hs_service_intro_point_t *ip = NULL;
+
+ /* Ensure that *cell_out is NULL such that we can use to check if we need to
+ * free `cell` in case of an error. */
+ *cell_out = NULL;
+
+ /* Auth key pair is generated in the constructor so we are all set for
+ * using this IP object. */
+ ip = service_intro_point_new(NULL, 0);
+ tt_assert(ip);
+ cell_len = hs_cell_build_establish_intro(circ_nonce, ip, buf);
+ tt_i64_op(cell_len, OP_GT, 0);
+
+ cell_len = trn_cell_establish_intro_parse(&cell, buf, sizeof(buf));
+ tt_i64_op(cell_len, OP_GT, 0);
+ tt_assert(cell);
+ *cell_out = cell;
+
+ done:
+ if (*cell_out == NULL)
+ trn_cell_establish_intro_free(cell);
+
+ service_intro_point_free(ip);
+ return cell_len;
+}
+
+static ssize_t
+new_establish_intro_encoded_cell(const char *circ_nonce, uint8_t *cell_out)
+{
+ ssize_t cell_len = 0;
+ hs_service_intro_point_t *ip = NULL;
+
+ /* Auth key pair is generated in the constructor so we are all set for
+ * using this IP object. */
+ ip = service_intro_point_new(NULL, 0);
+ tt_assert(ip);
+ cell_len = hs_cell_build_establish_intro(circ_nonce, ip, cell_out);
+ tt_i64_op(cell_len, OP_GT, 0);
+
+ done:
+ service_intro_point_free(ip);
+ return cell_len;
+}
+
+/* Mock function to avoid networking in unittests */
+static int
+mock_send_intro_established_cell(or_circuit_t *circ)
+{
+ (void) circ;
+ return 0;
+}
+
+static int
+mock_relay_send_command_from_edge(streamid_t stream_id, circuit_t *circ,
+ uint8_t relay_command, const char *payload,
+ size_t payload_len,
+ crypt_path_t *cpath_layer,
+ const char *filename, int lineno)
+{
+ (void) stream_id;
+ (void) circ;
+ (void) relay_command;
+ (void) payload;
+ (void) payload_len;
+ (void) cpath_layer;
+ (void) filename;
+ (void) lineno;
+ return 0;
+}
+
+static or_circuit_t *
+helper_create_intro_circuit(void)
+{
+ or_circuit_t *circ = or_circuit_new(0, NULL);
+ tt_assert(circ);
+ circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_OR);
+ done:
+ return circ;
+}
+
+static trn_cell_introduce1_t *
+helper_create_introduce1_cell(void)
+{
+ trn_cell_introduce1_t *cell = NULL;
+ ed25519_keypair_t auth_key_kp;
+
+ /* Generate the auth_key of the cell. */
+ if (ed25519_keypair_generate(&auth_key_kp, 0) < 0) {
+ goto err;
+ }
+
+ cell = trn_cell_introduce1_new();
+ tt_assert(cell);
+
+ /* Set the auth key. */
+ {
+ size_t auth_key_len = sizeof(auth_key_kp.pubkey);
+ trn_cell_introduce1_set_auth_key_type(cell,
+ HS_INTRO_AUTH_KEY_TYPE_ED25519);
+ 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. */
+ {
+ 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;
+ 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:
+ trn_cell_introduce1_free(cell);
+ return NULL;
+}
+
+/* Try sending an ESTABLISH_INTRO cell on a circuit that is already an intro
+ * point. Should fail. */
+static void
+test_establish_intro_wrong_purpose(void *arg)
+{
+ int retval;
+ ssize_t cell_len = 0;
+ char circ_nonce[DIGEST_LEN] = {0};
+ uint8_t cell_body[RELAY_PAYLOAD_SIZE];
+ or_circuit_t *intro_circ = or_circuit_new(0,NULL);
+
+ (void)arg;
+
+ /* Get the auth key of the intro point */
+ crypto_rand(circ_nonce, sizeof(circ_nonce));
+ memcpy(intro_circ->rend_circ_nonce, circ_nonce, DIGEST_LEN);
+
+ /* Set a bad circuit purpose!! :) */
+ circuit_change_purpose(TO_CIRCUIT(intro_circ), CIRCUIT_PURPOSE_INTRO_POINT);
+
+ /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we
+ attempt to parse it. */
+ cell_len = new_establish_intro_encoded_cell(circ_nonce, cell_body);
+ tt_i64_op(cell_len, OP_GT, 0);
+
+ /* Receive the cell. Should fail. */
+ setup_full_capture_of_logs(LOG_INFO);
+ retval = hs_intro_received_establish_intro(intro_circ, cell_body, cell_len);
+ expect_log_msg_containing("Rejecting ESTABLISH_INTRO on non-OR circuit.");
+ teardown_capture_of_logs();
+ tt_int_op(retval, OP_EQ, -1);
+
+ done:
+ circuit_free(TO_CIRCUIT(intro_circ));
+}
+
+/* Prepare a circuit for accepting an ESTABLISH_INTRO cell */
+static void
+helper_prepare_circ_for_intro(or_circuit_t *circ, const char *circ_nonce)
+{
+ /* Prepare the circuit for the incoming ESTABLISH_INTRO */
+ circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_OR);
+ memcpy(circ->rend_circ_nonce, circ_nonce, DIGEST_LEN);
+}
+
+/* Send an empty ESTABLISH_INTRO cell. Should fail. */
+static void
+test_establish_intro_wrong_keytype(void *arg)
+{
+ int retval;
+ or_circuit_t *intro_circ = or_circuit_new(0,NULL);
+ char circ_nonce[DIGEST_LEN] = {0};
+
+ (void) arg;
+
+ /* Get the auth key of the intro point */
+ crypto_rand(circ_nonce, sizeof(circ_nonce));
+ helper_prepare_circ_for_intro(intro_circ, circ_nonce);
+
+ /* Receive the cell. Should fail. */
+ setup_full_capture_of_logs(LOG_INFO);
+ retval = hs_intro_received_establish_intro(intro_circ, (uint8_t *) "", 0);
+ expect_log_msg_containing("Empty ESTABLISH_INTRO cell.");
+ teardown_capture_of_logs();
+ tt_int_op(retval, OP_EQ, -1);
+
+ done:
+ circuit_free(TO_CIRCUIT(intro_circ));
+}
+
+/* Send an ESTABLISH_INTRO cell with an unknown auth key type. Should fail. */
+static void
+test_establish_intro_wrong_keytype2(void *arg)
+{
+ int retval;
+ char circ_nonce[DIGEST_LEN] = {0};
+ uint8_t cell_body[RELAY_PAYLOAD_SIZE];
+ ssize_t cell_len = 0;
+ or_circuit_t *intro_circ = or_circuit_new(0,NULL);
+
+ (void) arg;
+
+ /* Get the auth key of the intro point */
+ crypto_rand(circ_nonce, sizeof(circ_nonce));
+ helper_prepare_circ_for_intro(intro_circ, circ_nonce);
+
+ /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we
+ * attempt to parse it. */
+ cell_len = new_establish_intro_encoded_cell(circ_nonce, cell_body);
+ tt_i64_op(cell_len, OP_GT, 0);
+
+ /* Mutate the auth key type! :) */
+ cell_body[0] = 42;
+
+ /* Receive the cell. Should fail. */
+ setup_full_capture_of_logs(LOG_INFO);
+ retval = hs_intro_received_establish_intro(intro_circ, cell_body, cell_len);
+ expect_log_msg_containing("Unrecognized AUTH_KEY_TYPE 42.");
+ teardown_capture_of_logs();
+ tt_int_op(retval, OP_EQ, -1);
+
+ done:
+ circuit_free(TO_CIRCUIT(intro_circ));
+}
+
+/* Send a legit ESTABLISH_INTRO cell but with a wrong MAC. Should fail. */
+static void
+test_establish_intro_wrong_mac(void *arg)
+{
+ int retval;
+ char circ_nonce[DIGEST_LEN] = {0};
+ ssize_t cell_len = 0;
+ uint8_t cell_body[RELAY_PAYLOAD_SIZE];
+ trn_cell_establish_intro_t *cell = NULL;
+ or_circuit_t *intro_circ = or_circuit_new(0,NULL);
+
+ (void) arg;
+
+ /* Get the auth key of the intro point */
+ crypto_rand(circ_nonce, sizeof(circ_nonce));
+ helper_prepare_circ_for_intro(intro_circ, circ_nonce);
+
+ /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we
+ * attempt to parse it. */
+ cell_len = new_establish_intro_cell(circ_nonce, &cell);
+ tt_i64_op(cell_len, OP_GT, 0);
+ tt_assert(cell);
+
+ /* Mangle one byte of the MAC. */
+ uint8_t *handshake_ptr =
+ trn_cell_establish_intro_getarray_handshake_mac(cell);
+ handshake_ptr[TRUNNEL_SHA3_256_LEN - 1]++;
+ /* We need to resign the payload with that change. */
+ {
+ ed25519_signature_t sig;
+ ed25519_keypair_t key_struct;
+ /* New keypair for the signature since we don't have access to the private
+ * key material generated earlier when creating the cell. */
+ retval = ed25519_keypair_generate(&key_struct, 0);
+ tt_int_op(retval, OP_EQ, 0);
+ uint8_t *auth_key_ptr =
+ trn_cell_establish_intro_getarray_auth_key(cell);
+ memcpy(auth_key_ptr, key_struct.pubkey.pubkey, ED25519_PUBKEY_LEN);
+ /* Encode payload so we can sign it. */
+ cell_len = trn_cell_establish_intro_encode(cell_body, sizeof(cell_body),
+ cell);
+ tt_i64_op(cell_len, OP_GT, 0);
+
+ retval = ed25519_sign_prefixed(&sig, cell_body,
+ cell_len -
+ (ED25519_SIG_LEN + sizeof(cell->sig_len)),
+ ESTABLISH_INTRO_SIG_PREFIX, &key_struct);
+ tt_int_op(retval, OP_EQ, 0);
+ /* And write the signature to the cell */
+ uint8_t *sig_ptr =
+ trn_cell_establish_intro_getarray_sig(cell);
+ memcpy(sig_ptr, sig.sig, cell->sig_len);
+ /* Re-encode with the new signature. */
+ cell_len = trn_cell_establish_intro_encode(cell_body, sizeof(cell_body),
+ cell);
+ tt_i64_op(cell_len, OP_GT, 0);
+ }
+
+ /* Receive the cell. Should fail because our MAC is wrong. */
+ setup_full_capture_of_logs(LOG_INFO);
+ retval = hs_intro_received_establish_intro(intro_circ, cell_body, cell_len);
+ expect_log_msg_containing("ESTABLISH_INTRO handshake_auth not as expected");
+ teardown_capture_of_logs();
+ tt_int_op(retval, OP_EQ, -1);
+
+ done:
+ trn_cell_establish_intro_free(cell);
+ circuit_free(TO_CIRCUIT(intro_circ));
+}
+
+/* Send a legit ESTABLISH_INTRO cell but with a wrong auth key length. Should
+ * fail. */
+static void
+test_establish_intro_wrong_auth_key_len(void *arg)
+{
+ int retval;
+ char circ_nonce[DIGEST_LEN] = {0};
+ uint8_t cell_body[RELAY_PAYLOAD_SIZE];
+ ssize_t cell_len = 0;
+ size_t bad_auth_key_len = ED25519_PUBKEY_LEN - 1;
+ trn_cell_establish_intro_t *cell = NULL;
+ or_circuit_t *intro_circ = or_circuit_new(0,NULL);
+
+ (void) arg;
+
+ /* Get the auth key of the intro point */
+ crypto_rand(circ_nonce, sizeof(circ_nonce));
+ helper_prepare_circ_for_intro(intro_circ, circ_nonce);
+
+ /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we
+ * attempt to parse it. */
+ cell_len = new_establish_intro_cell(circ_nonce, &cell);
+ tt_i64_op(cell_len, OP_GT, 0);
+ tt_assert(cell);
+
+ /* Mangle the auth key length. */
+ trn_cell_establish_intro_set_auth_key_len(cell, bad_auth_key_len);
+ trn_cell_establish_intro_setlen_auth_key(cell, bad_auth_key_len);
+ /* Encode cell. */
+ cell_len = trn_cell_establish_intro_encode(cell_body, sizeof(cell_body),
+ cell);
+ tt_int_op(cell_len, OP_GT, 0);
+
+ /* Receive the cell. Should fail. */
+ setup_full_capture_of_logs(LOG_INFO);
+ retval = hs_intro_received_establish_intro(intro_circ, cell_body, cell_len);
+ expect_log_msg_containing("ESTABLISH_INTRO auth key length is invalid");
+ teardown_capture_of_logs();
+ tt_int_op(retval, OP_EQ, -1);
+
+ done:
+ trn_cell_establish_intro_free(cell);
+ circuit_free(TO_CIRCUIT(intro_circ));
+}
+
+/* Send a legit ESTABLISH_INTRO cell but with a wrong sig length. Should
+ * fail. */
+static void
+test_establish_intro_wrong_sig_len(void *arg)
+{
+ int retval;
+ char circ_nonce[DIGEST_LEN] = {0};
+ uint8_t cell_body[RELAY_PAYLOAD_SIZE];
+ ssize_t cell_len = 0;
+ size_t bad_sig_len = ED25519_SIG_LEN - 1;
+ trn_cell_establish_intro_t *cell = NULL;
+ or_circuit_t *intro_circ = or_circuit_new(0,NULL);
+
+ (void) arg;
+
+ /* Get the auth key of the intro point */
+ crypto_rand(circ_nonce, sizeof(circ_nonce));
+ helper_prepare_circ_for_intro(intro_circ, circ_nonce);
+
+ /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we
+ * attempt to parse it. */
+ cell_len = new_establish_intro_cell(circ_nonce, &cell);
+ tt_i64_op(cell_len, OP_GT, 0);
+ tt_assert(cell);
+
+ /* Mangle the signature length. */
+ trn_cell_establish_intro_set_sig_len(cell, bad_sig_len);
+ trn_cell_establish_intro_setlen_sig(cell, bad_sig_len);
+ /* Encode cell. */
+ cell_len = trn_cell_establish_intro_encode(cell_body, sizeof(cell_body),
+ cell);
+ tt_int_op(cell_len, OP_GT, 0);
+
+ /* Receive the cell. Should fail. */
+ setup_full_capture_of_logs(LOG_INFO);
+ retval = hs_intro_received_establish_intro(intro_circ, cell_body, cell_len);
+ expect_log_msg_containing("ESTABLISH_INTRO sig len is invalid");
+ teardown_capture_of_logs();
+ tt_int_op(retval, OP_EQ, -1);
+
+ done:
+ trn_cell_establish_intro_free(cell);
+ circuit_free(TO_CIRCUIT(intro_circ));
+}
+
+/* Send a legit ESTABLISH_INTRO cell but slightly change the signature. Should
+ * fail. */
+static void
+test_establish_intro_wrong_sig(void *arg)
+{
+ int retval;
+ char circ_nonce[DIGEST_LEN] = {0};
+ uint8_t cell_body[RELAY_PAYLOAD_SIZE];
+ ssize_t cell_len = 0;
+ or_circuit_t *intro_circ = or_circuit_new(0,NULL);
+
+ (void) arg;
+
+ /* Get the auth key of the intro point */
+ crypto_rand(circ_nonce, sizeof(circ_nonce));
+ helper_prepare_circ_for_intro(intro_circ, circ_nonce);
+
+ /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we
+ attempt to parse it. */
+ cell_len = new_establish_intro_encoded_cell(circ_nonce, cell_body);
+ tt_i64_op(cell_len, OP_GT, 0);
+
+ /* Mutate the last byte (signature)! :) */
+ cell_body[cell_len - 1]++;
+
+ /* Receive the cell. Should fail. */
+ setup_full_capture_of_logs(LOG_INFO);
+ retval = hs_intro_received_establish_intro(intro_circ, cell_body,
+ (size_t)cell_len);
+ expect_log_msg_containing("Failed to verify ESTABLISH_INTRO cell.");
+ teardown_capture_of_logs();
+ tt_int_op(retval, OP_EQ, -1);
+
+ done:
+ 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 trn_cell_establish_intro_t *
+helper_establish_intro_v3(or_circuit_t *intro_circ)
+{
+ int retval;
+ char circ_nonce[DIGEST_LEN] = {0};
+ uint8_t cell_body[RELAY_PAYLOAD_SIZE];
+ ssize_t cell_len = 0;
+ trn_cell_establish_intro_t *cell = NULL;
+
+ tt_assert(intro_circ);
+
+ /* Prepare the circuit for the incoming ESTABLISH_INTRO */
+ crypto_rand(circ_nonce, sizeof(circ_nonce));
+ helper_prepare_circ_for_intro(intro_circ, circ_nonce);
+
+ /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we
+ * attempt to parse it. */
+ cell_len = new_establish_intro_cell(circ_nonce, &cell);
+ tt_i64_op(cell_len, OP_GT, 0);
+ tt_assert(cell);
+ cell_len = trn_cell_establish_intro_encode(cell_body, sizeof(cell_body),
+ cell);
+ tt_int_op(cell_len, OP_GT, 0);
+
+ /* Receive the cell */
+ retval = hs_intro_received_establish_intro(intro_circ, cell_body,
+ (size_t) cell_len);
+ tt_int_op(retval, OP_EQ, 0);
+
+ done:
+ return cell;
+}
+
+/* Helper function: Send a well-formed v2 ESTABLISH_INTRO cell to
+ * <b>intro_circ</b>. Return the public key advertised in the cell. */
+static crypto_pk_t *
+helper_establish_intro_v2(or_circuit_t *intro_circ)
+{
+ crypto_pk_t *key1 = NULL;
+ int retval;
+ uint8_t cell_body[RELAY_PAYLOAD_SIZE];
+ ssize_t cell_len = 0;
+ char circ_nonce[DIGEST_LEN] = {0};
+
+ tt_assert(intro_circ);
+
+ /* Prepare the circuit for the incoming ESTABLISH_INTRO */
+ crypto_rand(circ_nonce, sizeof(circ_nonce));
+ helper_prepare_circ_for_intro(intro_circ, circ_nonce);
+
+ /* Send legacy establish_intro */
+ key1 = pk_generate(0);
+
+ /* Use old circ_nonce why not */
+ cell_len = rend_service_encode_establish_intro_cell(
+ (char*)cell_body,
+ sizeof(cell_body), key1,
+ circ_nonce);
+ tt_int_op(cell_len, OP_GT, 0);
+
+ /* Receive legacy establish_intro */
+ retval = hs_intro_received_establish_intro(intro_circ,
+ cell_body, (size_t) cell_len);
+ tt_int_op(retval, OP_EQ, 0);
+
+ done:
+ return key1;
+}
+
+/* Helper function: test circuitmap free_all function outside of
+ * test_intro_point_registration to prevent Coverity from seeing a
+ * double free if the assertion hypothetically fails.
+ */
+static void
+test_circuitmap_free_all(void)
+{
+ hs_circuitmap_ht *the_hs_circuitmap = NULL;
+
+ the_hs_circuitmap = get_hs_circuitmap();
+ tt_assert(the_hs_circuitmap);
+ hs_circuitmap_free_all();
+ the_hs_circuitmap = get_hs_circuitmap();
+ tt_ptr_op(the_hs_circuitmap, OP_EQ, NULL);
+ done:
+ ;
+}
+
+/** Successfuly register a v2 intro point and a v3 intro point. Ensure that HS
+ * circuitmap is maintained properly. */
+static void
+test_intro_point_registration(void *arg)
+{
+ int retval;
+ hs_circuitmap_ht *the_hs_circuitmap = NULL;
+
+ or_circuit_t *intro_circ = NULL;
+ trn_cell_establish_intro_t *establish_intro_cell = NULL;
+ ed25519_public_key_t auth_key;
+
+ crypto_pk_t *legacy_auth_key = NULL;
+ or_circuit_t *legacy_intro_circ = NULL;
+
+ or_circuit_t *returned_intro_circ = NULL;
+
+ (void) arg;
+
+ MOCK(hs_intro_send_intro_established_cell, mock_send_intro_established_cell);
+
+ hs_circuitmap_init();
+
+ /* Check that the circuitmap is currently empty */
+ {
+ the_hs_circuitmap = get_hs_circuitmap();
+ tt_assert(the_hs_circuitmap);
+ tt_int_op(0, OP_EQ, HT_SIZE(the_hs_circuitmap));
+ /* Do a circuitmap query in any case */
+ returned_intro_circ =hs_circuitmap_get_intro_circ_v3_relay_side(&auth_key);
+ tt_ptr_op(returned_intro_circ, OP_EQ, NULL);
+ }
+
+ /* Create a v3 intro point */
+ {
+ intro_circ = or_circuit_new(0, NULL);
+ tt_assert(intro_circ);
+ establish_intro_cell = helper_establish_intro_v3(intro_circ);
+
+ /* Check that the intro point was registered on the HS circuitmap */
+ the_hs_circuitmap = get_hs_circuitmap();
+ tt_assert(the_hs_circuitmap);
+ tt_int_op(1, OP_EQ, 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_relay_side(&auth_key);
+ tt_ptr_op(intro_circ, OP_EQ, returned_intro_circ);
+ }
+
+ /* Create a v2 intro point */
+ {
+ char key_digest[DIGEST_LEN];
+
+ legacy_intro_circ = or_circuit_new(1, NULL);
+ tt_assert(legacy_intro_circ);
+ legacy_auth_key = helper_establish_intro_v2(legacy_intro_circ);
+ tt_assert(legacy_auth_key);
+
+ /* Check that the circuitmap now has two elements */
+ the_hs_circuitmap = get_hs_circuitmap();
+ tt_assert(the_hs_circuitmap);
+ tt_int_op(2, OP_EQ, HT_SIZE(the_hs_circuitmap));
+
+ /* Check that the new element is our legacy intro circuit. */
+ retval = crypto_pk_get_digest(legacy_auth_key, key_digest);
+ tt_int_op(retval, OP_EQ, 0);
+ returned_intro_circ =
+ hs_circuitmap_get_intro_circ_v2_relay_side((uint8_t*)key_digest);
+ tt_ptr_op(legacy_intro_circ, OP_EQ, returned_intro_circ);
+ }
+
+ /* XXX Continue test and try to register a second v3 intro point with the
+ * same auth key. Make sure that old intro circuit gets closed. */
+
+ done:
+ crypto_pk_free(legacy_auth_key);
+ circuit_free(TO_CIRCUIT(intro_circ));
+ circuit_free(TO_CIRCUIT(legacy_intro_circ));
+ trn_cell_establish_intro_free(establish_intro_cell);
+ test_circuitmap_free_all();
+
+ UNMOCK(hs_intro_send_intro_established_cell);
+}
+
+static void
+test_introduce1_suitable_circuit(void *arg)
+{
+ int ret;
+ or_circuit_t *circ = NULL;
+
+ (void) arg;
+
+ /* Valid suitable circuit. */
+ {
+ circ = or_circuit_new(0, NULL);
+ circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_OR);
+ ret = circuit_is_suitable_for_introduce1(circ);
+ circuit_free(TO_CIRCUIT(circ));
+ tt_int_op(ret, OP_EQ, 1);
+ }
+
+ /* Test if the circuit purpose safeguard works correctly. */
+ {
+ circ = or_circuit_new(0, NULL);
+ circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_INTRO_POINT);
+ ret = circuit_is_suitable_for_introduce1(circ);
+ circuit_free(TO_CIRCUIT(circ));
+ tt_int_op(ret, OP_EQ, 0);
+ }
+
+ /* Test the non-edge circuit safeguard works correctly. */
+ {
+ circ = or_circuit_new(0, NULL);
+ circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_OR);
+ /* Bogus pointer, the check is against NULL on n_chan. */
+ circ->base_.n_chan = (channel_t *) circ;
+ ret = circuit_is_suitable_for_introduce1(circ);
+ circuit_free(TO_CIRCUIT(circ));
+ tt_int_op(ret, OP_EQ, 0);
+ }
+
+ /* Mangle the circuit a bit more so see if our only one INTRODUCE1 cell
+ * limit works correctly. */
+ {
+ circ = or_circuit_new(0, NULL);
+ circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_OR);
+ circ->already_received_introduce1 = 1;
+ ret = circuit_is_suitable_for_introduce1(circ);
+ circuit_free(TO_CIRCUIT(circ));
+ tt_int_op(ret, OP_EQ, 0);
+ }
+
+ done:
+ ;
+}
+
+static void
+test_introduce1_is_legacy(void *arg)
+{
+ int ret;
+ uint8_t request[256];
+
+ (void) arg;
+
+ /* For a cell to be considered legacy, according to the specification, the
+ * first 20 bytes MUST BE non-zero else it's a v3 cell. */
+ memset(request, 'a', DIGEST_LEN);
+ memset(request + DIGEST_LEN, 0, sizeof(request) - DIGEST_LEN);
+ ret = introduce1_cell_is_legacy(request);
+ tt_int_op(ret, OP_EQ, 1);
+
+ /* This is a NON legacy cell. */
+ memset(request, 0, DIGEST_LEN);
+ memset(request + DIGEST_LEN, 'a', sizeof(request) - DIGEST_LEN);
+ ret = introduce1_cell_is_legacy(request);
+ tt_int_op(ret, OP_EQ, 0);
+
+ done:
+ ;
+}
+
+static void
+test_introduce1_validation(void *arg)
+{
+ int ret;
+ trn_cell_introduce1_t *cell = NULL;
+
+ (void) arg;
+
+ /* Create our decoy cell that we'll modify as we go to test the validation
+ * function of that parsed cell. */
+ cell = helper_create_introduce1_cell();
+
+ /* It should NOT be a legacy cell which will trigger a BUG(). */
+ memset(cell->legacy_key_id, 'a', sizeof(cell->legacy_key_id));
+ tor_capture_bugs_(1);
+ ret = validate_introduce1_parsed_cell(cell);
+ tor_end_capture_bugs_();
+ tt_int_op(ret, OP_EQ, -1);
+ /* Reset legacy ID and make sure it's correct. */
+ memset(cell->legacy_key_id, 0, sizeof(cell->legacy_key_id));
+ ret = validate_introduce1_parsed_cell(cell);
+ tt_int_op(ret, OP_EQ, 0);
+
+ /* Non existing auth key type. */
+ cell->auth_key_type = 42;
+ ret = validate_introduce1_parsed_cell(cell);
+ tt_int_op(ret, OP_EQ, -1);
+ /* Reset is to correct value and make sure it's correct. */
+ cell->auth_key_type = HS_INTRO_AUTH_KEY_TYPE_ED25519;
+ ret = validate_introduce1_parsed_cell(cell);
+ tt_int_op(ret, OP_EQ, 0);
+
+ /* Really bad key length. */
+ cell->auth_key_len = 0;
+ ret = validate_introduce1_parsed_cell(cell);
+ tt_int_op(ret, OP_EQ, -1);
+ cell->auth_key_len = UINT16_MAX;
+ ret = validate_introduce1_parsed_cell(cell);
+ tt_int_op(ret, OP_EQ, -1);
+ /* Correct size, let's try that. */
+ cell->auth_key_len = sizeof(ed25519_public_key_t);
+ ret = validate_introduce1_parsed_cell(cell);
+ tt_int_op(ret, OP_EQ, 0);
+ /* Set an invalid size of the auth key buffer. */
+ 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. */
+ 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. */
+ 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. */
+ trn_cell_introduce1_setlen_encrypted(cell, 1);
+ ret = validate_introduce1_parsed_cell(cell);
+ tt_int_op(ret, OP_EQ, 0);
+
+ done:
+ trn_cell_introduce1_free(cell);
+}
+
+static void
+test_received_introduce1_handling(void *arg)
+{
+ int ret;
+ uint8_t *request = NULL, buf[128];
+ trn_cell_introduce1_t *cell = NULL;
+ or_circuit_t *circ = NULL;
+
+ (void) arg;
+
+ MOCK(relay_send_command_from_edge_, mock_relay_send_command_from_edge);
+
+ hs_circuitmap_init();
+
+ /* Too small request length. An INTRODUCE1 expect at the very least a
+ * DIGEST_LEN size. */
+ {
+ memset(buf, 0, sizeof(buf));
+ circ = helper_create_intro_circuit();
+ ret = hs_intro_received_introduce1(circ, buf, DIGEST_LEN - 1);
+ tt_int_op(ret, OP_EQ, -1);
+ circuit_free(TO_CIRCUIT(circ));
+ }
+
+ /* We have a unit test only for the suitability of a circuit to receive an
+ * INTRODUCE1 cell so from now on we'll only test the handling of a cell. */
+
+ /* Bad request. */
+ {
+ circ = helper_create_intro_circuit();
+ uint8_t test[2]; /* Too small request. */
+ memset(test, 0, sizeof(test));
+ ret = handle_introduce1(circ, test, sizeof(test));
+ tor_free(circ->p_chan);
+ circuit_free(TO_CIRCUIT(circ));
+ tt_int_op(ret, OP_EQ, -1);
+ }
+
+ /* Valid case. */
+ {
+ cell = helper_create_introduce1_cell();
+ 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 =
+ 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();
+ circuit_change_purpose(TO_CIRCUIT(service_circ),
+ CIRCUIT_PURPOSE_INTRO_POINT);
+ /* 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 =
+ trn_cell_introduce1_getconstarray_auth_key(cell);
+ memcpy(auth_key.pubkey, cell_auth_key, ED25519_PUBKEY_LEN);
+ 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));
+ tt_int_op(ret, OP_EQ, 0);
+ }
+
+ /* Valid legacy cell. */
+ {
+ tor_free(request);
+ trn_cell_introduce1_free(cell);
+ cell = helper_create_introduce1_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 = 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 =
+ 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();
+ circuit_change_purpose(TO_CIRCUIT(service_circ),
+ CIRCUIT_PURPOSE_INTRO_POINT);
+ /* 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_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));
+ tt_int_op(ret, OP_EQ, 0);
+ }
+
+ done:
+ trn_cell_introduce1_free(cell);
+ tor_free(request);
+ hs_circuitmap_free_all();
+ UNMOCK(relay_send_command_from_edge_);
+}
+
+struct testcase_t hs_intropoint_tests[] = {
+ { "intro_point_registration",
+ test_intro_point_registration, TT_FORK, NULL, NULL },
+
+ { "receive_establish_intro_wrong_keytype",
+ test_establish_intro_wrong_keytype, TT_FORK, NULL, NULL },
+
+ { "receive_establish_intro_wrong_keytype2",
+ test_establish_intro_wrong_keytype2, TT_FORK, NULL, NULL },
+
+ { "receive_establish_intro_wrong_purpose",
+ test_establish_intro_wrong_purpose, TT_FORK, NULL, NULL },
+
+ { "receive_establish_intro_wrong_sig",
+ test_establish_intro_wrong_sig, TT_FORK, NULL, NULL },
+
+ { "receive_establish_intro_wrong_sig_len",
+ test_establish_intro_wrong_sig_len, TT_FORK, NULL, NULL },
+
+ { "receive_establish_intro_wrong_auth_key_len",
+ test_establish_intro_wrong_auth_key_len, TT_FORK, NULL, NULL },
+
+ { "receive_establish_intro_wrong_mac",
+ test_establish_intro_wrong_mac, TT_FORK, NULL, NULL },
+
+ { "introduce1_suitable_circuit",
+ test_introduce1_suitable_circuit, TT_FORK, NULL, NULL },
+
+ { "introduce1_is_legacy",
+ test_introduce1_is_legacy, TT_FORK, NULL, NULL },
+
+ { "introduce1_validation",
+ test_introduce1_validation, TT_FORK, NULL, NULL },
+
+ { "received_introduce1_handling",
+ test_received_introduce1_handling, TT_FORK, NULL, NULL },
+
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_hs_ntor.c b/src/test/test_hs_ntor.c
new file mode 100644
index 0000000000..8eee54d4b4
--- /dev/null
+++ b/src/test/test_hs_ntor.c
@@ -0,0 +1,114 @@
+/* Copyright (c) 2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file test_hs_ntor.c
+ * \brief Test hidden service ntor functionality.
+ */
+
+#include "test.h"
+#include "test_helpers.h"
+#include "log_test_helpers.h"
+
+#include "hs_ntor.h"
+
+/* 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, OP_EQ, 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, OP_EQ, 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, OP_EQ, 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, OP_EQ, 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:
+ ;
+}
+
+struct testcase_t hs_ntor_tests[] = {
+ { "hs_ntor", test_hs_ntor, TT_FORK,
+ NULL, NULL },
+
+ END_OF_TESTCASES
+};
+
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
new file mode 100644
index 0000000000..d040f10e0c
--- /dev/null
+++ b/src/test/test_hs_service.c
@@ -0,0 +1,1625 @@
+/* Copyright (c) 2016-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file test_hs_service.c
+ * \brief Test hidden service functionality.
+ */
+
+#define CIRCUITBUILD_PRIVATE
+#define CIRCUITLIST_PRIVATE
+#define CONFIG_PRIVATE
+#define CONNECTION_PRIVATE
+#define CRYPTO_PRIVATE
+#define HS_COMMON_PRIVATE
+#define HS_SERVICE_PRIVATE
+#define HS_INTROPOINT_PRIVATE
+#define HS_CIRCUIT_PRIVATE
+#define MAIN_PRIVATE
+#define NETWORKSTATUS_PRIVATE
+#define STATEFILE_PRIVATE
+#define TOR_CHANNEL_INTERNAL_
+#define HS_CLIENT_PRIVATE
+
+#include "test.h"
+#include "test_helpers.h"
+#include "log_test_helpers.h"
+#include "rend_test_helpers.h"
+#include "hs_test_helpers.h"
+
+#include "or.h"
+#include "config.h"
+#include "circuitbuild.h"
+#include "circuitlist.h"
+#include "circuituse.h"
+#include "crypto.h"
+#include "dirvote.h"
+#include "networkstatus.h"
+#include "nodelist.h"
+#include "relay.h"
+
+#include "hs_common.h"
+#include "hs_config.h"
+#include "hs_ident.h"
+#include "hs_intropoint.h"
+#include "hs_ntor.h"
+#include "hs_circuit.h"
+#include "hs_service.h"
+#include "hs_client.h"
+#include "main.h"
+#include "rendservice.h"
+#include "statefile.h"
+#include "shared_random_state.h"
+
+/* Trunnel */
+#include "hs/cell_establish_intro.h"
+
+static networkstatus_t mock_ns;
+
+static networkstatus_t *
+mock_networkstatus_get_live_consensus(time_t now)
+{
+ (void) now;
+ return &mock_ns;
+}
+
+static or_state_t *dummy_state = NULL;
+
+/* Mock function to get fake or state (used for rev counters) */
+static or_state_t *
+get_or_state_replacement(void)
+{
+ return dummy_state;
+}
+
+/* Mock function because we are not trying to test the close circuit that does
+ * an awful lot of checks on the circuit object. */
+static void
+mock_circuit_mark_for_close(circuit_t *circ, int reason, int line,
+ const char *file)
+{
+ (void) circ;
+ (void) reason;
+ (void) line;
+ (void) file;
+ return;
+}
+
+static int
+mock_relay_send_command_from_edge(streamid_t stream_id, circuit_t *circ,
+ uint8_t relay_command, const char *payload,
+ size_t payload_len,
+ crypt_path_t *cpath_layer,
+ const char *filename, int lineno)
+{
+ (void) stream_id;
+ (void) circ;
+ (void) relay_command;
+ (void) payload;
+ (void) payload_len;
+ (void) cpath_layer;
+ (void) filename;
+ (void) lineno;
+ return 0;
+}
+
+/* Helper: from a set of options in conf, configure a service which will add
+ * it to the staging list of the HS subsytem. */
+static int
+helper_config_service(const char *conf)
+{
+ int ret = 0;
+ or_options_t *options = NULL;
+ tt_assert(conf);
+ options = helper_parse_options(conf);
+ tt_assert(options);
+ ret = hs_config_service_all(options, 0);
+ done:
+ or_options_free(options);
+ return ret;
+}
+
+/* Test: Ensure that setting up rendezvous circuits works correctly. */
+static void
+test_e2e_rend_circuit_setup(void *arg)
+{
+ ed25519_public_key_t service_pk;
+ origin_circuit_t *or_circ;
+ int retval;
+
+ /** In this test we create a v3 prop224 service-side rendezvous circuit.
+ * We simulate an HS ntor key exchange with a client, and check that
+ * the circuit was setup correctly and is ready to accept rendezvous data */
+
+ (void) arg;
+
+ /* Now make dummy circuit */
+ {
+ or_circ = origin_circuit_new();
+
+ or_circ->base_.purpose = CIRCUIT_PURPOSE_S_CONNECT_REND;
+
+ or_circ->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
+ or_circ->build_state->is_internal = 1;
+
+ /* prop224: Setup hs conn identifier on the stream */
+ ed25519_secret_key_t sk;
+ tt_int_op(0, OP_EQ, ed25519_secret_key_generate(&sk, 0));
+ tt_int_op(0, OP_EQ, ed25519_public_key_generate(&service_pk, &sk));
+
+ or_circ->hs_ident = hs_ident_circuit_new(&service_pk,
+ HS_IDENT_CIRCUIT_RENDEZVOUS);
+
+ TO_CIRCUIT(or_circ)->state = CIRCUIT_STATE_OPEN;
+ }
+
+ /* Check number of hops */
+ retval = cpath_get_n_hops(&or_circ->cpath);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /* Setup the circuit: do the ntor key exchange */
+ {
+ uint8_t ntor_key_seed[DIGEST256_LEN] = {2};
+ retval = hs_circuit_setup_e2e_rend_circ(or_circ,
+ ntor_key_seed, sizeof(ntor_key_seed),
+ 1);
+ tt_int_op(retval, OP_EQ, 0);
+ }
+
+ /* See that a hop was added to the circuit's cpath */
+ retval = cpath_get_n_hops(&or_circ->cpath);
+ tt_int_op(retval, OP_EQ, 1);
+
+ /* Check the digest algo */
+ tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->f_digest),
+ OP_EQ, DIGEST_SHA3_256);
+ tt_int_op(crypto_digest_get_algorithm(or_circ->cpath->b_digest),
+ OP_EQ, DIGEST_SHA3_256);
+ tt_assert(or_circ->cpath->f_crypto);
+ tt_assert(or_circ->cpath->b_crypto);
+
+ /* Ensure that circ purpose was changed */
+ tt_int_op(or_circ->base_.purpose, OP_EQ, CIRCUIT_PURPOSE_S_REND_JOINED);
+
+ done:
+ circuit_free(TO_CIRCUIT(or_circ));
+}
+
+/* Helper: Return a newly allocated and initialized origin circuit with
+ * purpose and flags. A default HS identifier is set to an ed25519
+ * authentication key for introduction point. */
+static origin_circuit_t *
+helper_create_origin_circuit(int purpose, int flags)
+{
+ origin_circuit_t *circ = NULL;
+
+ circ = origin_circuit_init(purpose, flags);
+ tt_assert(circ);
+ circ->cpath = tor_malloc_zero(sizeof(crypt_path_t));
+ circ->cpath->magic = CRYPT_PATH_MAGIC;
+ circ->cpath->state = CPATH_STATE_OPEN;
+ circ->cpath->package_window = circuit_initial_package_window();
+ circ->cpath->deliver_window = CIRCWINDOW_START;
+ circ->cpath->prev = circ->cpath;
+ /* Random nonce. */
+ crypto_rand(circ->cpath->prev->rend_circ_nonce, DIGEST_LEN);
+ /* Create a default HS identifier. */
+ circ->hs_ident = tor_malloc_zero(sizeof(hs_ident_circuit_t));
+
+ done:
+ return circ;
+}
+
+/* Helper: Return a newly allocated service object with the identity keypair
+ * sets and the current descriptor. Then register it to the global map.
+ * Caller should us hs_free_all() to free this service or remove it from the
+ * global map before freeing. */
+static hs_service_t *
+helper_create_service(void)
+{
+ /* Set a service for this circuit. */
+ hs_service_t *service = hs_service_new(get_options());
+ tt_assert(service);
+ service->config.version = HS_VERSION_THREE;
+ ed25519_secret_key_generate(&service->keys.identity_sk, 0);
+ ed25519_public_key_generate(&service->keys.identity_pk,
+ &service->keys.identity_sk);
+ service->desc_current = service_descriptor_new();
+ tt_assert(service->desc_current);
+ /* Register service to global map. */
+ int ret = register_service(get_hs_service_map(), service);
+ tt_int_op(ret, OP_EQ, 0);
+
+ done:
+ return service;
+}
+
+/* Helper: Return a newly allocated service intro point with two link
+ * specifiers, one IPv4 and one legacy ID set to As. */
+static hs_service_intro_point_t *
+helper_create_service_ip(void)
+{
+ hs_desc_link_specifier_t *ls;
+ hs_service_intro_point_t *ip = service_intro_point_new(NULL, 0);
+ tt_assert(ip);
+ /* Add a first unused link specifier. */
+ ls = tor_malloc_zero(sizeof(*ls));
+ ls->type = LS_IPV4;
+ smartlist_add(ip->base.link_specifiers, ls);
+ /* Add a second link specifier used by a test. */
+ ls = tor_malloc_zero(sizeof(*ls));
+ ls->type = LS_LEGACY_ID;
+ memset(ls->u.legacy_id, 'A', sizeof(ls->u.legacy_id));
+ smartlist_add(ip->base.link_specifiers, ls);
+
+ done:
+ return ip;
+}
+
+static void
+test_load_keys(void *arg)
+{
+ int ret;
+ char *conf = NULL;
+ char *hsdir_v2 = tor_strdup(get_fname("hs2"));
+ char *hsdir_v3 = tor_strdup(get_fname("hs3"));
+ char addr[HS_SERVICE_ADDR_LEN_BASE32 + 1];
+
+ (void) arg;
+
+ /* We'll register two services, a v2 and a v3, then we'll load keys and
+ * validate that both are in a correct state. */
+
+ hs_init();
+
+#define conf_fmt \
+ "HiddenServiceDir %s\n" \
+ "HiddenServiceVersion %d\n" \
+ "HiddenServicePort 65535\n"
+
+ /* v2 service. */
+ tor_asprintf(&conf, conf_fmt, hsdir_v2, HS_VERSION_TWO);
+ ret = helper_config_service(conf);
+ tor_free(conf);
+ tt_int_op(ret, OP_EQ, 0);
+ /* This one should now be registered into the v2 list. */
+ tt_int_op(get_hs_service_staging_list_size(), OP_EQ, 0);
+ tt_int_op(rend_num_services(), OP_EQ, 1);
+
+ /* v3 service. */
+ tor_asprintf(&conf, conf_fmt, hsdir_v3, HS_VERSION_THREE);
+ ret = helper_config_service(conf);
+ tor_free(conf);
+ tt_int_op(ret, OP_EQ, 0);
+ /* It's in staging? */
+ tt_int_op(get_hs_service_staging_list_size(), OP_EQ, 1);
+
+ /* Load the keys for these. After that, the v3 service should be registered
+ * in the global map. */
+ hs_service_load_all_keys();
+ tt_int_op(get_hs_service_map_size(), OP_EQ, 1);
+ hs_service_t *s = get_first_service();
+ tt_assert(s);
+
+ /* Ok we have the service object. Validate few things. */
+ tt_assert(!tor_mem_is_zero(s->onion_address, sizeof(s->onion_address)));
+ tt_int_op(hs_address_is_valid(s->onion_address), OP_EQ, 1);
+ tt_assert(!tor_mem_is_zero((char *) s->keys.identity_sk.seckey,
+ ED25519_SECKEY_LEN));
+ tt_assert(!tor_mem_is_zero((char *) s->keys.identity_pk.pubkey,
+ ED25519_PUBKEY_LEN));
+ /* Check onion address from identity key. */
+ hs_build_address(&s->keys.identity_pk, s->config.version, addr);
+ tt_int_op(hs_address_is_valid(addr), OP_EQ, 1);
+ tt_str_op(addr, OP_EQ, s->onion_address);
+
+ done:
+ tor_free(hsdir_v2);
+ tor_free(hsdir_v3);
+ hs_free_all();
+}
+
+static void
+test_access_service(void *arg)
+{
+ int ret;
+ char *conf = NULL;
+ char *hsdir_v3 = tor_strdup(get_fname("hs3"));
+ hs_service_ht *global_map;
+ hs_service_t *s = NULL;
+
+ (void) arg;
+
+ /* We'll register two services, a v2 and a v3, then we'll load keys and
+ * validate that both are in a correct state. */
+
+ hs_init();
+
+#define conf_fmt \
+ "HiddenServiceDir %s\n" \
+ "HiddenServiceVersion %d\n" \
+ "HiddenServicePort 65535\n"
+
+ /* v3 service. */
+ tor_asprintf(&conf, conf_fmt, hsdir_v3, HS_VERSION_THREE);
+ ret = helper_config_service(conf);
+ tor_free(conf);
+ tt_int_op(ret, OP_EQ, 0);
+ /* It's in staging? */
+ tt_int_op(get_hs_service_staging_list_size(), OP_EQ, 1);
+
+ /* Load the keys for these. After that, the v3 service should be registered
+ * in the global map. */
+ hs_service_load_all_keys();
+ tt_int_op(get_hs_service_map_size(), OP_EQ, 1);
+ s = get_first_service();
+ tt_assert(s);
+ global_map = get_hs_service_map();
+ tt_assert(global_map);
+
+ /* From here, we'll try the service accessors. */
+ hs_service_t *query = find_service(global_map, &s->keys.identity_pk);
+ tt_assert(query);
+ tt_mem_op(query, OP_EQ, s, sizeof(hs_service_t));
+ /* Remove service, check if it actually works and then put it back. */
+ remove_service(global_map, s);
+ tt_int_op(get_hs_service_map_size(), OP_EQ, 0);
+ query = find_service(global_map, &s->keys.identity_pk);
+ tt_ptr_op(query, OP_EQ, NULL);
+
+ /* Register back the service in the map. */
+ ret = register_service(global_map, s);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_int_op(get_hs_service_map_size(), OP_EQ, 1);
+ /* Twice should fail. */
+ ret = register_service(global_map, s);
+ tt_int_op(ret, OP_EQ, -1);
+ /* Remove service from map so we don't double free on cleanup. */
+ remove_service(global_map, s);
+ tt_int_op(get_hs_service_map_size(), OP_EQ, 0);
+ query = find_service(global_map, &s->keys.identity_pk);
+ tt_ptr_op(query, OP_EQ, NULL);
+ /* Let's try to remove twice for fun. */
+ setup_full_capture_of_logs(LOG_WARN);
+ remove_service(global_map, s);
+ expect_log_msg_containing("Could not find service in the global map");
+ teardown_capture_of_logs();
+
+ done:
+ hs_service_free(s);
+ tor_free(hsdir_v3);
+ hs_free_all();
+}
+
+/** Test that we can create intro point objects, index them and find them */
+static void
+test_service_intro_point(void *arg)
+{
+ hs_service_t *service = NULL;
+ hs_service_intro_point_t *ip = NULL;
+
+ (void) arg;
+
+ /* Test simple creation of an object. */
+ {
+ time_t now = time(NULL);
+ ip = helper_create_service_ip();
+ tt_assert(ip);
+ /* Make sure the authentication keypair is not zeroes. */
+ tt_int_op(tor_mem_is_zero((const char *) &ip->auth_key_kp,
+ sizeof(ed25519_keypair_t)), OP_EQ, 0);
+ /* The introduce2_max MUST be in that range. */
+ tt_u64_op(ip->introduce2_max, OP_GE,
+ INTRO_POINT_MIN_LIFETIME_INTRODUCTIONS);
+ tt_u64_op(ip->introduce2_max, OP_LE,
+ INTRO_POINT_MAX_LIFETIME_INTRODUCTIONS);
+ /* Time to expire MUST also be in that range. We subtract 500 seconds
+ * because there could be a gap between setting now and the time taken in
+ * service_intro_point_new. On ARM and other older CPUs, it can be
+ * surprisingly slow... */
+ tt_u64_op(ip->time_to_expire, OP_GE,
+ now + INTRO_POINT_LIFETIME_MIN_SECONDS - 500);
+ /* We add 500 seconds, because this time we're testing against the
+ * maximum allowed time. */
+ tt_u64_op(ip->time_to_expire, OP_LE,
+ now + INTRO_POINT_LIFETIME_MAX_SECONDS + 500);
+ tt_assert(ip->replay_cache);
+ tt_assert(ip->base.link_specifiers);
+ /* By default, this is NOT a legacy object. */
+ tt_int_op(ip->base.is_only_legacy, OP_EQ, 0);
+ }
+
+ /* Test functions that uses a service intropoints map with that previously
+ * created object (non legacy). */
+ {
+ ed25519_public_key_t garbage = { {0} };
+ hs_service_intro_point_t *query;
+
+ service = hs_service_new(get_options());
+ tt_assert(service);
+ service->desc_current = service_descriptor_new();
+ tt_assert(service->desc_current);
+ /* Add intropoint to descriptor map. */
+ service_intro_point_add(service->desc_current->intro_points.map, ip);
+ query = service_intro_point_find(service, &ip->auth_key_kp.pubkey);
+ tt_mem_op(query, OP_EQ, ip, sizeof(hs_service_intro_point_t));
+ query = service_intro_point_find(service, &garbage);
+ tt_ptr_op(query, OP_EQ, NULL);
+
+ /* While at it, can I find the descriptor with the intro point? */
+ hs_service_descriptor_t *desc_lookup =
+ service_desc_find_by_intro(service, ip);
+ tt_mem_op(service->desc_current, OP_EQ, desc_lookup,
+ sizeof(hs_service_descriptor_t));
+
+ /* Remove object from service descriptor and make sure it is out. */
+ service_intro_point_remove(service, ip);
+ query = service_intro_point_find(service, &ip->auth_key_kp.pubkey);
+ tt_ptr_op(query, OP_EQ, NULL);
+ }
+
+ done:
+ /* If the test succeed, this object is no longer referenced in the service
+ * so we can free it without use after free. Else, it might explode because
+ * it's still in the service descriptor map. */
+ service_intro_point_free(ip);
+ hs_service_free(service);
+}
+
+static node_t mock_node;
+static const node_t *
+mock_node_get_by_id(const char *digest)
+{
+ (void) digest;
+ memset(mock_node.identity, 'A', DIGEST_LEN);
+ /* Only return the matchin identity of As */
+ if (!tor_memcmp(mock_node.identity, digest, DIGEST_LEN)) {
+ return &mock_node;
+ }
+ return NULL;
+}
+
+static void
+test_helper_functions(void *arg)
+{
+ int ret;
+ hs_service_t *service = NULL;
+ hs_service_intro_point_t *ip = NULL;
+ hs_ident_circuit_t ident;
+
+ (void) arg;
+
+ MOCK(node_get_by_id, mock_node_get_by_id);
+
+ hs_service_init();
+
+ service = helper_create_service();
+
+ ip = helper_create_service_ip();
+ /* Immediately add the intro point to the service so the free service at the
+ * end cleans it as well. */
+ service_intro_point_add(service->desc_current->intro_points.map, ip);
+
+ /* Setup the circuit identifier. */
+ ed25519_pubkey_copy(&ident.intro_auth_pk, &ip->auth_key_kp.pubkey);
+ ed25519_pubkey_copy(&ident.identity_pk, &service->keys.identity_pk);
+
+ /* Testing get_objects_from_ident(). */
+ {
+ hs_service_t *s_lookup = NULL;
+ hs_service_intro_point_t *ip_lookup = NULL;
+ hs_service_descriptor_t *desc_lookup = NULL;
+
+ get_objects_from_ident(&ident, &s_lookup, &ip_lookup, &desc_lookup);
+ tt_mem_op(s_lookup, OP_EQ, service, sizeof(hs_service_t));
+ tt_mem_op(ip_lookup, OP_EQ, ip, sizeof(hs_service_intro_point_t));
+ tt_mem_op(desc_lookup, OP_EQ, service->desc_current,
+ sizeof(hs_service_descriptor_t));
+ /* Reset */
+ s_lookup = NULL; ip_lookup = NULL; desc_lookup = NULL;
+
+ /* NULL parameter should work. */
+ get_objects_from_ident(&ident, NULL, &ip_lookup, &desc_lookup);
+ tt_mem_op(ip_lookup, OP_EQ, ip, sizeof(hs_service_intro_point_t));
+ tt_mem_op(desc_lookup, OP_EQ, service->desc_current,
+ sizeof(hs_service_descriptor_t));
+ /* Reset. */
+ s_lookup = NULL; ip_lookup = NULL; desc_lookup = NULL;
+
+ /* Break the ident and we should find nothing. */
+ memset(&ident, 0, sizeof(ident));
+ get_objects_from_ident(&ident, &s_lookup, &ip_lookup, &desc_lookup);
+ tt_ptr_op(s_lookup, OP_EQ, NULL);
+ tt_ptr_op(ip_lookup, OP_EQ, NULL);
+ tt_ptr_op(desc_lookup, OP_EQ, NULL);
+ }
+
+ /* Testing get_node_from_intro_point() */
+ {
+ const node_t *node = get_node_from_intro_point(ip);
+ tt_ptr_op(node, OP_EQ, &mock_node);
+ SMARTLIST_FOREACH_BEGIN(ip->base.link_specifiers,
+ hs_desc_link_specifier_t *, ls) {
+ if (ls->type == LS_LEGACY_ID) {
+ /* Change legacy id in link specifier which is not the mock node. */
+ memset(ls->u.legacy_id, 'B', sizeof(ls->u.legacy_id));
+ }
+ } SMARTLIST_FOREACH_END(ls);
+ node = get_node_from_intro_point(ip);
+ tt_ptr_op(node, OP_EQ, NULL);
+ }
+
+ /* Testing can_service_launch_intro_circuit() */
+ {
+ time_t now = time(NULL);
+ /* Put the start of the retry period back in time, we should be allowed.
+ * to launch intro circuit. */
+ service->state.num_intro_circ_launched = 2;
+ service->state.intro_circ_retry_started_time =
+ (now - INTRO_CIRC_RETRY_PERIOD - 1);
+ ret = can_service_launch_intro_circuit(service, now);
+ tt_int_op(ret, OP_EQ, 1);
+ tt_u64_op(service->state.intro_circ_retry_started_time, OP_EQ, now);
+ tt_u64_op(service->state.num_intro_circ_launched, OP_EQ, 0);
+ /* Call it again, we should still be allowed because we are under
+ * MAX_INTRO_CIRCS_PER_PERIOD which been set to 0 previously. */
+ ret = can_service_launch_intro_circuit(service, now);
+ tt_int_op(ret, OP_EQ, 1);
+ tt_u64_op(service->state.intro_circ_retry_started_time, OP_EQ, now);
+ tt_u64_op(service->state.num_intro_circ_launched, OP_EQ, 0);
+ /* Too many intro circuit launched means we are not allowed. */
+ service->state.num_intro_circ_launched = 20;
+ ret = can_service_launch_intro_circuit(service, now);
+ tt_int_op(ret, OP_EQ, 0);
+ }
+
+ /* Testing intro_point_should_expire(). */
+ {
+ time_t now = time(NULL);
+ /* Just some basic test of the current state. */
+ tt_u64_op(ip->introduce2_max, OP_GE,
+ INTRO_POINT_MIN_LIFETIME_INTRODUCTIONS);
+ tt_u64_op(ip->introduce2_max, OP_LE,
+ INTRO_POINT_MAX_LIFETIME_INTRODUCTIONS);
+ tt_u64_op(ip->time_to_expire, OP_GE,
+ now + INTRO_POINT_LIFETIME_MIN_SECONDS);
+ tt_u64_op(ip->time_to_expire, OP_LE,
+ now + INTRO_POINT_LIFETIME_MAX_SECONDS);
+
+ /* This newly created IP from above shouldn't expire now. */
+ ret = intro_point_should_expire(ip, now);
+ tt_int_op(ret, OP_EQ, 0);
+ /* Maximum number of INTRODUCE2 cell reached, it should expire. */
+ ip->introduce2_count = INTRO_POINT_MAX_LIFETIME_INTRODUCTIONS + 1;
+ ret = intro_point_should_expire(ip, now);
+ tt_int_op(ret, OP_EQ, 1);
+ ip->introduce2_count = 0;
+ /* It should expire if time to expire has been reached. */
+ ip->time_to_expire = now - 1000;
+ ret = intro_point_should_expire(ip, now);
+ tt_int_op(ret, OP_EQ, 1);
+ }
+
+ done:
+ /* This will free the service and all objects associated to it. */
+ hs_service_free_all();
+ UNMOCK(node_get_by_id);
+}
+
+/** Test that we do the right operations when an intro circuit opens */
+static void
+test_intro_circuit_opened(void *arg)
+{
+ int flags = CIRCLAUNCH_NEED_UPTIME | CIRCLAUNCH_IS_INTERNAL;
+ hs_service_t *service;
+ origin_circuit_t *circ = NULL;
+
+ (void) arg;
+
+ hs_init();
+ MOCK(circuit_mark_for_close_, mock_circuit_mark_for_close);
+ MOCK(relay_send_command_from_edge_, mock_relay_send_command_from_edge);
+
+ circ = helper_create_origin_circuit(CIRCUIT_PURPOSE_S_ESTABLISH_INTRO,
+ flags);
+
+ /* No service associated with this circuit. */
+ setup_full_capture_of_logs(LOG_WARN);
+ hs_service_circuit_has_opened(circ);
+ expect_log_msg_containing("Unknown service identity key");
+ teardown_capture_of_logs();
+
+ /* Set a service for this circuit. */
+ {
+ service = helper_create_service();
+ ed25519_pubkey_copy(&circ->hs_ident->identity_pk,
+ &service->keys.identity_pk);
+
+ /* No intro point associated with this circuit. */
+ setup_full_capture_of_logs(LOG_WARN);
+ hs_service_circuit_has_opened(circ);
+ expect_log_msg_containing("Unknown introduction point auth key");
+ teardown_capture_of_logs();
+ }
+
+ /* Set an IP object now for this circuit. */
+ {
+ hs_service_intro_point_t *ip = helper_create_service_ip();
+ service_intro_point_add(service->desc_current->intro_points.map, ip);
+ /* Update ident to contain the intro point auth key. */
+ ed25519_pubkey_copy(&circ->hs_ident->intro_auth_pk,
+ &ip->auth_key_kp.pubkey);
+ }
+
+ /* This one should go all the way. */
+ setup_full_capture_of_logs(LOG_INFO);
+ hs_service_circuit_has_opened(circ);
+ expect_log_msg_containing("Introduction circuit 0 established for service");
+ teardown_capture_of_logs();
+
+ done:
+ circuit_free(TO_CIRCUIT(circ));
+ hs_free_all();
+ UNMOCK(circuit_mark_for_close_);
+ UNMOCK(relay_send_command_from_edge_);
+}
+
+/** Test the operations we do on a circuit after we learn that we successfuly
+ * established an intro point on it */
+static void
+test_intro_established(void *arg)
+{
+ int ret;
+ int flags = CIRCLAUNCH_NEED_UPTIME | CIRCLAUNCH_IS_INTERNAL;
+ uint8_t payload[RELAY_PAYLOAD_SIZE] = {0};
+ origin_circuit_t *circ = NULL;
+ hs_service_t *service;
+ hs_service_intro_point_t *ip = NULL;
+
+ (void) arg;
+
+ hs_init();
+ MOCK(circuit_mark_for_close_, mock_circuit_mark_for_close);
+
+ circ = helper_create_origin_circuit(CIRCUIT_PURPOSE_S_ESTABLISH_INTRO,
+ flags);
+ tt_assert(circ);
+
+ /* Test a wrong purpose. */
+ TO_CIRCUIT(circ)->purpose = CIRCUIT_PURPOSE_S_INTRO;
+ setup_full_capture_of_logs(LOG_WARN);
+ ret = hs_service_receive_intro_established(circ, payload, sizeof(payload));
+ tt_int_op(ret, OP_EQ, -1);
+ expect_log_msg_containing("Received an INTRO_ESTABLISHED cell on a "
+ "non introduction circuit of purpose");
+ teardown_capture_of_logs();
+
+ /* Back to normal. */
+ TO_CIRCUIT(circ)->purpose = CIRCUIT_PURPOSE_S_ESTABLISH_INTRO;
+
+ /* No service associated to it. */
+ setup_full_capture_of_logs(LOG_WARN);
+ ret = hs_service_receive_intro_established(circ, payload, sizeof(payload));
+ tt_int_op(ret, OP_EQ, -1);
+ expect_log_msg_containing("Unknown service identity key");
+ teardown_capture_of_logs();
+
+ /* Set a service for this circuit. */
+ service = helper_create_service();
+ ed25519_pubkey_copy(&circ->hs_ident->identity_pk,
+ &service->keys.identity_pk);
+ /* No introduction point associated to it. */
+ setup_full_capture_of_logs(LOG_WARN);
+ ret = hs_service_receive_intro_established(circ, payload, sizeof(payload));
+ tt_int_op(ret, OP_EQ, -1);
+ expect_log_msg_containing("Introduction circuit established without an "
+ "intro point object on circuit");
+ teardown_capture_of_logs();
+
+ /* Set an IP object now for this circuit. */
+ {
+ ip = helper_create_service_ip();
+ service_intro_point_add(service->desc_current->intro_points.map, ip);
+ /* Update ident to contain the intro point auth key. */
+ ed25519_pubkey_copy(&circ->hs_ident->intro_auth_pk,
+ &ip->auth_key_kp.pubkey);
+ }
+
+ /* Send an empty payload. INTRO_ESTABLISHED cells are basically zeroes. */
+ ret = hs_service_receive_intro_established(circ, payload, sizeof(payload));
+ tt_int_op(ret, OP_EQ, 0);
+ tt_u64_op(ip->circuit_established, OP_EQ, 1);
+ tt_int_op(TO_CIRCUIT(circ)->purpose, OP_EQ, CIRCUIT_PURPOSE_S_INTRO);
+
+ done:
+ if (circ)
+ circuit_free(TO_CIRCUIT(circ));
+ hs_free_all();
+ UNMOCK(circuit_mark_for_close_);
+}
+
+/** Check the operations we do on a rendezvous circuit after we learn it's
+ * open */
+static void
+test_rdv_circuit_opened(void *arg)
+{
+ int flags = CIRCLAUNCH_NEED_UPTIME | CIRCLAUNCH_IS_INTERNAL;
+ origin_circuit_t *circ = NULL;
+ hs_service_t *service;
+
+ (void) arg;
+
+ hs_init();
+ MOCK(circuit_mark_for_close_, mock_circuit_mark_for_close);
+ MOCK(relay_send_command_from_edge_, mock_relay_send_command_from_edge);
+
+ circ = helper_create_origin_circuit(CIRCUIT_PURPOSE_S_CONNECT_REND, flags);
+ crypto_rand((char *) circ->hs_ident->rendezvous_cookie, REND_COOKIE_LEN);
+ crypto_rand((char *) circ->hs_ident->rendezvous_handshake_info,
+ sizeof(circ->hs_ident->rendezvous_handshake_info));
+
+ /* No service associated with this circuit. */
+ setup_full_capture_of_logs(LOG_WARN);
+ hs_service_circuit_has_opened(circ);
+ expect_log_msg_containing("Unknown service identity key");
+ teardown_capture_of_logs();
+ /* This should be set to a non zero timestamp. */
+ tt_u64_op(TO_CIRCUIT(circ)->timestamp_dirty, OP_NE, 0);
+
+ /* Set a service for this circuit. */
+ service = helper_create_service();
+ ed25519_pubkey_copy(&circ->hs_ident->identity_pk,
+ &service->keys.identity_pk);
+ /* Should be all good. */
+ hs_service_circuit_has_opened(circ);
+ tt_int_op(TO_CIRCUIT(circ)->purpose, OP_EQ, CIRCUIT_PURPOSE_S_REND_JOINED);
+
+ done:
+ circuit_free(TO_CIRCUIT(circ));
+ hs_free_all();
+ UNMOCK(circuit_mark_for_close_);
+ UNMOCK(relay_send_command_from_edge_);
+}
+
+static void
+mock_assert_circuit_ok(const circuit_t *c)
+{
+ (void) c;
+ return;
+}
+
+/** Test for the general mechanism for closing intro circs.
+ * Also a way to identify that #23603 has been fixed. */
+static void
+test_closing_intro_circs(void *arg)
+{
+ hs_service_t *service = NULL;
+ hs_service_intro_point_t *ip = NULL, *entry = NULL;
+ origin_circuit_t *intro_circ = NULL, *tmp_circ;
+ int flags = CIRCLAUNCH_NEED_UPTIME | CIRCLAUNCH_IS_INTERNAL;
+
+ (void) arg;
+
+ MOCK(assert_circuit_ok, mock_assert_circuit_ok);
+
+ hs_init();
+
+ /* Initialize service */
+ service = helper_create_service();
+ /* Initialize intro point */
+ ip = helper_create_service_ip();
+ tt_assert(ip);
+ service_intro_point_add(service->desc_current->intro_points.map, ip);
+
+ /* Initialize intro circuit */
+ intro_circ = origin_circuit_init(CIRCUIT_PURPOSE_S_ESTABLISH_INTRO, flags);
+ intro_circ->hs_ident = hs_ident_circuit_new(&service->keys.identity_pk,
+ HS_IDENT_CIRCUIT_INTRO);
+ /* Register circuit in the circuitmap . */
+ hs_circuitmap_register_intro_circ_v3_service_side(intro_circ,
+ &ip->auth_key_kp.pubkey);
+ tmp_circ =
+ hs_circuitmap_get_intro_circ_v3_service_side(&ip->auth_key_kp.pubkey);
+ tt_ptr_op(tmp_circ, OP_EQ, intro_circ);
+
+ /* Pretend that intro point has failed too much */
+ ip->circuit_retries = MAX_INTRO_POINT_CIRCUIT_RETRIES+1;
+
+ /* Now pretend we are freeing this intro circuit. We want to see that our
+ * destructor is not gonna kill our intro point structure since that's the
+ * job of the cleanup routine. */
+ circuit_free(TO_CIRCUIT(intro_circ));
+ intro_circ = NULL;
+ entry = service_intro_point_find(service, &ip->auth_key_kp.pubkey);
+ tt_assert(entry);
+ /* The free should also remove the circuit from the circuitmap. */
+ tmp_circ =
+ hs_circuitmap_get_intro_circ_v3_service_side(&ip->auth_key_kp.pubkey);
+ tt_assert(!tmp_circ);
+
+ /* Now pretend that a new intro point circ was launched and opened. Check
+ * that the intro point will be established correctly. */
+ intro_circ = origin_circuit_init(CIRCUIT_PURPOSE_S_ESTABLISH_INTRO, flags);
+ intro_circ->hs_ident = hs_ident_circuit_new(&service->keys.identity_pk,
+ HS_IDENT_CIRCUIT_INTRO);
+ ed25519_pubkey_copy(&intro_circ->hs_ident->intro_auth_pk,
+ &ip->auth_key_kp.pubkey);
+ /* Register circuit in the circuitmap . */
+ hs_circuitmap_register_intro_circ_v3_service_side(intro_circ,
+ &ip->auth_key_kp.pubkey);
+ tmp_circ =
+ hs_circuitmap_get_intro_circ_v3_service_side(&ip->auth_key_kp.pubkey);
+ tt_ptr_op(tmp_circ, OP_EQ, intro_circ);
+ tt_int_op(TO_CIRCUIT(intro_circ)->marked_for_close, OP_EQ, 0);
+ circuit_mark_for_close(TO_CIRCUIT(intro_circ), END_CIRC_REASON_INTERNAL);
+ tt_int_op(TO_CIRCUIT(intro_circ)->marked_for_close, OP_NE, 0);
+ /* At this point, we should not be able to find it in the circuitmap. */
+ tmp_circ =
+ hs_circuitmap_get_intro_circ_v3_service_side(&ip->auth_key_kp.pubkey);
+ tt_assert(!tmp_circ);
+
+ done:
+ if (intro_circ) {
+ circuit_free(TO_CIRCUIT(intro_circ));
+ }
+ /* Frees the service object. */
+ hs_free_all();
+ UNMOCK(assert_circuit_ok);
+}
+
+/** Test sending and receiving introduce2 cells */
+static void
+test_introduce2(void *arg)
+{
+ int ret;
+ int flags = CIRCLAUNCH_NEED_UPTIME | CIRCLAUNCH_IS_INTERNAL;
+ uint8_t payload[RELAY_PAYLOAD_SIZE] = {0};
+ origin_circuit_t *circ = NULL;
+ hs_service_t *service;
+ hs_service_intro_point_t *ip = NULL;
+
+ (void) arg;
+
+ hs_init();
+ MOCK(circuit_mark_for_close_, mock_circuit_mark_for_close);
+ MOCK(get_or_state,
+ get_or_state_replacement);
+
+ dummy_state = tor_malloc_zero(sizeof(or_state_t));
+
+ circ = helper_create_origin_circuit(CIRCUIT_PURPOSE_S_INTRO, flags);
+ tt_assert(circ);
+
+ /* Test a wrong purpose. */
+ TO_CIRCUIT(circ)->purpose = CIRCUIT_PURPOSE_S_ESTABLISH_INTRO;
+ setup_full_capture_of_logs(LOG_WARN);
+ ret = hs_service_receive_introduce2(circ, payload, sizeof(payload));
+ tt_int_op(ret, OP_EQ, -1);
+ expect_log_msg_containing("Received an INTRODUCE2 cell on a "
+ "non introduction circuit of purpose");
+ teardown_capture_of_logs();
+
+ /* Back to normal. */
+ TO_CIRCUIT(circ)->purpose = CIRCUIT_PURPOSE_S_INTRO;
+
+ /* No service associated to it. */
+ setup_full_capture_of_logs(LOG_WARN);
+ ret = hs_service_receive_introduce2(circ, payload, sizeof(payload));
+ tt_int_op(ret, OP_EQ, -1);
+ expect_log_msg_containing("Unknown service identity key");
+ teardown_capture_of_logs();
+
+ /* Set a service for this circuit. */
+ service = helper_create_service();
+ ed25519_pubkey_copy(&circ->hs_ident->identity_pk,
+ &service->keys.identity_pk);
+ /* No introduction point associated to it. */
+ setup_full_capture_of_logs(LOG_WARN);
+ ret = hs_service_receive_introduce2(circ, payload, sizeof(payload));
+ tt_int_op(ret, OP_EQ, -1);
+ expect_log_msg_containing("Unknown introduction auth key when handling "
+ "an INTRODUCE2 cell on circuit");
+ teardown_capture_of_logs();
+
+ /* Set an IP object now for this circuit. */
+ {
+ ip = helper_create_service_ip();
+ service_intro_point_add(service->desc_current->intro_points.map, ip);
+ /* Update ident to contain the intro point auth key. */
+ ed25519_pubkey_copy(&circ->hs_ident->intro_auth_pk,
+ &ip->auth_key_kp.pubkey);
+ }
+
+ /* This will fail because receiving an INTRODUCE2 cell implies a valid cell
+ * and then launching circuits so let's not do that and instead test that
+ * behaviour differently. */
+ ret = hs_service_receive_introduce2(circ, payload, sizeof(payload));
+ tt_int_op(ret, OP_EQ, -1);
+ tt_u64_op(ip->introduce2_count, OP_EQ, 0);
+
+ done:
+ or_state_free(dummy_state);
+ dummy_state = NULL;
+ if (circ)
+ circuit_free(TO_CIRCUIT(circ));
+ hs_free_all();
+ UNMOCK(circuit_mark_for_close_);
+}
+
+/** Test basic hidden service housekeeping operations (maintaining intro
+ * points, etc) */
+static void
+test_service_event(void *arg)
+{
+ int flags = CIRCLAUNCH_NEED_UPTIME | CIRCLAUNCH_IS_INTERNAL;
+ time_t now = time(NULL);
+ hs_service_t *service;
+ origin_circuit_t *circ = NULL;
+
+ (void) arg;
+
+ hs_init();
+ MOCK(circuit_mark_for_close_, mock_circuit_mark_for_close);
+
+ circ = helper_create_origin_circuit(CIRCUIT_PURPOSE_S_INTRO, flags);
+
+ /* Set a service for this circuit. */
+ service = helper_create_service();
+ ed25519_pubkey_copy(&circ->hs_ident->identity_pk,
+ &service->keys.identity_pk);
+
+ /* Currently this consists of cleaning invalid intro points. So adding IPs
+ * here that should get cleaned up. */
+ {
+ hs_service_intro_point_t *ip = helper_create_service_ip();
+ service_intro_point_add(service->desc_current->intro_points.map, ip);
+ /* This run will remove the IP because we have no circuits nor node_t
+ * associated with it. */
+ run_housekeeping_event(now);
+ tt_int_op(digest256map_size(service->desc_current->intro_points.map),
+ OP_EQ, 0);
+ /* We'll trigger a removal because we've reached our maximum amount of
+ * times we should retry a circuit. For this, we need to have a node_t
+ * that matches the identity of this IP. */
+ routerinfo_t ri;
+ memset(&ri, 0, sizeof(ri));
+ ip = helper_create_service_ip();
+ service_intro_point_add(service->desc_current->intro_points.map, ip);
+ memset(ri.cache_info.identity_digest, 'A', DIGEST_LEN);
+ /* This triggers a node_t creation. */
+ tt_assert(nodelist_set_routerinfo(&ri, NULL));
+ ip->circuit_retries = MAX_INTRO_POINT_CIRCUIT_RETRIES + 1;
+ run_housekeeping_event(now);
+ tt_int_op(digest256map_size(service->desc_current->intro_points.map),
+ OP_EQ, 0);
+ /* No removal but no circuit so this means the IP object will stay in the
+ * descriptor map so we can retry it. */
+ ip = helper_create_service_ip();
+ service_intro_point_add(service->desc_current->intro_points.map, ip);
+ ip->circuit_established = 1; /* We'll test that, it MUST be 0 after. */
+ run_housekeeping_event(now);
+ tt_int_op(digest256map_size(service->desc_current->intro_points.map),
+ OP_EQ, 1);
+ /* Remove the IP object at once for the next test. */
+ ip->circuit_retries = MAX_INTRO_POINT_CIRCUIT_RETRIES + 1;
+ run_housekeeping_event(now);
+ tt_int_op(digest256map_size(service->desc_current->intro_points.map),
+ OP_EQ, 0);
+ /* Now, we'll create an IP with a registered circuit. The IP object
+ * shouldn't go away. */
+ ip = helper_create_service_ip();
+ service_intro_point_add(service->desc_current->intro_points.map, ip);
+ ed25519_pubkey_copy(&circ->hs_ident->intro_auth_pk,
+ &ip->auth_key_kp.pubkey);
+ hs_circuitmap_register_intro_circ_v3_service_side(
+ circ, &ip->auth_key_kp.pubkey);
+ run_housekeeping_event(now);
+ tt_int_op(digest256map_size(service->desc_current->intro_points.map),
+ OP_EQ, 1);
+ /* We'll mangle the IP object to expire. */
+ ip->time_to_expire = now;
+ run_housekeeping_event(now);
+ tt_int_op(digest256map_size(service->desc_current->intro_points.map),
+ OP_EQ, 0);
+ }
+
+ done:
+ hs_circuitmap_remove_circuit(TO_CIRCUIT(circ));
+ circuit_free(TO_CIRCUIT(circ));
+ hs_free_all();
+ UNMOCK(circuit_mark_for_close_);
+}
+
+/** Test that we rotate descriptors correctly. */
+static void
+test_rotate_descriptors(void *arg)
+{
+ int ret;
+ time_t next_rotation_time, now = time(NULL);
+ hs_service_t *service;
+ hs_service_descriptor_t *desc_next;
+
+ (void) arg;
+
+ dummy_state = tor_malloc_zero(sizeof(or_state_t));
+
+ hs_init();
+ MOCK(get_or_state, get_or_state_replacement);
+ MOCK(circuit_mark_for_close_, mock_circuit_mark_for_close);
+ MOCK(networkstatus_get_live_consensus,
+ mock_networkstatus_get_live_consensus);
+
+ /* Descriptor rotation happens with a consensus with a new SRV. */
+
+ ret = parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC",
+ &mock_ns.valid_after);
+ tt_int_op(ret, OP_EQ, 0);
+ ret = parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC",
+ &mock_ns.fresh_until);
+ tt_int_op(ret, OP_EQ, 0);
+ dirvote_recalculate_timing(get_options(), mock_ns.valid_after);
+
+ /* Create a service with a default descriptor and state. It's added to the
+ * global map. */
+ service = helper_create_service();
+ service_descriptor_free(service->desc_current);
+ service->desc_current = NULL;
+ /* This triggers a build for both descriptors. The time now is only used in
+ * the descriptor certificate which is important to be now else the decoding
+ * will complain that the cert has expired if we use valid_after. */
+ build_all_descriptors(now);
+ tt_assert(service->desc_current);
+ tt_assert(service->desc_next);
+
+ /* Tweak our service next rotation time so we can use a custom time. */
+ service->state.next_rotation_time = next_rotation_time =
+ mock_ns.valid_after + (11 * 60 * 60);
+
+ /* Nothing should happen, we are not at a new SRV. Our next rotation time
+ * should be untouched. */
+ rotate_all_descriptors(mock_ns.valid_after);
+ tt_u64_op(service->state.next_rotation_time, OP_EQ, next_rotation_time);
+ tt_assert(service->desc_current);
+ tt_assert(service->desc_next);
+ tt_u64_op(service->desc_current->time_period_num, OP_EQ,
+ hs_get_previous_time_period_num(0));
+ tt_u64_op(service->desc_next->time_period_num, OP_EQ,
+ hs_get_time_period_num(0));
+ /* Keep a reference so we can compare it after rotation to the current. */
+ desc_next = service->desc_next;
+
+ /* Going right after a new SRV. */
+ ret = parse_rfc1123_time("Sat, 27 Oct 1985 01:00:00 UTC",
+ &mock_ns.valid_after);
+ tt_int_op(ret, OP_EQ, 0);
+ ret = parse_rfc1123_time("Sat, 27 Oct 1985 02:00:00 UTC",
+ &mock_ns.fresh_until);
+ tt_int_op(ret, OP_EQ, 0);
+ dirvote_recalculate_timing(get_options(), mock_ns.valid_after);
+
+ /* Note down what to expect for the next rotation time which is 01:00 + 23h
+ * meaning 00:00:00. */
+ next_rotation_time = mock_ns.valid_after + (23 * 60 * 60);
+ /* We should have our next rotation time modified, our current descriptor
+ * cleaned up and the next descriptor becoming the current. */
+ rotate_all_descriptors(mock_ns.valid_after);
+ tt_u64_op(service->state.next_rotation_time, OP_EQ, next_rotation_time);
+ tt_mem_op(service->desc_current, OP_EQ, desc_next, sizeof(*desc_next));
+ tt_assert(service->desc_next == NULL);
+
+ /* A second time should do nothing. */
+ rotate_all_descriptors(mock_ns.valid_after);
+ tt_u64_op(service->state.next_rotation_time, OP_EQ, next_rotation_time);
+ tt_mem_op(service->desc_current, OP_EQ, desc_next, sizeof(*desc_next));
+ tt_assert(service->desc_next == NULL);
+
+ build_all_descriptors(now);
+ tt_mem_op(service->desc_current, OP_EQ, desc_next, sizeof(*desc_next));
+ tt_u64_op(service->desc_current->time_period_num, OP_EQ,
+ hs_get_time_period_num(0));
+ tt_u64_op(service->desc_next->time_period_num, OP_EQ,
+ hs_get_next_time_period_num(0));
+ tt_assert(service->desc_next);
+
+ done:
+ hs_free_all();
+ UNMOCK(get_or_state);
+ UNMOCK(circuit_mark_for_close_);
+ UNMOCK(networkstatus_get_live_consensus);
+}
+
+/** Test building descriptors: picking intro points, setting up their link
+ * specifiers, etc. */
+static void
+test_build_update_descriptors(void *arg)
+{
+ int ret;
+ time_t now = time(NULL);
+ node_t *node;
+ hs_service_t *service;
+ hs_service_intro_point_t *ip_cur, *ip_next;
+ routerinfo_t ri;
+
+ (void) arg;
+
+ hs_init();
+
+ MOCK(get_or_state,
+ get_or_state_replacement);
+ MOCK(networkstatus_get_live_consensus,
+ mock_networkstatus_get_live_consensus);
+
+ dummy_state = tor_malloc_zero(sizeof(or_state_t));
+
+ ret = parse_rfc1123_time("Sat, 26 Oct 1985 03:00:00 UTC",
+ &mock_ns.valid_after);
+ tt_int_op(ret, OP_EQ, 0);
+ ret = parse_rfc1123_time("Sat, 26 Oct 1985 04:00:00 UTC",
+ &mock_ns.fresh_until);
+ tt_int_op(ret, OP_EQ, 0);
+ dirvote_recalculate_timing(get_options(), mock_ns.valid_after);
+
+ /* Create a service without a current descriptor to trigger a build. */
+ service = helper_create_service();
+ tt_assert(service);
+ /* Unfortunately, the helper creates a dummy descriptor so get rid of it. */
+ service_descriptor_free(service->desc_current);
+ service->desc_current = NULL;
+
+ /* We have a fresh service so this should trigger a build for both
+ * descriptors for specific time period that we'll test. */
+ build_all_descriptors(now);
+ /* Check *current* descriptor. */
+ tt_assert(service->desc_current);
+ tt_assert(service->desc_current->desc);
+ tt_assert(service->desc_current->intro_points.map);
+ /* The current time period is the one expected when starting at 03:00. */
+ tt_u64_op(service->desc_current->time_period_num, OP_EQ,
+ hs_get_time_period_num(0));
+ /* This should be untouched, the update descriptor process changes it. */
+ tt_u64_op(service->desc_current->next_upload_time, OP_EQ, 0);
+
+ /* Check *next* descriptor. */
+ tt_assert(service->desc_next);
+ tt_assert(service->desc_next->desc);
+ tt_assert(service->desc_next->intro_points.map);
+ tt_assert(service->desc_current != service->desc_next);
+ tt_u64_op(service->desc_next->time_period_num, OP_EQ,
+ hs_get_next_time_period_num(0));
+ /* This should be untouched, the update descriptor process changes it. */
+ tt_u64_op(service->desc_next->next_upload_time, OP_EQ, 0);
+
+ /* Time to test the update of those descriptors. At first, we have no node
+ * in the routerlist so this will find NO suitable node for the IPs. */
+ setup_full_capture_of_logs(LOG_INFO);
+ update_all_descriptors(now);
+ expect_log_msg_containing("Unable to find a suitable node to be an "
+ "introduction point for service");
+ teardown_capture_of_logs();
+ tt_int_op(digest256map_size(service->desc_current->intro_points.map),
+ OP_EQ, 0);
+ tt_int_op(digest256map_size(service->desc_next->intro_points.map),
+ OP_EQ, 0);
+
+ /* Now, we'll setup a node_t. */
+ {
+ tor_addr_t ipv4_addr;
+ curve25519_secret_key_t curve25519_secret_key;
+
+ memset(&ri, 0, sizeof(routerinfo_t));
+
+ tor_addr_parse(&ipv4_addr, "127.0.0.1");
+ ri.addr = tor_addr_to_ipv4h(&ipv4_addr);
+ ri.or_port = 1337;
+ ri.purpose = ROUTER_PURPOSE_GENERAL;
+ /* Ugly yes but we never free the "ri" object so this just makes things
+ * easier. */
+ ri.protocol_list = (char *) "HSDir=1-2 LinkAuth=3";
+ ret = curve25519_secret_key_generate(&curve25519_secret_key, 0);
+ tt_int_op(ret, OP_EQ, 0);
+ ri.onion_curve25519_pkey =
+ tor_malloc_zero(sizeof(curve25519_public_key_t));
+ ri.onion_pkey = crypto_pk_new();
+ curve25519_public_key_generate(ri.onion_curve25519_pkey,
+ &curve25519_secret_key);
+ memset(ri.cache_info.identity_digest, 'A', DIGEST_LEN);
+ /* Setup ed25519 identity */
+ ed25519_keypair_t kp1;
+ ed25519_keypair_generate(&kp1, 0);
+ ri.cache_info.signing_key_cert = tor_malloc_zero(sizeof(tor_cert_t));
+ tt_assert(ri.cache_info.signing_key_cert);
+ ed25519_pubkey_copy(&ri.cache_info.signing_key_cert->signing_key,
+ &kp1.pubkey);
+ nodelist_set_routerinfo(&ri, NULL);
+ node = node_get_mutable_by_id(ri.cache_info.identity_digest);
+ tt_assert(node);
+ node->is_running = node->is_valid = node->is_fast = node->is_stable = 1;
+ }
+
+ /* We expect to pick only one intro point from the node above. */
+ setup_full_capture_of_logs(LOG_INFO);
+ update_all_descriptors(now);
+ tor_free(node->ri->onion_curve25519_pkey); /* Avoid memleak. */
+ tor_free(node->ri->cache_info.signing_key_cert);
+ crypto_pk_free(node->ri->onion_pkey);
+ expect_log_msg_containing("just picked 1 intro points and wanted 3 for next "
+ "descriptor. It currently has 0 intro points. "
+ "Launching ESTABLISH_INTRO circuit shortly.");
+ teardown_capture_of_logs();
+ tt_int_op(digest256map_size(service->desc_current->intro_points.map),
+ OP_EQ, 1);
+ tt_int_op(digest256map_size(service->desc_next->intro_points.map),
+ OP_EQ, 1);
+ /* Get the IP object. Because we don't have the auth key of the IP, we can't
+ * query it so get the first element in the map. */
+ {
+ void *obj = NULL;
+ const uint8_t *key;
+ digest256map_iter_t *iter =
+ digest256map_iter_init(service->desc_current->intro_points.map);
+ digest256map_iter_get(iter, &key, &obj);
+ tt_assert(obj);
+ ip_cur = obj;
+ /* Get also the IP from the next descriptor. We'll make sure it's not the
+ * same object as in the current descriptor. */
+ iter = digest256map_iter_init(service->desc_next->intro_points.map);
+ digest256map_iter_get(iter, &key, &obj);
+ tt_assert(obj);
+ ip_next = obj;
+ }
+ tt_mem_op(ip_cur, OP_NE, ip_next, sizeof(hs_desc_intro_point_t));
+
+ /* We won't test the service IP object because there is a specific test
+ * already for this but we'll make sure that the state is coherent.*/
+
+ /* Three link specifiers are mandatoy so make sure we do have them. */
+ tt_int_op(smartlist_len(ip_cur->base.link_specifiers), OP_EQ, 3);
+ /* Make sure we have a valid encryption keypair generated when we pick an
+ * intro point in the update process. */
+ tt_assert(!tor_mem_is_zero((char *) ip_cur->enc_key_kp.seckey.secret_key,
+ CURVE25519_SECKEY_LEN));
+ tt_assert(!tor_mem_is_zero((char *) ip_cur->enc_key_kp.pubkey.public_key,
+ CURVE25519_PUBKEY_LEN));
+ tt_u64_op(ip_cur->time_to_expire, OP_GE, now +
+ INTRO_POINT_LIFETIME_MIN_SECONDS);
+ tt_u64_op(ip_cur->time_to_expire, OP_LE, now +
+ INTRO_POINT_LIFETIME_MAX_SECONDS);
+
+ /* Now, we will try to set up a service after a new time period has started
+ * and see if it behaves as expected. */
+
+ ret = parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC",
+ &mock_ns.valid_after);
+ tt_int_op(ret, OP_EQ, 0);
+ ret = parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC",
+ &mock_ns.fresh_until);
+ tt_int_op(ret, OP_EQ, 0);
+
+ /* Create a service without a current descriptor to trigger a build. */
+ service = helper_create_service();
+ tt_assert(service);
+ /* Unfortunately, the helper creates a dummy descriptor so get rid of it. */
+ service_descriptor_free(service->desc_current);
+ service->desc_current = NULL;
+
+ /* We have a fresh service so this should trigger a build for both
+ * descriptors for specific time period that we'll test. */
+ build_all_descriptors(now);
+ /* Check *current* descriptor. */
+ tt_assert(service->desc_current);
+ tt_assert(service->desc_current->desc);
+ tt_assert(service->desc_current->intro_points.map);
+ /* This should be for the previous time period. */
+ tt_u64_op(service->desc_current->time_period_num, OP_EQ,
+ hs_get_previous_time_period_num(0));
+ /* This should be untouched, the update descriptor process changes it. */
+ tt_u64_op(service->desc_current->next_upload_time, OP_EQ, 0);
+
+ /* Check *next* descriptor. */
+ tt_assert(service->desc_next);
+ tt_assert(service->desc_next->desc);
+ tt_assert(service->desc_next->intro_points.map);
+ tt_assert(service->desc_current != service->desc_next);
+ tt_u64_op(service->desc_next->time_period_num, OP_EQ,
+ hs_get_time_period_num(0));
+ /* This should be untouched, the update descriptor process changes it. */
+ tt_u64_op(service->desc_next->next_upload_time, OP_EQ, 0);
+
+ /* Let's remove the next descriptor to simulate a rotation. */
+ service_descriptor_free(service->desc_next);
+ service->desc_next = NULL;
+
+ build_all_descriptors(now);
+ /* Check *next* descriptor. */
+ tt_assert(service->desc_next);
+ tt_assert(service->desc_next->desc);
+ tt_assert(service->desc_next->intro_points.map);
+ tt_assert(service->desc_current != service->desc_next);
+ tt_u64_op(service->desc_next->time_period_num, OP_EQ,
+ hs_get_next_time_period_num(0));
+ /* This should be untouched, the update descriptor process changes it. */
+ tt_u64_op(service->desc_next->next_upload_time, OP_EQ, 0);
+
+ done:
+ hs_free_all();
+ nodelist_free_all();
+}
+
+static void
+test_upload_descriptors(void *arg)
+{
+ int ret;
+ time_t now = time(NULL);
+ hs_service_t *service;
+
+ (void) arg;
+
+ hs_init();
+ MOCK(get_or_state,
+ get_or_state_replacement);
+ MOCK(networkstatus_get_live_consensus,
+ mock_networkstatus_get_live_consensus);
+
+ dummy_state = tor_malloc_zero(sizeof(or_state_t));
+
+ ret = parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC",
+ &mock_ns.valid_after);
+ tt_int_op(ret, OP_EQ, 0);
+ ret = parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC",
+ &mock_ns.fresh_until);
+ tt_int_op(ret, OP_EQ, 0);
+
+ /* Create a service with no descriptor. It's added to the global map. */
+ service = hs_service_new(get_options());
+ tt_assert(service);
+ service->config.version = HS_VERSION_THREE;
+ ed25519_secret_key_generate(&service->keys.identity_sk, 0);
+ ed25519_public_key_generate(&service->keys.identity_pk,
+ &service->keys.identity_sk);
+ /* Register service to global map. */
+ ret = register_service(get_hs_service_map(), service);
+ tt_int_op(ret, OP_EQ, 0);
+ /* But first, build our descriptor. */
+ build_all_descriptors(now);
+
+ /* Nothing should happen because we have 0 introduction circuit established
+ * and we want (by default) 3 intro points. */
+ run_upload_descriptor_event(now);
+ /* If no upload happened, this should be untouched. */
+ tt_u64_op(service->desc_current->next_upload_time, OP_EQ, 0);
+ /* We'll simulate that we've opened our intro point circuit and that we only
+ * want one intro point. */
+ service->config.num_intro_points = 1;
+
+ /* Set our next upload time after now which will skip the upload. */
+ service->desc_current->next_upload_time = now + 1000;
+ run_upload_descriptor_event(now);
+ /* If no upload happened, this should be untouched. */
+ tt_u64_op(service->desc_current->next_upload_time, OP_EQ, now + 1000);
+
+ done:
+ hs_free_all();
+ UNMOCK(get_or_state);
+}
+
+/** Test the functions that save and load HS revision counters to state. */
+static void
+test_revision_counter_state(void *arg)
+{
+ char *state_line_one = NULL;
+ char *state_line_two = NULL;
+
+ hs_service_descriptor_t *desc_one = service_descriptor_new();
+ hs_service_descriptor_t *desc_two = service_descriptor_new();
+
+ (void) arg;
+
+ /* Prepare both descriptors */
+ desc_one->desc->plaintext_data.revision_counter = 42;
+ desc_two->desc->plaintext_data.revision_counter = 240;
+ memset(&desc_one->blinded_kp.pubkey.pubkey, 66,
+ sizeof(desc_one->blinded_kp.pubkey.pubkey));
+ memset(&desc_two->blinded_kp.pubkey.pubkey, 240,
+ sizeof(desc_one->blinded_kp.pubkey.pubkey));
+
+ /* Turn the descriptor rev counters into state lines */
+ state_line_one = encode_desc_rev_counter_for_state(desc_one);
+ tt_str_op(state_line_one, OP_EQ,
+ "QkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkI 42");
+
+ state_line_two = encode_desc_rev_counter_for_state(desc_two);
+ tt_str_op(state_line_two, OP_EQ,
+ "8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PA 240");
+
+ /* Now let's test our state parsing function: */
+ int service_found;
+ uint64_t cached_rev_counter;
+
+ /* First's try with wrong pubkey and check that no service was found */
+ cached_rev_counter =check_state_line_for_service_rev_counter(state_line_one,
+ &desc_two->blinded_kp.pubkey,
+ &service_found);
+ tt_int_op(service_found, OP_EQ, 0);
+ tt_u64_op(cached_rev_counter, OP_EQ, 0);
+
+ /* Now let's try with the right pubkeys */
+ cached_rev_counter =check_state_line_for_service_rev_counter(state_line_one,
+ &desc_one->blinded_kp.pubkey,
+ &service_found);
+ tt_int_op(service_found, OP_EQ, 1);
+ tt_u64_op(cached_rev_counter, OP_EQ, 42);
+
+ cached_rev_counter =check_state_line_for_service_rev_counter(state_line_two,
+ &desc_two->blinded_kp.pubkey,
+ &service_found);
+ tt_int_op(service_found, OP_EQ, 1);
+ tt_u64_op(cached_rev_counter, OP_EQ, 240);
+
+ done:
+ tor_free(state_line_one);
+ tor_free(state_line_two);
+ service_descriptor_free(desc_one);
+ service_descriptor_free(desc_two);
+}
+
+/** Global vars used by test_rendezvous1_parsing() */
+static char rend1_payload[RELAY_PAYLOAD_SIZE];
+static size_t rend1_payload_len = 0;
+
+/** Mock for relay_send_command_from_edge() to send a RENDEZVOUS1 cell. Instead
+ * of sending it to the network, instead save it to the global `rend1_payload`
+ * variable so that we can inspect it in the test_rendezvous1_parsing()
+ * test. */
+static int
+mock_relay_send_rendezvous1(streamid_t stream_id, circuit_t *circ,
+ uint8_t relay_command, const char *payload,
+ size_t payload_len,
+ crypt_path_t *cpath_layer,
+ const char *filename, int lineno)
+{
+ (void) stream_id;
+ (void) circ;
+ (void) relay_command;
+ (void) cpath_layer;
+ (void) filename;
+ (void) lineno;
+
+ memcpy(rend1_payload, payload, payload_len);
+ rend1_payload_len = payload_len;
+
+ return 0;
+}
+
+/** Send a RENDEZVOUS1 as a service, and parse it as a client. */
+static void
+test_rendezvous1_parsing(void *arg)
+{
+ int retval;
+ static const char *test_addr =
+ "4acth47i6kxnvkewtm6q7ib2s3ufpo5sqbsnzjpbi7utijcltosqemad.onion";
+ hs_service_t *service = NULL;
+ origin_circuit_t *service_circ = NULL;
+ origin_circuit_t *client_circ = NULL;
+ ed25519_keypair_t ip_auth_kp;
+ curve25519_keypair_t ephemeral_kp;
+ curve25519_keypair_t client_kp;
+ curve25519_keypair_t ip_enc_kp;
+ int flags = CIRCLAUNCH_NEED_UPTIME | CIRCLAUNCH_IS_INTERNAL;
+
+ (void) arg;
+
+ MOCK(relay_send_command_from_edge_, mock_relay_send_rendezvous1);
+
+ {
+ /* Let's start by setting up the service that will start the rend */
+ service = tor_malloc_zero(sizeof(hs_service_t));
+ ed25519_secret_key_generate(&service->keys.identity_sk, 0);
+ ed25519_public_key_generate(&service->keys.identity_pk,
+ &service->keys.identity_sk);
+ memcpy(service->onion_address, test_addr, sizeof(service->onion_address));
+ tt_assert(service);
+ }
+
+ {
+ /* Now let's set up the service rendezvous circuit and its keys. */
+ service_circ = helper_create_origin_circuit(CIRCUIT_PURPOSE_S_CONNECT_REND,
+ flags);
+ tor_free(service_circ->hs_ident);
+ hs_ntor_rend_cell_keys_t hs_ntor_rend_cell_keys;
+ uint8_t rendezvous_cookie[HS_REND_COOKIE_LEN];
+ curve25519_keypair_generate(&ip_enc_kp, 0);
+ curve25519_keypair_generate(&ephemeral_kp, 0);
+ curve25519_keypair_generate(&client_kp, 0);
+ ed25519_keypair_generate(&ip_auth_kp, 0);
+ retval = hs_ntor_service_get_rendezvous1_keys(&ip_auth_kp.pubkey,
+ &ip_enc_kp,
+ &ephemeral_kp,
+ &client_kp.pubkey,
+ &hs_ntor_rend_cell_keys);
+ tt_int_op(retval, OP_EQ, 0);
+
+ memset(rendezvous_cookie, 2, sizeof(rendezvous_cookie));
+ service_circ->hs_ident =
+ create_rp_circuit_identifier(service, rendezvous_cookie,
+ &ephemeral_kp.pubkey,
+ &hs_ntor_rend_cell_keys);
+ }
+
+ /* Send out the RENDEZVOUS1 and make sure that our mock func worked */
+ tt_assert(tor_mem_is_zero(rend1_payload, 32));
+ hs_circ_service_rp_has_opened(service, service_circ);
+ tt_assert(!tor_mem_is_zero(rend1_payload, 32));
+ tt_int_op(rend1_payload_len, OP_EQ, HS_LEGACY_RENDEZVOUS_CELL_SIZE);
+
+ /******************************/
+
+ /** Now let's create the client rendezvous circuit */
+ client_circ =
+ helper_create_origin_circuit(CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED,
+ flags);
+ /* fix up its circ ident */
+ ed25519_pubkey_copy(&client_circ->hs_ident->intro_auth_pk,
+ &ip_auth_kp.pubkey);
+ memcpy(&client_circ->hs_ident->rendezvous_client_kp,
+ &client_kp, sizeof(client_circ->hs_ident->rendezvous_client_kp));
+ memcpy(&client_circ->hs_ident->intro_enc_pk.public_key,
+ &ip_enc_kp.pubkey.public_key,
+ sizeof(client_circ->hs_ident->intro_enc_pk.public_key));
+
+ /* Now parse the rendezvous2 circuit and make sure it was fine. We are
+ * skipping 20 bytes off its payload, since that's the rendezvous cookie
+ * which is only present in REND1. */
+ retval = handle_rendezvous2(client_circ,
+ (uint8_t*)rend1_payload+20,
+ rend1_payload_len-20);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /* TODO: We are only simulating client/service here. We could also simulate
+ * the rendezvous point by plugging in rend_mid_establish_rendezvous(). We
+ * would need an extra circuit and some more stuff but it's doable. */
+
+ done:
+ circuit_free(TO_CIRCUIT(service_circ));
+ circuit_free(TO_CIRCUIT(client_circ));
+ hs_service_free(service);
+ hs_free_all();
+ UNMOCK(relay_send_command_from_edge_);
+}
+
+struct testcase_t hs_service_tests[] = {
+ { "e2e_rend_circuit_setup", test_e2e_rend_circuit_setup, TT_FORK,
+ NULL, NULL },
+ { "load_keys", test_load_keys, TT_FORK,
+ NULL, NULL },
+ { "access_service", test_access_service, TT_FORK,
+ NULL, NULL },
+ { "service_intro_point", test_service_intro_point, TT_FORK,
+ NULL, NULL },
+ { "helper_functions", test_helper_functions, TT_FORK,
+ NULL, NULL },
+ { "intro_circuit_opened", test_intro_circuit_opened, TT_FORK,
+ NULL, NULL },
+ { "intro_established", test_intro_established, TT_FORK,
+ NULL, NULL },
+ { "closing_intro_circs", test_closing_intro_circs, TT_FORK,
+ NULL, NULL },
+ { "rdv_circuit_opened", test_rdv_circuit_opened, TT_FORK,
+ NULL, NULL },
+ { "introduce2", test_introduce2, TT_FORK,
+ NULL, NULL },
+ { "service_event", test_service_event, TT_FORK,
+ NULL, NULL },
+ { "rotate_descriptors", test_rotate_descriptors, TT_FORK,
+ NULL, NULL },
+ { "build_update_descriptors", test_build_update_descriptors, TT_FORK,
+ NULL, NULL },
+ { "upload_descriptors", test_upload_descriptors, TT_FORK,
+ NULL, NULL },
+ { "revision_counter_state", test_revision_counter_state, TT_FORK,
+ NULL, NULL },
+ { "rendezvous1_parsing", test_rendezvous1_parsing, TT_FORK,
+ NULL, NULL },
+
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_introduce.c b/src/test/test_introduce.c
index 810b03c93d..d502bdddb1 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"
@@ -307,7 +307,7 @@ do_parse_test(uint8_t *plaintext, size_t plaintext_len, int phase)
/* Do early parsing */
parsed_req = rend_service_begin_parse_intro(cell, cell_len, 2, &err_msg);
tt_assert(parsed_req);
- tt_assert(!err_msg);
+ tt_ptr_op(err_msg, OP_EQ, NULL);
tt_mem_op(parsed_req->pk,OP_EQ, digest, DIGEST_LEN);
tt_assert(parsed_req->ciphertext);
tt_assert(parsed_req->ciphertext_len > 0);
@@ -318,7 +318,7 @@ do_parse_test(uint8_t *plaintext, size_t plaintext_len, int phase)
/* Do decryption */
r = rend_service_decrypt_intro(parsed_req, k, &err_msg);
tt_assert(!r);
- tt_assert(!err_msg);
+ tt_ptr_op(err_msg, OP_EQ, NULL);
tt_assert(parsed_req->plaintext);
tt_assert(parsed_req->plaintext_len > 0);
@@ -328,7 +328,7 @@ do_parse_test(uint8_t *plaintext, size_t plaintext_len, int phase)
/* Do late parsing */
r = rend_service_parse_intro_plaintext(parsed_req, &err_msg);
tt_assert(!r);
- tt_assert(!err_msg);
+ tt_ptr_op(err_msg, OP_EQ, NULL);
tt_assert(parsed_req->parsed);
done:
@@ -355,7 +355,7 @@ make_intro_from_plaintext(
/*
* Figure out an upper bound on how big the ciphertext will be
- * (see crypto_pk_public_hybrid_encrypt())
+ * (see crypto_pk_obsolete_public_hybrid_encrypt())
*/
ciphertext_size = PKCS1_OAEP_PADDING_OVERHEAD;
ciphertext_size += crypto_pk_keysize(key);
@@ -372,7 +372,7 @@ make_intro_from_plaintext(
tt_assert(r >= 0);
/* Do encryption */
- r = crypto_pk_public_hybrid_encrypt(
+ r = crypto_pk_obsolete_public_hybrid_encrypt(
key, cell + DIGEST_LEN, ciphertext_size,
buf, len,
PK_PKCS1_OAEP_PADDING, 0);
diff --git a/src/test/test_key_expiration.sh b/src/test/test_key_expiration.sh
new file mode 100755
index 0000000000..cf6608634d
--- /dev/null
+++ b/src/test/test_key_expiration.sh
@@ -0,0 +1,137 @@
+#!/bin/sh
+
+# Note: some of this code is lifted from zero_length_keys.sh and
+# test_keygen.sh, and could be unified.
+
+umask 077
+set -e
+
+if [ $# -eq 0 ] || [ ! -f ${1} ] || [ ! -x ${1} ]; then
+ if [ "$TESTING_TOR_BINARY" = "" ] ; then
+ echo "Usage: ${0} PATH_TO_TOR [case-number]"
+ exit 1
+ fi
+fi
+
+UNAME_OS=`uname -s | cut -d_ -f1`
+if test "$UNAME_OS" = 'CYGWIN' || \
+ test "$UNAME_OS" = 'MSYS' || \
+ test "$UNAME_OS" = 'MINGW'; then
+ echo "This test is unreliable on Windows. See trac #26076. Skipping." >&2
+ exit 77
+fi
+
+if [ $# -ge 1 ]; then
+ TOR_BINARY="${1}"
+ shift
+else
+ TOR_BINARY="${TESTING_TOR_BINARY}"
+fi
+
+if [ $# -ge 1 ]; then
+ dflt=0
+else
+ dflt=1
+fi
+
+CASE1=$dflt
+CASE2=$dflt
+CASE3=$dflt
+
+if [ $# -ge 1 ]; then
+ eval "CASE${1}"=1
+fi
+
+
+dump() { xxd -p "$1" | tr -d '\n '; }
+die() { echo "$1" >&2 ; exit 5; }
+check_dir() { [ -d "$1" ] || die "$1 did not exist"; }
+check_file() { [ -e "$1" ] || die "$1 did not exist"; }
+check_no_file() { [ -e "$1" ] && die "$1 was not supposed to exist" || true; }
+check_files_eq() { cmp "$1" "$2" || die "$1 and $2 did not match: `dump $1` vs `dump $2`"; }
+check_keys_eq() { check_files_eq "${SRC}/keys/${1}" "${ME}/keys/${1}"; }
+
+DATA_DIR=`mktemp -d -t tor_key_expiration_tests.XXXXXX`
+if [ -z "$DATA_DIR" ]; then
+ echo "Failure: mktemp invocation returned empty string" >&2
+ exit 3
+fi
+if [ ! -d "$DATA_DIR" ]; then
+ echo "Failure: mktemp invocation result doesn't point to directory" >&2
+ exit 3
+fi
+trap "rm -rf '$DATA_DIR'" 0
+
+# Use an absolute path for this or Tor will complain
+DATA_DIR=`cd "${DATA_DIR}" && pwd`
+
+touch "${DATA_DIR}/empty_torrc"
+
+QUIETLY="--hush"
+SILENTLY="--quiet"
+TOR="${TOR_BINARY} --DisableNetwork 1 --ShutdownWaitLength 0 --ORPort 12345 --ExitRelay 0 -f ${DATA_DIR}/empty_torrc --DataDirectory ${DATA_DIR}"
+
+##### SETUP
+#
+# Here we create a set of keys.
+
+# Step 1: Start Tor with --list-fingerprint --quiet. Make sure everything is there.
+echo "Setup step #1"
+${TOR} --list-fingerprint ${SILENTLY} > /dev/null
+
+check_dir "${DATA_DIR}/keys"
+check_file "${DATA_DIR}/keys/ed25519_master_id_public_key"
+check_file "${DATA_DIR}/keys/ed25519_master_id_secret_key"
+check_file "${DATA_DIR}/keys/ed25519_signing_cert"
+check_file "${DATA_DIR}/keys/ed25519_signing_secret_key"
+check_file "${DATA_DIR}/keys/secret_id_key"
+check_file "${DATA_DIR}/keys/secret_onion_key"
+check_file "${DATA_DIR}/keys/secret_onion_key_ntor"
+
+##### TEST CASES
+
+echo "=== Starting key expiration tests."
+
+FN="${DATA_DIR}/stderr"
+
+if [ "$CASE1" = 1 ]; then
+ echo "==== Case 1: Test --key-expiration without argument and ensure usage"
+ echo " instructions are printed."
+
+ ${TOR} ${QUIETLY} --key-expiration 2>"$FN" || true
+ grep "No valid argument to --key-expiration found!" "$FN" >/dev/null || \
+ die "Tor didn't mention supported --key-expiration argmuents"
+
+ echo "==== Case 1: ok"
+fi
+
+if [ "$CASE2" = 1 ]; then
+ echo "==== Case 2: Start Tor with --key-expiration 'sign' and make sure it prints an expiration."
+
+ ${TOR} ${QUIETLY} --key-expiration sign 2>"$FN"
+ grep "signing-cert-expiry:" "$FN" >/dev/null || \
+ die "Tor didn't print an expiration"
+
+ echo "==== Case 2: ok"
+fi
+
+if [ "$CASE3" = 1 ]; then
+ echo "==== Case 3: Start Tor with --key-expiration 'sign', when there is no"
+ echo " signing key, and make sure that Tor generates a new key"
+ echo " and prints its certificate's expiration."
+
+ mv "${DATA_DIR}/keys/ed25519_signing_cert" \
+ "${DATA_DIR}/keys/ed25519_signing_cert.bak"
+
+ ${TOR} --key-expiration sign > "$FN" 2>&1
+ grep "It looks like I need to generate and sign a new medium-term signing key" "$FN" >/dev/null || \
+ die "Tor didn't create a new signing key"
+ check_file "${DATA_DIR}/keys/ed25519_signing_cert"
+ grep "signing-cert-expiry:" "$FN" >/dev/null || \
+ die "Tor didn't print an expiration"
+
+ mv "${DATA_DIR}/keys/ed25519_signing_cert.bak" \
+ "${DATA_DIR}/keys/ed25519_signing_cert"
+
+ echo "==== Case 3: ok"
+fi
diff --git a/src/test/test_keypin.c b/src/test/test_keypin.c
index 95657349c6..79d7bac902 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"
@@ -20,8 +20,8 @@ test_keypin_parse_line(void *arg)
"aGVyZSBpcyBhIGdvb2Qgc2hhMSE "
"VGhpcyBlZDI1NTE5IHNjb2ZmcyBhdCB0aGUgc2hhMS4");
tt_assert(ent);
- tt_mem_op(ent->rsa_id, ==, "here is a good sha1!", 20);
- tt_mem_op(ent->ed25519_key, ==, "This ed25519 scoffs at the sha1.", 32);
+ tt_mem_op(ent->rsa_id, OP_EQ, "here is a good sha1!", 20);
+ tt_mem_op(ent->ed25519_key, OP_EQ, "This ed25519 scoffs at the sha1.", 32);
tor_free(ent); ent = NULL;
/* Good line with extra stuff we will ignore. */
@@ -29,27 +29,27 @@ test_keypin_parse_line(void *arg)
"aGVyZSBpcyBhIGdvb2Qgc2hhMSE "
"VGhpcyBlZDI1NTE5IHNjb2ZmcyBhdCB0aGUgc2hhMS4helloworld");
tt_assert(ent);
- tt_mem_op(ent->rsa_id, ==, "here is a good sha1!", 20);
- tt_mem_op(ent->ed25519_key, ==, "This ed25519 scoffs at the sha1.", 32);
+ tt_mem_op(ent->rsa_id, OP_EQ, "here is a good sha1!", 20);
+ tt_mem_op(ent->ed25519_key, OP_EQ, "This ed25519 scoffs at the sha1.", 32);
tor_free(ent); ent = NULL;
/* Bad line: no space in the middle. */
ent = keypin_parse_journal_line(
"aGVyZSBpcyBhIGdvb2Qgc2hhMSE?"
"VGhpcyBlZDI1NTE5IHNjb2ZmcyBhdCB0aGUgc2hhMS4");
- tt_assert(! ent);
+ tt_ptr_op(ent, OP_EQ, NULL);
/* Bad line: bad base64 in RSA ID */
ent = keypin_parse_journal_line(
"aGVyZSBpcyBhIGdv!2Qgc2hhMSE "
"VGhpcyBlZDI1NTE5IHNjb2ZmcyBhdCB0aGUgc2hhMS4");
- tt_assert(! ent);
+ tt_ptr_op(ent, OP_EQ, NULL);
/* Bad line: bad base64 in Ed25519 */
ent = keypin_parse_journal_line(
"aGVyZSBpcyBhIGdvb2Qgc2hhMSE "
"VGhpcyBlZDI1NTE5IHNjb2ZmcyB!dCB0aGUgc2hhMS4");
- tt_assert(! ent);
+ tt_ptr_op(ent, OP_EQ, NULL);
done:
tor_free(ent);
@@ -82,11 +82,11 @@ test_keypin_parse_file(void *arg)
"Z2dsZSBpbiBzd29tZWVzd2FucyA aW4gdm9sdXB0YXRlIGF4ZS1oYWNrZXIgZXNzZSByaXA\n"
"cHVsdXMgY3J1bW1paSBldSBtb28 ZiBudWxsYSBzbnV2di5QTFVHSFBMT1ZFUlhZWlpZLi4\n";
- tt_int_op(0, ==, keypin_load_journal_impl(data1, strlen(data1)));
- tt_int_op(8, ==, smartlist_len(mock_addent_got));
+ tt_int_op(0, OP_EQ, keypin_load_journal_impl(data1, strlen(data1)));
+ tt_int_op(8, OP_EQ, smartlist_len(mock_addent_got));
keypin_ent_t *ent = smartlist_get(mock_addent_got, 2);
- tt_mem_op(ent->rsa_id, ==, "r lerkim, sed do bar", 20);
- tt_mem_op(ent->ed25519_key, ==, "baloot tempor gluppitus ut labor", 32);
+ tt_mem_op(ent->rsa_id, OP_EQ, "r lerkim, sed do bar", 20);
+ tt_mem_op(ent->ed25519_key, OP_EQ, "baloot tempor gluppitus ut labor", 32);
/* More complex example: weird lines, bogus lines,
duplicate/conflicting lines */
@@ -107,24 +107,25 @@ test_keypin_parse_file(void *arg)
"ZHMgc3BlYWsgdHJ1dGgsIGFuZCA aXQgd2FzIHRydaUgdGhhdCBhbGwgdGhlIG1hc3Rlcgo\n"
;
- tt_int_op(0, ==, keypin_load_journal_impl(data2, strlen(data2)));
- tt_int_op(13, ==, smartlist_len(mock_addent_got));
+ tt_int_op(0, OP_EQ, keypin_load_journal_impl(data2, strlen(data2)));
+ tt_int_op(13, OP_EQ, smartlist_len(mock_addent_got));
ent = smartlist_get(mock_addent_got, 9);
- tt_mem_op(ent->rsa_id, ==, "\"You have made a goo", 20);
- tt_mem_op(ent->ed25519_key, ==, "d beginning.\" But no more. Wizar", 32);
+ tt_mem_op(ent->rsa_id, OP_EQ, "\"You have made a goo", 20);
+ tt_mem_op(ent->ed25519_key, OP_EQ, "d beginning.\" But no more. Wizar", 32);
ent = smartlist_get(mock_addent_got, 12);
- tt_mem_op(ent->rsa_id, ==, "ds speak truth, and ", 20);
- tt_mem_op(ent->ed25519_key, ==, "it was tru\xa5 that all the master\n", 32);
+ tt_mem_op(ent->rsa_id, OP_EQ, "ds speak truth, and ", 20);
+ tt_mem_op(ent->ed25519_key, OP_EQ,
+ "it was tru\xa5 that all the master\n", 32);
/* File truncated before NL */
const char data3[] =
"Tm8gZHJhZ29uIGNhbiByZXNpc3Q IHRoZSBmYXNjaW5hdGlvbiBvZiByaWRkbGluZyB0YWw";
- tt_int_op(0, ==, keypin_load_journal_impl(data3, strlen(data3)));
- tt_int_op(14, ==, smartlist_len(mock_addent_got));
+ tt_int_op(0, OP_EQ, keypin_load_journal_impl(data3, strlen(data3)));
+ tt_int_op(14, OP_EQ, smartlist_len(mock_addent_got));
ent = smartlist_get(mock_addent_got, 13);
- tt_mem_op(ent->rsa_id, ==, "No dragon can resist", 20);
- tt_mem_op(ent->ed25519_key, ==, " the fascination of riddling tal", 32);
+ tt_mem_op(ent->rsa_id, OP_EQ, "No dragon can resist", 20);
+ tt_mem_op(ent->ed25519_key, OP_EQ, " the fascination of riddling tal", 32);
done:
keypin_clear();
@@ -141,32 +142,32 @@ test_keypin_add_entry(void *arg)
(void)arg;
keypin_clear();
- tt_int_op(KEYPIN_ADDED, ==, ADD("ambassadors-at-large",
+ tt_int_op(KEYPIN_ADDED, OP_EQ, ADD("ambassadors-at-large",
"bread-and-butter thing-in-itself"));
- tt_int_op(KEYPIN_ADDED, ==, ADD("gentleman-adventurer",
+ tt_int_op(KEYPIN_ADDED, OP_EQ, ADD("gentleman-adventurer",
"cloak-and-dagger what's-his-face"));
- tt_int_op(KEYPIN_FOUND, ==, ADD("ambassadors-at-large",
+ tt_int_op(KEYPIN_FOUND, OP_EQ, ADD("ambassadors-at-large",
"bread-and-butter thing-in-itself"));
- tt_int_op(KEYPIN_FOUND, ==, ADD("ambassadors-at-large",
+ tt_int_op(KEYPIN_FOUND, OP_EQ, ADD("ambassadors-at-large",
"bread-and-butter thing-in-itself"));
- tt_int_op(KEYPIN_FOUND, ==, ADD("gentleman-adventurer",
+ tt_int_op(KEYPIN_FOUND, OP_EQ, ADD("gentleman-adventurer",
"cloak-and-dagger what's-his-face"));
- tt_int_op(KEYPIN_ADDED, ==, ADD("Johnnies-come-lately",
+ tt_int_op(KEYPIN_ADDED, OP_EQ, ADD("Johnnies-come-lately",
"run-of-the-mill root-mean-square"));
- tt_int_op(KEYPIN_MISMATCH, ==, ADD("gentleman-adventurer",
+ tt_int_op(KEYPIN_MISMATCH, OP_EQ, ADD("gentleman-adventurer",
"hypersentimental closefistedness"));
- tt_int_op(KEYPIN_MISMATCH, ==, ADD("disestablismentarian",
+ tt_int_op(KEYPIN_MISMATCH, OP_EQ, ADD("disestablismentarian",
"cloak-and-dagger what's-his-face"));
- tt_int_op(KEYPIN_FOUND, ==, ADD("gentleman-adventurer",
+ tt_int_op(KEYPIN_FOUND, OP_EQ, ADD("gentleman-adventurer",
"cloak-and-dagger what's-his-face"));
- tt_int_op(KEYPIN_NOT_FOUND, ==, LONE_RSA("Llanfairpwllgwyngyll"));
- tt_int_op(KEYPIN_MISMATCH, ==, LONE_RSA("Johnnies-come-lately"));
+ tt_int_op(KEYPIN_NOT_FOUND, OP_EQ, LONE_RSA("Llanfairpwllgwyngyll"));
+ tt_int_op(KEYPIN_MISMATCH, OP_EQ, LONE_RSA("Johnnies-come-lately"));
done:
keypin_clear();
@@ -179,51 +180,51 @@ test_keypin_journal(void *arg)
char *contents = NULL;
const char *fname = get_fname("keypin-journal");
- tt_int_op(0, ==, keypin_load_journal(fname)); /* ENOENT is okay */
+ tt_int_op(0, OP_EQ, keypin_load_journal(fname)); /* ENOENT is okay */
update_approx_time(1217709000);
- tt_int_op(0, ==, keypin_open_journal(fname));
+ tt_int_op(0, OP_EQ, keypin_open_journal(fname));
- tt_int_op(KEYPIN_ADDED, ==, ADD("king-of-the-herrings",
+ tt_int_op(KEYPIN_ADDED, OP_EQ, ADD("king-of-the-herrings",
"good-for-nothing attorney-at-law"));
- tt_int_op(KEYPIN_ADDED, ==, ADD("yellowish-red-yellow",
+ tt_int_op(KEYPIN_ADDED, OP_EQ, ADD("yellowish-red-yellow",
"salt-and-pepper high-muck-a-muck"));
- tt_int_op(KEYPIN_FOUND, ==, ADD("yellowish-red-yellow",
+ tt_int_op(KEYPIN_FOUND, OP_EQ, ADD("yellowish-red-yellow",
"salt-and-pepper high-muck-a-muck"));
keypin_close_journal();
keypin_clear();
- tt_int_op(0, ==, keypin_load_journal(fname));
+ tt_int_op(0, OP_EQ, keypin_load_journal(fname));
update_approx_time(1231041600);
- tt_int_op(0, ==, keypin_open_journal(fname));
- tt_int_op(KEYPIN_FOUND, ==, ADD("yellowish-red-yellow",
+ tt_int_op(0, OP_EQ, keypin_open_journal(fname));
+ tt_int_op(KEYPIN_FOUND, OP_EQ, ADD("yellowish-red-yellow",
"salt-and-pepper high-muck-a-muck"));
- tt_int_op(KEYPIN_ADDED, ==, ADD("theatre-in-the-round",
+ tt_int_op(KEYPIN_ADDED, OP_EQ, ADD("theatre-in-the-round",
"holier-than-thou jack-in-the-box"));
- tt_int_op(KEYPIN_ADDED, ==, ADD("no-deposit-no-return",
+ tt_int_op(KEYPIN_ADDED, OP_EQ, ADD("no-deposit-no-return",
"across-the-board will-o-the-wisp"));
- tt_int_op(KEYPIN_MISMATCH, ==, ADD("intellectualizations",
+ tt_int_op(KEYPIN_MISMATCH, OP_EQ, ADD("intellectualizations",
"salt-and-pepper high-muck-a-muck"));
keypin_close_journal();
keypin_clear();
- tt_int_op(0, ==, keypin_load_journal(fname));
+ tt_int_op(0, OP_EQ, keypin_load_journal(fname));
update_approx_time(1412278354);
- tt_int_op(0, ==, keypin_open_journal(fname));
- tt_int_op(KEYPIN_FOUND, ==, ADD("yellowish-red-yellow",
+ tt_int_op(0, OP_EQ, keypin_open_journal(fname));
+ tt_int_op(KEYPIN_FOUND, OP_EQ, ADD("yellowish-red-yellow",
"salt-and-pepper high-muck-a-muck"));
- tt_int_op(KEYPIN_MISMATCH, ==, ADD("intellectualizations",
+ tt_int_op(KEYPIN_MISMATCH, OP_EQ, ADD("intellectualizations",
"salt-and-pepper high-muck-a-muck"));
- tt_int_op(KEYPIN_FOUND, ==, ADD("theatre-in-the-round",
+ tt_int_op(KEYPIN_FOUND, OP_EQ, ADD("theatre-in-the-round",
"holier-than-thou jack-in-the-box"));
- tt_int_op(KEYPIN_MISMATCH, ==, ADD("counterrevolutionary",
+ tt_int_op(KEYPIN_MISMATCH, OP_EQ, ADD("counterrevolutionary",
"holier-than-thou jack-in-the-box"));
- tt_int_op(KEYPIN_MISMATCH, ==, ADD("no-deposit-no-return",
+ tt_int_op(KEYPIN_MISMATCH, OP_EQ, ADD("no-deposit-no-return",
"floccinaucinihilipilificationism"));
keypin_close_journal();
contents = read_file_to_str(fname, RFTS_BIN, NULL);
tt_assert(contents);
- tt_str_op(contents,==,
+ tt_str_op(contents,OP_EQ,
"\n"
"@opened-at 2008-08-02 20:30:00\n"
"a2luZy1vZi10aGUtaGVycmluZ3M Z29vZC1mb3Itbm90aGluZyBhdHRvcm5leS1hdC1sYXc\n"
diff --git a/src/test/test_link_handshake.c b/src/test/test_link_handshake.c
index ddf66f4d34..422d419078 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"
@@ -6,13 +6,20 @@
#define CHANNELTLS_PRIVATE
#define CONNECTION_PRIVATE
#define TOR_CHANNEL_INTERNAL_
+#define TORTLS_PRIVATE
+
+#include "compat.h"
+
#include "or.h"
#include "config.h"
#include "connection.h"
#include "connection_or.h"
#include "channeltls.h"
#include "link_handshake.h"
+#include "router.h"
+#include "routerkeys.h"
#include "scheduler.h"
+#include "torcert.h"
#include "test.h"
#include "log_test_helpers.h"
@@ -37,6 +44,16 @@ mock_tls_cert_matches_key(const tor_tls_t *tls, const tor_x509_cert_t *cert)
(void) cert; // XXXX look at this.
return 1;
}
+static tor_tls_t *mock_peer_cert_expect_tortls = NULL;
+static tor_x509_cert_t *mock_peer_cert = NULL;
+static tor_x509_cert_t *
+mock_get_peer_cert(tor_tls_t *tls)
+{
+ if (mock_peer_cert_expect_tortls &&
+ mock_peer_cert_expect_tortls != tls)
+ return NULL;
+ return tor_x509_cert_dup(mock_peer_cert);
+}
static int mock_send_netinfo_called = 0;
static int
@@ -57,14 +74,29 @@ mock_close_for_err(or_connection_t *orconn, int flush)
}
static int mock_send_authenticate_called = 0;
+static int mock_send_authenticate_called_with_type = 0;
static int
mock_send_authenticate(or_connection_t *conn, int type)
{
(void) conn;
- (void) type;
+ mock_send_authenticate_called_with_type = type;
++mock_send_authenticate_called;// XXX check_this
return 0;
}
+static int
+mock_export_key_material(tor_tls_t *tls, uint8_t *secrets_out,
+ const uint8_t *context,
+ size_t context_len,
+ const char *label)
+{
+ (void) tls;
+ (void)secrets_out;
+ (void)context;
+ (void)context_len;
+ (void)label;
+ memcpy(secrets_out, "int getRandomNumber(){return 4;}", 32);
+ return 0;
+}
static tor_x509_cert_t *mock_own_cert = NULL;
static tor_x509_cert_t *
@@ -78,20 +110,23 @@ mock_get_own_cert(tor_tls_t *tls)
static void
test_link_handshake_certs_ok(void *arg)
{
- (void) arg;
-
or_connection_t *c1 = or_connection_new(CONN_TYPE_OR, AF_INET);
or_connection_t *c2 = or_connection_new(CONN_TYPE_OR, AF_INET);
var_cell_t *cell1 = NULL, *cell2 = NULL;
certs_cell_t *cc1 = NULL, *cc2 = NULL;
channel_tls_t *chan1 = NULL, *chan2 = NULL;
crypto_pk_t *key1 = NULL, *key2 = NULL;
+ const int with_ed = !strcmp((const char *)arg, "Ed25519");
+
+ tor_addr_from_ipv4h(&c1->base_.addr, 0x7f000001);
+ tor_addr_from_ipv4h(&c2->base_.addr, 0x7f000001);
scheduler_init();
MOCK(tor_tls_cert_matches_key, mock_tls_cert_matches_key);
MOCK(connection_or_write_var_cell_to_buf, mock_write_var_cell);
MOCK(connection_or_send_netinfo, mock_send_netinfo);
+ MOCK(tor_tls_get_peer_cert, mock_get_peer_cert);
MOCK(tor_tls_get_own_cert, mock_get_own_cert);
key1 = pk_generate(2);
@@ -101,8 +136,17 @@ test_link_handshake_certs_ok(void *arg)
* actually generate a CERTS cell.
*/
tt_int_op(tor_tls_context_init(TOR_TLS_CTX_IS_PUBLIC_SERVER,
- key1, key2, 86400), ==, 0);
+ key1, key2, 86400), OP_EQ, 0);
+
+ if (with_ed) {
+ /* If we're making a CERTS cell for an ed handshake, let's make sure we
+ * have some Ed25519 certificates and keys. */
+ init_mock_ed_keys(key2);
+ } else {
+ certs_cell_ed25519_disabled_for_testing = 1;
+ }
+ /* c1 has started_here == 1 */
{
const tor_x509_cert_t *link_cert = NULL;
tt_assert(!tor_tls_get_my_certs(1, &link_cert, NULL));
@@ -111,44 +155,66 @@ test_link_handshake_certs_ok(void *arg)
c1->base_.state = OR_CONN_STATE_OR_HANDSHAKING_V3;
c1->link_proto = 3;
- tt_int_op(connection_init_or_handshake_state(c1, 1), ==, 0);
+ tt_int_op(connection_init_or_handshake_state(c1, 1), OP_EQ, 0);
+ /* c2 has started_here == 0 */
c2->base_.state = OR_CONN_STATE_OR_HANDSHAKING_V3;
c2->link_proto = 3;
- tt_int_op(connection_init_or_handshake_state(c2, 0), ==, 0);
+ tt_int_op(connection_init_or_handshake_state(c2, 0), OP_EQ, 0);
- tt_int_op(0, ==, connection_or_send_certs_cell(c1));
+ tt_int_op(0, OP_EQ, connection_or_send_certs_cell(c1));
tt_assert(mock_got_var_cell);
cell1 = mock_got_var_cell;
- tt_int_op(0, ==, connection_or_send_certs_cell(c2));
+ tt_int_op(0, OP_EQ, connection_or_send_certs_cell(c2));
tt_assert(mock_got_var_cell);
cell2 = mock_got_var_cell;
- tt_int_op(cell1->command, ==, CELL_CERTS);
- tt_int_op(cell1->payload_len, >, 1);
+ tt_int_op(cell1->command, OP_EQ, CELL_CERTS);
+ tt_int_op(cell1->payload_len, OP_GT, 1);
- tt_int_op(cell2->command, ==, CELL_CERTS);
- tt_int_op(cell2->payload_len, >, 1);
+ tt_int_op(cell2->command, OP_EQ, CELL_CERTS);
+ tt_int_op(cell2->payload_len, OP_GT, 1);
- tt_int_op(cell1->payload_len, ==,
+ tt_int_op(cell1->payload_len, OP_EQ,
certs_cell_parse(&cc1, cell1->payload, cell1->payload_len));
- tt_int_op(cell2->payload_len, ==,
+ tt_int_op(cell2->payload_len, OP_EQ,
certs_cell_parse(&cc2, cell2->payload, cell2->payload_len));
- tt_int_op(2, ==, cc1->n_certs);
- tt_int_op(2, ==, cc2->n_certs);
+ if (with_ed) {
+ tt_int_op(5, OP_EQ, cc1->n_certs);
+ tt_int_op(5, OP_EQ, cc2->n_certs);
+ } else {
+ tt_int_op(2, OP_EQ, cc1->n_certs);
+ tt_int_op(2, OP_EQ, cc2->n_certs);
+ }
- tt_int_op(certs_cell_get_certs(cc1, 0)->cert_type, ==,
+ tt_int_op(certs_cell_get_certs(cc1, 0)->cert_type, OP_EQ,
CERTTYPE_RSA1024_ID_AUTH);
- tt_int_op(certs_cell_get_certs(cc1, 1)->cert_type, ==,
+ tt_int_op(certs_cell_get_certs(cc1, 1)->cert_type, OP_EQ,
CERTTYPE_RSA1024_ID_ID);
- tt_int_op(certs_cell_get_certs(cc2, 0)->cert_type, ==,
+ tt_int_op(certs_cell_get_certs(cc2, 0)->cert_type, OP_EQ,
CERTTYPE_RSA1024_ID_LINK);
- tt_int_op(certs_cell_get_certs(cc2, 1)->cert_type, ==,
+ tt_int_op(certs_cell_get_certs(cc2, 1)->cert_type, OP_EQ,
CERTTYPE_RSA1024_ID_ID);
+ if (with_ed) {
+ tt_int_op(certs_cell_get_certs(cc1, 2)->cert_type, OP_EQ,
+ CERTTYPE_ED_ID_SIGN);
+ tt_int_op(certs_cell_get_certs(cc1, 3)->cert_type, OP_EQ,
+ CERTTYPE_ED_SIGN_AUTH);
+ tt_int_op(certs_cell_get_certs(cc1, 4)->cert_type, OP_EQ,
+ CERTTYPE_RSA1024_ID_EDID);
+
+ tt_int_op(certs_cell_get_certs(cc2, 2)->cert_type, OP_EQ,
+ CERTTYPE_ED_ID_SIGN);
+ tt_int_op(certs_cell_get_certs(cc2, 3)->cert_type, OP_EQ,
+ CERTTYPE_ED_SIGN_LINK);
+ tt_int_op(certs_cell_get_certs(cc2, 4)->cert_type, OP_EQ,
+ CERTTYPE_RSA1024_ID_EDID);
+ }
+
chan1 = tor_malloc_zero(sizeof(*chan1));
channel_tls_common_init(chan1);
c1->chan = chan1;
@@ -159,13 +225,39 @@ test_link_handshake_certs_ok(void *arg)
c1->base_.conn_array_index = -1;
crypto_pk_get_digest(key2, c1->identity_digest);
+ if (with_ed) {
+ const tor_x509_cert_t *linkc, *idc;
+ tor_tls_get_my_certs(1, &linkc, &idc);
+ mock_peer_cert_expect_tortls = c1->tls; /* We should see this tls... */
+ mock_peer_cert = tor_x509_cert_dup(linkc); /* and when we do, the peer's
+ * cert is this... */
+ }
channel_tls_process_certs_cell(cell2, chan1);
+ mock_peer_cert_expect_tortls = NULL;
+ tor_x509_cert_free(mock_peer_cert);
+ mock_peer_cert = NULL;
+
+ tor_assert(c1->handshake_state->authenticated);
tt_assert(c1->handshake_state->received_certs_cell);
- tt_assert(c1->handshake_state->auth_cert == NULL);
- tt_assert(c1->handshake_state->id_cert);
+ tt_ptr_op(c1->handshake_state->certs->auth_cert, OP_EQ, NULL);
+ tt_ptr_op(c1->handshake_state->certs->ed_sign_auth, OP_EQ, NULL);
+ tt_assert(c1->handshake_state->certs->id_cert);
+ if (with_ed) {
+ tt_assert(c1->handshake_state->certs->ed_sign_link);
+ tt_assert(c1->handshake_state->certs->ed_rsa_crosscert);
+ tt_assert(c1->handshake_state->certs->ed_id_sign);
+ tt_assert(c1->handshake_state->authenticated_rsa);
+ tt_assert(c1->handshake_state->authenticated_ed25519);
+ } else {
+ tt_ptr_op(c1->handshake_state->certs->ed_sign_link, OP_EQ, NULL);
+ tt_ptr_op(c1->handshake_state->certs->ed_rsa_crosscert, OP_EQ, NULL);
+ tt_ptr_op(c1->handshake_state->certs->ed_id_sign, OP_EQ, NULL);
+ tt_assert(c1->handshake_state->authenticated_rsa);
+ tt_assert(! c1->handshake_state->authenticated_ed25519);
+ }
tt_assert(! tor_mem_is_zero(
- (char*)c1->handshake_state->authenticated_peer_id, 20));
+ (char*)c1->handshake_state->authenticated_rsa_peer_id, 20));
chan2 = tor_malloc_zero(sizeof(*chan2));
channel_tls_common_init(chan2);
@@ -180,18 +272,34 @@ test_link_handshake_certs_ok(void *arg)
channel_tls_process_certs_cell(cell1, chan2);
tt_assert(c2->handshake_state->received_certs_cell);
- tt_assert(c2->handshake_state->auth_cert);
- tt_assert(c2->handshake_state->id_cert);
+ if (with_ed) {
+ tt_assert(c2->handshake_state->certs->ed_sign_auth);
+ tt_assert(c2->handshake_state->certs->ed_rsa_crosscert);
+ tt_assert(c2->handshake_state->certs->ed_id_sign);
+ } else {
+ tt_assert(c2->handshake_state->certs->auth_cert);
+ tt_ptr_op(c2->handshake_state->certs->ed_sign_auth, OP_EQ, NULL);
+ tt_ptr_op(c2->handshake_state->certs->ed_rsa_crosscert, OP_EQ, NULL);
+ tt_ptr_op(c2->handshake_state->certs->ed_id_sign, OP_EQ, NULL);
+ }
+ tt_assert(c2->handshake_state->certs->id_cert);
tt_assert(tor_mem_is_zero(
- (char*)c2->handshake_state->authenticated_peer_id, 20));
+ (char*)c2->handshake_state->authenticated_rsa_peer_id, 20));
+ /* no authentication has happened yet, since we haen't gotten an AUTH cell.
+ */
+ tt_assert(! c2->handshake_state->authenticated);
+ tt_assert(! c2->handshake_state->authenticated_rsa);
+ tt_assert(! c2->handshake_state->authenticated_ed25519);
done:
UNMOCK(tor_tls_cert_matches_key);
UNMOCK(connection_or_write_var_cell_to_buf);
UNMOCK(connection_or_send_netinfo);
+ UNMOCK(tor_tls_get_peer_cert);
UNMOCK(tor_tls_get_own_cert);
tor_x509_cert_free(mock_own_cert);
- mock_own_cert = NULL;
+ tor_x509_cert_free(mock_peer_cert);
+ mock_own_cert = mock_peer_cert = NULL;
memset(c1->identity_digest, 0, sizeof(c1->identity_digest));
memset(c2->identity_digest, 0, sizeof(c2->identity_digest));
connection_free_(TO_CONN(c1));
@@ -211,6 +319,8 @@ test_link_handshake_certs_ok(void *arg)
}
typedef struct certs_data_s {
+ int is_ed;
+ int is_link_cert;
or_connection_t *c;
channel_tls_t *chan;
certs_cell_t *ccell;
@@ -226,11 +336,13 @@ recv_certs_cleanup(const struct testcase_t *test, void *obj)
UNMOCK(tor_tls_cert_matches_key);
UNMOCK(connection_or_send_netinfo);
UNMOCK(connection_or_close_for_error);
+ UNMOCK(tor_tls_get_peer_cert);
+ UNMOCK(tor_tls_get_own_cert);
if (d) {
tor_free(d->cell);
certs_cell_free(d->ccell);
- connection_or_remove_from_identity_map(d->c);
+ connection_or_clear_identity(d->c);
connection_free_(TO_CONN(d->c));
circuitmux_free(d->chan->base_.cmux);
tor_free(d->chan);
@@ -238,6 +350,7 @@ recv_certs_cleanup(const struct testcase_t *test, void *obj)
crypto_pk_free(d->key2);
tor_free(d);
}
+ routerkeys_free_all();
return 1;
}
@@ -249,34 +362,47 @@ recv_certs_setup(const struct testcase_t *test)
certs_cell_cert_t *ccc1 = NULL;
certs_cell_cert_t *ccc2 = NULL;
ssize_t n;
+ int is_ed = d->is_ed = !strcmpstart(test->setup_data, "Ed25519");
+ int is_rsa = !strcmpstart(test->setup_data, "RSA");
+ int is_link = d->is_link_cert = !strcmpend(test->setup_data, "-Link");
+ int is_auth = !strcmpend(test->setup_data, "-Auth");
+ tor_assert(is_ed != is_rsa);
+ tor_assert(is_link != is_auth);
d->c = or_connection_new(CONN_TYPE_OR, AF_INET);
d->chan = tor_malloc_zero(sizeof(*d->chan));
d->c->chan = d->chan;
d->c->base_.address = tor_strdup("HaveAnAddress");
+ tor_addr_from_ipv4h(&d->c->base_.addr, 0x801f0127);
d->c->base_.state = OR_CONN_STATE_OR_HANDSHAKING_V3;
d->chan->conn = d->c;
- tt_int_op(connection_init_or_handshake_state(d->c, 1), ==, 0);
+ tt_int_op(connection_init_or_handshake_state(d->c, 1), OP_EQ, 0);
d->c->link_proto = 4;
d->key1 = pk_generate(2);
d->key2 = pk_generate(3);
tt_int_op(tor_tls_context_init(TOR_TLS_CTX_IS_PUBLIC_SERVER,
- d->key1, d->key2, 86400), ==, 0);
+ d->key1, d->key2, 86400), OP_EQ, 0);
+ if (is_ed) {
+ init_mock_ed_keys(d->key2);
+ } else {
+ routerkeys_free_all();
+ }
+
d->ccell = certs_cell_new();
ccc1 = certs_cell_cert_new();
certs_cell_add_certs(d->ccell, ccc1);
ccc2 = certs_cell_cert_new();
certs_cell_add_certs(d->ccell, ccc2);
d->ccell->n_certs = 2;
- ccc1->cert_type = 1;
+ ccc1->cert_type = is_link ? 1 : 3;
ccc2->cert_type = 2;
const tor_x509_cert_t *a,*b;
const uint8_t *enca, *encb;
size_t lena, lenb;
- tor_tls_get_my_certs(1, &a, &b);
+ tor_tls_get_my_certs(is_link ? 1 : 0, &a, &b);
tor_x509_cert_get_der(a, &enca, &lena);
tor_x509_cert_get_der(b, &encb, &lenb);
certs_cell_cert_setlen_body(ccc1, lena);
@@ -287,20 +413,61 @@ recv_certs_setup(const struct testcase_t *test)
memcpy(certs_cell_cert_getarray_body(ccc1), enca, lena);
memcpy(certs_cell_cert_getarray_body(ccc2), encb, lenb);
+ if (is_ed) {
+ certs_cell_cert_t *ccc3 = NULL; /* Id->Sign */
+ certs_cell_cert_t *ccc4 = NULL; /* Sign->Link or Sign->Auth. */
+ certs_cell_cert_t *ccc5 = NULL; /* RSAId->Ed Id. */
+ const tor_cert_t *id_sign = get_master_signing_key_cert();
+ const tor_cert_t *secondary =
+ is_link ? get_current_link_cert_cert() : get_current_auth_key_cert();
+ const uint8_t *cc = NULL;
+ size_t cc_sz;
+ get_master_rsa_crosscert(&cc, &cc_sz);
+
+ ccc3 = certs_cell_cert_new();
+ ccc4 = certs_cell_cert_new();
+ ccc5 = certs_cell_cert_new();
+ certs_cell_add_certs(d->ccell, ccc3);
+ certs_cell_add_certs(d->ccell, ccc4);
+ certs_cell_add_certs(d->ccell, ccc5);
+ ccc3->cert_len = id_sign->encoded_len;
+ ccc4->cert_len = secondary->encoded_len;
+ ccc5->cert_len = cc_sz;
+ certs_cell_cert_setlen_body(ccc3, ccc3->cert_len);
+ certs_cell_cert_setlen_body(ccc4, ccc4->cert_len);
+ certs_cell_cert_setlen_body(ccc5, ccc5->cert_len);
+ memcpy(certs_cell_cert_getarray_body(ccc3), id_sign->encoded,
+ ccc3->cert_len);
+ memcpy(certs_cell_cert_getarray_body(ccc4), secondary->encoded,
+ ccc4->cert_len);
+ memcpy(certs_cell_cert_getarray_body(ccc5), cc, ccc5->cert_len);
+ ccc3->cert_type = 4;
+ ccc4->cert_type = is_link ? 5 : 6;
+ ccc5->cert_type = 7;
+
+ d->ccell->n_certs = 5;
+ }
+
d->cell = var_cell_new(4096);
d->cell->command = CELL_CERTS;
n = certs_cell_encode(d->cell->payload, 4096, d->ccell);
- tt_int_op(n, >, 0);
+ tt_int_op(n, OP_GT, 0);
d->cell->payload_len = n;
MOCK(tor_tls_cert_matches_key, mock_tls_cert_matches_key);
MOCK(connection_or_send_netinfo, mock_send_netinfo);
MOCK(connection_or_close_for_error, mock_close_for_err);
+ MOCK(tor_tls_get_peer_cert, mock_get_peer_cert);
+
+ if (is_link) {
+ /* Say that this is the peer's certificate */
+ mock_peer_cert = tor_x509_cert_dup(a);
+ }
- tt_int_op(0, ==, d->c->handshake_state->received_certs_cell);
- tt_int_op(0, ==, mock_send_authenticate_called);
- tt_int_op(0, ==, mock_send_netinfo_called);
+ tt_int_op(0, OP_EQ, d->c->handshake_state->received_certs_cell);
+ tt_int_op(0, OP_EQ, mock_send_authenticate_called);
+ tt_int_op(0, OP_EQ, mock_send_netinfo_called);
return d;
done:
@@ -318,11 +485,26 @@ test_link_handshake_recv_certs_ok(void *arg)
{
certs_data_t *d = arg;
channel_tls_process_certs_cell(d->cell, d->chan);
- tt_int_op(0, ==, mock_close_called);
- tt_int_op(d->c->handshake_state->authenticated, ==, 1);
- tt_int_op(d->c->handshake_state->received_certs_cell, ==, 1);
- tt_assert(d->c->handshake_state->id_cert != NULL);
- tt_assert(d->c->handshake_state->auth_cert == NULL);
+ tt_int_op(0, OP_EQ, mock_close_called);
+ tt_int_op(d->c->handshake_state->authenticated, OP_EQ, 1);
+ tt_int_op(d->c->handshake_state->authenticated_rsa, OP_EQ, 1);
+ tt_int_op(d->c->handshake_state->received_certs_cell, OP_EQ, 1);
+ tt_ptr_op(d->c->handshake_state->certs->id_cert, OP_NE, NULL);
+ tt_ptr_op(d->c->handshake_state->certs->auth_cert, OP_EQ, NULL);
+
+ if (d->is_ed) {
+ tt_ptr_op(d->c->handshake_state->certs->ed_id_sign, OP_NE, NULL);
+ tt_ptr_op(d->c->handshake_state->certs->ed_sign_link, OP_NE, NULL);
+ tt_ptr_op(d->c->handshake_state->certs->ed_sign_auth, OP_EQ, NULL);
+ tt_ptr_op(d->c->handshake_state->certs->ed_rsa_crosscert, OP_NE, NULL);
+ tt_int_op(d->c->handshake_state->authenticated_ed25519, OP_EQ, 1);
+ } else {
+ tt_ptr_op(d->c->handshake_state->certs->ed_id_sign, OP_EQ, NULL);
+ tt_ptr_op(d->c->handshake_state->certs->ed_sign_link, OP_EQ, NULL);
+ tt_ptr_op(d->c->handshake_state->certs->ed_sign_auth, OP_EQ, NULL);
+ tt_ptr_op(d->c->handshake_state->certs->ed_rsa_crosscert, OP_EQ, NULL);
+ tt_int_op(d->c->handshake_state->authenticated_ed25519, OP_EQ, 0);
+ }
done:
;
@@ -333,17 +515,20 @@ test_link_handshake_recv_certs_ok_server(void *arg)
{
certs_data_t *d = arg;
d->c->handshake_state->started_here = 0;
- certs_cell_get_certs(d->ccell, 0)->cert_type = 3;
- certs_cell_get_certs(d->ccell, 1)->cert_type = 2;
- ssize_t n = certs_cell_encode(d->cell->payload, 2048, d->ccell);
- tt_int_op(n, >, 0);
- d->cell->payload_len = n;
+ d->c->handshake_state->certs->started_here = 0;
channel_tls_process_certs_cell(d->cell, d->chan);
- tt_int_op(0, ==, mock_close_called);
- tt_int_op(d->c->handshake_state->authenticated, ==, 0);
- tt_int_op(d->c->handshake_state->received_certs_cell, ==, 1);
- tt_assert(d->c->handshake_state->id_cert != NULL);
- tt_assert(d->c->handshake_state->auth_cert != NULL);
+ tt_int_op(0, OP_EQ, mock_close_called);
+ tt_int_op(d->c->handshake_state->authenticated, OP_EQ, 0);
+ tt_int_op(d->c->handshake_state->received_certs_cell, OP_EQ, 1);
+ tt_ptr_op(d->c->handshake_state->certs->id_cert, OP_NE, NULL);
+ tt_ptr_op(d->c->handshake_state->certs->link_cert, OP_EQ, NULL);
+ if (d->is_ed) {
+ tt_ptr_op(d->c->handshake_state->certs->ed_sign_auth, OP_NE, NULL);
+ tt_ptr_op(d->c->handshake_state->certs->auth_cert, OP_EQ, NULL);
+ } else {
+ tt_ptr_op(d->c->handshake_state->certs->ed_sign_auth, OP_EQ, NULL);
+ tt_ptr_op(d->c->handshake_state->certs->auth_cert, OP_NE, NULL);
+ }
done:
;
@@ -358,9 +543,11 @@ test_link_handshake_recv_certs_ok_server(void *arg)
setup_capture_of_logs(LOG_INFO); \
{ code ; } \
channel_tls_process_certs_cell(d->cell, d->chan); \
- tt_int_op(1, ==, mock_close_called); \
- tt_int_op(0, ==, mock_send_authenticate_called); \
- tt_int_op(0, ==, mock_send_netinfo_called); \
+ tt_int_op(1, OP_EQ, mock_close_called); \
+ tt_int_op(0, OP_EQ, mock_send_authenticate_called); \
+ tt_int_op(0, OP_EQ, mock_send_netinfo_called); \
+ tt_int_op(0, OP_EQ, d->c->handshake_state->authenticated_rsa); \
+ tt_int_op(0, OP_EQ, d->c->handshake_state->authenticated_ed25519); \
if (require_failure_message) { \
expect_log_msg_containing(require_failure_message); \
} \
@@ -401,12 +588,41 @@ CERTS_FAIL(truncated_3,
d->cell->payload_len = 7;
memcpy(d->cell->payload, "\x01\x01\x00\x05""abc", 7);
})
+CERTS_FAIL(truncated_4, /* ed25519 */
+ {
+ require_failure_message = "It couldn't be parsed";
+ d->cell->payload_len -= 10;
+ })
+CERTS_FAIL(truncated_5, /* ed25519 */
+ {
+ require_failure_message = "It couldn't be parsed";
+ d->cell->payload_len -= 100;
+ })
+
#define REENCODE() do { \
+ const char *msg = certs_cell_check(d->ccell); \
+ if (msg) puts(msg); \
ssize_t n = certs_cell_encode(d->cell->payload, 4096, d->ccell); \
- tt_int_op(n, >, 0); \
+ tt_int_op(n, OP_GT, 0); \
d->cell->payload_len = n; \
} while (0)
+CERTS_FAIL(truncated_6, /* ed25519 */
+ {
+ /* truncate the link certificate */
+ require_failure_message = "undecodable Ed certificate";
+ certs_cell_cert_setlen_body(certs_cell_get_certs(d->ccell, 3), 7);
+ certs_cell_get_certs(d->ccell, 3)->cert_len = 7;
+ REENCODE();
+ })
+CERTS_FAIL(truncated_7, /* ed25519 */
+ {
+ /* truncate the crosscert */
+ require_failure_message = "Unparseable or overlong crosscert";
+ certs_cell_cert_setlen_body(certs_cell_get_certs(d->ccell, 4), 7);
+ certs_cell_get_certs(d->ccell, 4)->cert_len = 7;
+ REENCODE();
+ })
CERTS_FAIL(not_x509,
{
require_failure_message = "Received undecodable certificate";
@@ -435,6 +651,201 @@ CERTS_FAIL(both_auth,
certs_cell_get_certs(d->ccell, 1)->cert_type = 3;
REENCODE();
})
+CERTS_FAIL(duplicate_id, /* ed25519 */
+ {
+ require_failure_message = "Duplicate Ed25519 certificate";
+ certs_cell_get_certs(d->ccell, 2)->cert_type = 4;
+ certs_cell_get_certs(d->ccell, 3)->cert_type = 4;
+ REENCODE();
+ })
+CERTS_FAIL(duplicate_link, /* ed25519 */
+ {
+ require_failure_message = "Duplicate Ed25519 certificate";
+ certs_cell_get_certs(d->ccell, 2)->cert_type = 5;
+ certs_cell_get_certs(d->ccell, 3)->cert_type = 5;
+ REENCODE();
+ })
+CERTS_FAIL(duplicate_crosscert, /* ed25519 */
+ {
+ require_failure_message = "Duplicate RSA->Ed25519 crosscert";
+ certs_cell_get_certs(d->ccell, 2)->cert_type = 7;
+ certs_cell_get_certs(d->ccell, 3)->cert_type = 7;
+ REENCODE();
+ })
+static void
+test_link_handshake_recv_certs_missing_id(void *arg) /* ed25519 */
+{
+ certs_data_t *d = arg;
+ tt_int_op(certs_cell_getlen_certs(d->ccell), OP_EQ, 5);
+ certs_cell_set_certs(d->ccell, 2, certs_cell_get_certs(d->ccell, 4));
+ certs_cell_set0_certs(d->ccell, 4, NULL); /* prevent free */
+ certs_cell_setlen_certs(d->ccell, 4);
+ d->ccell->n_certs = 4;
+ REENCODE();
+
+ /* This handshake succeeds, but since we have no ID cert, we will
+ * just do the RSA handshake. */
+ channel_tls_process_certs_cell(d->cell, d->chan);
+ tt_int_op(0, OP_EQ, mock_close_called);
+ tt_int_op(0, OP_EQ, d->c->handshake_state->authenticated_ed25519);
+ tt_int_op(1, OP_EQ, d->c->handshake_state->authenticated_rsa);
+ done:
+ ;
+}
+CERTS_FAIL(missing_signing_key, /* ed25519 */
+ {
+ require_failure_message = "No Ed25519 signing key";
+ tt_int_op(certs_cell_getlen_certs(d->ccell), OP_EQ, 5);
+ certs_cell_cert_t *cert = certs_cell_get_certs(d->ccell, 2);
+ tt_int_op(cert->cert_type, OP_EQ, CERTTYPE_ED_ID_SIGN);
+ /* replace this with a valid master->signing cert, but with no
+ * signing key. */
+ const ed25519_keypair_t *mk = get_master_identity_keypair();
+ const ed25519_keypair_t *sk = get_master_signing_keypair();
+ tor_cert_t *bad_cert = tor_cert_create(mk, CERT_TYPE_ID_SIGNING,
+ &sk->pubkey, time(NULL), 86400,
+ 0 /* don't include signer */);
+ certs_cell_cert_setlen_body(cert, bad_cert->encoded_len);
+ memcpy(certs_cell_cert_getarray_body(cert),
+ bad_cert->encoded, bad_cert->encoded_len);
+ cert->cert_len = bad_cert->encoded_len;
+ tor_cert_free(bad_cert);
+ REENCODE();
+ })
+CERTS_FAIL(missing_link, /* ed25519 */
+ {
+ require_failure_message = "No Ed25519 link key";
+ tt_int_op(certs_cell_getlen_certs(d->ccell), OP_EQ, 5);
+ certs_cell_set_certs(d->ccell, 3, certs_cell_get_certs(d->ccell, 4));
+ certs_cell_set0_certs(d->ccell, 4, NULL); /* prevent free */
+ certs_cell_setlen_certs(d->ccell, 4);
+ d->ccell->n_certs = 4;
+ REENCODE();
+ })
+CERTS_FAIL(missing_auth, /* ed25519 */
+ {
+ d->c->handshake_state->started_here = 0;
+ d->c->handshake_state->certs->started_here = 0;
+ require_failure_message = "No Ed25519 link authentication key";
+ tt_int_op(certs_cell_getlen_certs(d->ccell), OP_EQ, 5);
+ certs_cell_set_certs(d->ccell, 3, certs_cell_get_certs(d->ccell, 4));
+ certs_cell_set0_certs(d->ccell, 4, NULL); /* prevent free */
+ certs_cell_setlen_certs(d->ccell, 4);
+ d->ccell->n_certs = 4;
+ REENCODE();
+ })
+CERTS_FAIL(missing_crosscert, /* ed25519 */
+ {
+ require_failure_message = "Missing RSA->Ed25519 crosscert";
+ tt_int_op(certs_cell_getlen_certs(d->ccell), OP_EQ, 5);
+ certs_cell_setlen_certs(d->ccell, 4);
+ d->ccell->n_certs = 4;
+ REENCODE();
+ })
+CERTS_FAIL(missing_rsa_id, /* ed25519 */
+ {
+ require_failure_message = "Missing legacy RSA ID cert";
+ tt_int_op(certs_cell_getlen_certs(d->ccell), OP_EQ, 5);
+ certs_cell_set_certs(d->ccell, 1, certs_cell_get_certs(d->ccell, 4));
+ certs_cell_set0_certs(d->ccell, 4, NULL); /* prevent free */
+ certs_cell_setlen_certs(d->ccell, 4);
+ d->ccell->n_certs = 4;
+ REENCODE();
+ })
+CERTS_FAIL(link_mismatch, /* ed25519 */
+ {
+ require_failure_message = "Link certificate does not match "
+ "TLS certificate";
+ const tor_x509_cert_t *idc;
+ tor_tls_get_my_certs(1, NULL, &idc);
+ tor_x509_cert_free(mock_peer_cert);
+ /* Pretend that the peer cert was something else. */
+ mock_peer_cert = tor_x509_cert_dup(idc);
+ /* No reencode needed. */
+ })
+CERTS_FAIL(bad_ed_sig, /* ed25519 */
+ {
+ require_failure_message = "At least one Ed25519 certificate was "
+ "badly signed";
+ certs_cell_cert_t *cert = certs_cell_get_certs(d->ccell, 3);
+ uint8_t *body = certs_cell_cert_getarray_body(cert);
+ ssize_t body_len = certs_cell_cert_getlen_body(cert);
+ /* Frob a byte in the signature */
+ body[body_len - 13] ^= 7;
+ REENCODE();
+ })
+CERTS_FAIL(bad_crosscert, /*ed25519*/
+ {
+ require_failure_message = "Invalid RSA->Ed25519 crosscert";
+ certs_cell_cert_t *cert = certs_cell_get_certs(d->ccell, 4);
+ uint8_t *body = certs_cell_cert_getarray_body(cert);
+ ssize_t body_len = certs_cell_cert_getlen_body(cert);
+ /* Frob a byte in the signature */
+ body[body_len - 13] ^= 7;
+ REENCODE();
+ })
+CERTS_FAIL(bad_rsa_id_cert, /*ed25519*/
+ {
+ require_failure_message = "legacy RSA ID certificate was not valid";
+ certs_cell_cert_t *cert = certs_cell_get_certs(d->ccell, 1);
+ uint8_t *body = certs_cell_cert_getarray_body(cert);
+ ssize_t body_len = certs_cell_cert_getlen_body(cert);
+ /* Frob a byte in the signature */
+ body[body_len - 13] ^= 7;
+ REENCODE();
+ })
+CERTS_FAIL(expired_rsa_id, /* both */
+ {
+ require_failure_message = "Certificate already expired";
+ /* we're going to replace the identity cert with an expired one. */
+ 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);
+ tor_x509_cert_t *newc;
+ time_t new_end = time(NULL) - 86400 * 10;
+ 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();
+ tor_x509_cert_free(newc);
+ })
+CERTS_FAIL(expired_ed_id, /* ed25519 */
+ {
+ /* we're going to replace the Ed Id->sign cert with an expired one. */
+ require_failure_message = "At least one certificate expired";
+ /* We don't need to re-sign, since we check for expiration first. */
+ certs_cell_cert_t *cert = certs_cell_get_certs(d->ccell, 2);
+ uint8_t *body = certs_cell_cert_getarray_body(cert);
+ /* The expiration field is bytes [2..5]. It is in HOURS since the
+ * epoch. */
+ set_uint32(body+2, htonl(24)); /* Back to jan 2, 1970. */
+ REENCODE();
+ })
+CERTS_FAIL(expired_ed_link, /* ed25519 */
+ {
+ /* we're going to replace the Ed Sign->link cert with an expired one. */
+ require_failure_message = "At least one certificate expired";
+ /* We don't need to re-sign, since we check for expiration first. */
+ certs_cell_cert_t *cert = certs_cell_get_certs(d->ccell, 3);
+ uint8_t *body = certs_cell_cert_getarray_body(cert);
+ /* The expiration field is bytes [2..5]. It is in HOURS since the
+ * epoch. */
+ set_uint32(body+2, htonl(24)); /* Back to jan 2, 1970. */
+ REENCODE();
+ })
+CERTS_FAIL(expired_crosscert, /* ed25519 */
+ {
+ /* we're going to replace the Ed Sign->link cert with an expired one. */
+ require_failure_message = "Crosscert is expired";
+ /* We don't need to re-sign, since we check for expiration first. */
+ certs_cell_cert_t *cert = certs_cell_get_certs(d->ccell, 4);
+ uint8_t *body = certs_cell_cert_getarray_body(cert);
+ /* The expiration field is bytes [32..35]. once again, HOURS. */
+ set_uint32(body+32, htonl(24)); /* Back to jan 2, 1970. */
+ REENCODE();
+ })
+
CERTS_FAIL(wrong_labels_1,
{
require_failure_message = "The link certificate was not valid";
@@ -459,21 +870,26 @@ CERTS_FAIL(wrong_labels_2,
})
CERTS_FAIL(wrong_labels_3,
{
- require_failure_message = "The certs we wanted were missing";
+ require_failure_message =
+ "The certs we wanted (ID, Link) were missing";
certs_cell_get_certs(d->ccell, 0)->cert_type = 2;
certs_cell_get_certs(d->ccell, 1)->cert_type = 3;
REENCODE();
})
CERTS_FAIL(server_missing_certs,
{
- require_failure_message = "The certs we wanted were missing";
+ require_failure_message =
+ "The certs we wanted (ID, Auth) were missing";
d->c->handshake_state->started_here = 0;
+ d->c->handshake_state->certs->started_here = 0;
+
})
CERTS_FAIL(server_wrong_labels_1,
{
require_failure_message =
"The authentication certificate was not valid";
d->c->handshake_state->started_here = 0;
+ d->c->handshake_state->certs->started_here = 0;
certs_cell_get_certs(d->ccell, 0)->cert_type = 2;
certs_cell_get_certs(d->ccell, 1)->cert_type = 3;
REENCODE();
@@ -487,31 +903,38 @@ test_link_handshake_send_authchallenge(void *arg)
or_connection_t *c1 = or_connection_new(CONN_TYPE_OR, AF_INET);
var_cell_t *cell1=NULL, *cell2=NULL;
+ crypto_pk_t *rsa0 = pk_generate(0), *rsa1 = pk_generate(1);
+ tt_int_op(tor_tls_context_init(TOR_TLS_CTX_IS_PUBLIC_SERVER,
+ rsa0, rsa1, 86400), OP_EQ, 0);
+ init_mock_ed_keys(rsa0);
+
MOCK(connection_or_write_var_cell_to_buf, mock_write_var_cell);
- tt_int_op(connection_init_or_handshake_state(c1, 0), ==, 0);
+ tt_int_op(connection_init_or_handshake_state(c1, 0), OP_EQ, 0);
c1->base_.state = OR_CONN_STATE_OR_HANDSHAKING_V3;
- tt_assert(! mock_got_var_cell);
- tt_int_op(0, ==, connection_or_send_auth_challenge_cell(c1));
+ tt_ptr_op(mock_got_var_cell, OP_EQ, NULL);
+ tt_int_op(0, OP_EQ, connection_or_send_auth_challenge_cell(c1));
cell1 = mock_got_var_cell;
- tt_int_op(0, ==, connection_or_send_auth_challenge_cell(c1));
+ tt_int_op(0, OP_EQ, connection_or_send_auth_challenge_cell(c1));
cell2 = mock_got_var_cell;
- tt_int_op(36, ==, cell1->payload_len);
- tt_int_op(36, ==, cell2->payload_len);
- tt_int_op(0, ==, cell1->circ_id);
- tt_int_op(0, ==, cell2->circ_id);
- tt_int_op(CELL_AUTH_CHALLENGE, ==, cell1->command);
- tt_int_op(CELL_AUTH_CHALLENGE, ==, cell2->command);
+ tt_int_op(38, OP_EQ, cell1->payload_len);
+ tt_int_op(38, OP_EQ, cell2->payload_len);
+ tt_int_op(0, OP_EQ, cell1->circ_id);
+ tt_int_op(0, OP_EQ, cell2->circ_id);
+ tt_int_op(CELL_AUTH_CHALLENGE, OP_EQ, cell1->command);
+ tt_int_op(CELL_AUTH_CHALLENGE, OP_EQ, cell2->command);
- tt_mem_op("\x00\x01\x00\x01", ==, cell1->payload + 32, 4);
- tt_mem_op("\x00\x01\x00\x01", ==, cell2->payload + 32, 4);
- tt_mem_op(cell1->payload, !=, cell2->payload, 32);
+ tt_mem_op("\x00\x02\x00\x01\x00\x03", OP_EQ, cell1->payload + 32, 6);
+ tt_mem_op("\x00\x02\x00\x01\x00\x03", OP_EQ, cell2->payload + 32, 6);
+ tt_mem_op(cell1->payload, OP_NE, cell2->payload, 32);
done:
UNMOCK(connection_or_write_var_cell_to_buf);
connection_free_(TO_CONN(c1));
tor_free(cell1);
tor_free(cell2);
+ crypto_pk_free(rsa0);
+ crypto_pk_free(rsa1);
}
typedef struct authchallenge_data_s {
@@ -551,14 +974,14 @@ recv_authchallenge_setup(const struct testcase_t *test)
d->c->base_.address = tor_strdup("HaveAnAddress");
d->c->base_.state = OR_CONN_STATE_OR_HANDSHAKING_V3;
d->chan->conn = d->c;
- tt_int_op(connection_init_or_handshake_state(d->c, 1), ==, 0);
+ tt_int_op(connection_init_or_handshake_state(d->c, 1), OP_EQ, 0);
d->c->link_proto = 4;
d->c->handshake_state->received_certs_cell = 1;
d->cell = var_cell_new(128);
d->cell->payload_len = 38;
- d->cell->payload[33] = 2;
- d->cell->payload[35] = 7;
- d->cell->payload[37] = 1;
+ d->cell->payload[33] = 2; /* 2 methods */
+ d->cell->payload[35] = 7; /* This one isn't real */
+ d->cell->payload[37] = 1; /* This is the old RSA one. */
d->cell->command = CELL_AUTH_CHALLENGE;
get_options_mutable()->ORPort_set = 1;
@@ -566,10 +989,9 @@ recv_authchallenge_setup(const struct testcase_t *test)
MOCK(connection_or_close_for_error, mock_close_for_err);
MOCK(connection_or_send_netinfo, mock_send_netinfo);
MOCK(connection_or_send_authenticate_cell, mock_send_authenticate);
-
- tt_int_op(0, ==, d->c->handshake_state->received_auth_challenge);
- tt_int_op(0, ==, mock_send_authenticate_called);
- tt_int_op(0, ==, mock_send_netinfo_called);
+ tt_int_op(0, OP_EQ, d->c->handshake_state->received_auth_challenge);
+ tt_int_op(0, OP_EQ, mock_send_authenticate_called);
+ tt_int_op(0, OP_EQ, mock_send_netinfo_called);
return d;
done:
@@ -588,10 +1010,30 @@ test_link_handshake_recv_authchallenge_ok(void *arg)
authchallenge_data_t *d = arg;
channel_tls_process_auth_challenge_cell(d->cell, d->chan);
- tt_int_op(0, ==, mock_close_called);
- tt_int_op(1, ==, d->c->handshake_state->received_auth_challenge);
- tt_int_op(1, ==, mock_send_authenticate_called);
- tt_int_op(1, ==, mock_send_netinfo_called);
+ tt_int_op(0, OP_EQ, mock_close_called);
+ tt_int_op(1, OP_EQ, d->c->handshake_state->received_auth_challenge);
+ tt_int_op(1, OP_EQ, mock_send_authenticate_called);
+ tt_int_op(1, OP_EQ, mock_send_netinfo_called);
+ tt_int_op(1, OP_EQ, mock_send_authenticate_called_with_type); /* RSA */
+ done:
+ ;
+}
+
+static void
+test_link_handshake_recv_authchallenge_ok_ed25519(void *arg)
+{
+ authchallenge_data_t *d = arg;
+
+ /* Add the ed25519 authentication mechanism here. */
+ d->cell->payload[33] = 3; /* 3 types are supported now. */
+ d->cell->payload[39] = 3;
+ d->cell->payload_len += 2;
+ channel_tls_process_auth_challenge_cell(d->cell, d->chan);
+ tt_int_op(0, OP_EQ, mock_close_called);
+ tt_int_op(1, OP_EQ, d->c->handshake_state->received_auth_challenge);
+ tt_int_op(1, OP_EQ, mock_send_authenticate_called);
+ tt_int_op(1, OP_EQ, mock_send_netinfo_called);
+ tt_int_op(3, OP_EQ, mock_send_authenticate_called_with_type); /* Ed25519 */
done:
;
}
@@ -603,10 +1045,10 @@ test_link_handshake_recv_authchallenge_ok_noserver(void *arg)
get_options_mutable()->ORPort_set = 0;
channel_tls_process_auth_challenge_cell(d->cell, d->chan);
- tt_int_op(0, ==, mock_close_called);
- tt_int_op(1, ==, d->c->handshake_state->received_auth_challenge);
- tt_int_op(0, ==, mock_send_authenticate_called);
- tt_int_op(0, ==, mock_send_netinfo_called);
+ tt_int_op(0, OP_EQ, mock_close_called);
+ tt_int_op(1, OP_EQ, d->c->handshake_state->received_auth_challenge);
+ tt_int_op(0, OP_EQ, mock_send_authenticate_called);
+ tt_int_op(0, OP_EQ, mock_send_netinfo_called);
done:
;
}
@@ -618,10 +1060,10 @@ test_link_handshake_recv_authchallenge_ok_unrecognized(void *arg)
d->cell->payload[37] = 99;
channel_tls_process_auth_challenge_cell(d->cell, d->chan);
- tt_int_op(0, ==, mock_close_called);
- tt_int_op(1, ==, d->c->handshake_state->received_auth_challenge);
- tt_int_op(0, ==, mock_send_authenticate_called);
- tt_int_op(1, ==, mock_send_netinfo_called);
+ tt_int_op(0, OP_EQ, mock_close_called);
+ tt_int_op(1, OP_EQ, d->c->handshake_state->received_auth_challenge);
+ tt_int_op(0, OP_EQ, mock_send_authenticate_called);
+ tt_int_op(1, OP_EQ, mock_send_netinfo_called);
done:
;
}
@@ -635,9 +1077,9 @@ test_link_handshake_recv_authchallenge_ok_unrecognized(void *arg)
setup_capture_of_logs(LOG_INFO); \
{ code ; } \
channel_tls_process_auth_challenge_cell(d->cell, d->chan); \
- tt_int_op(1, ==, mock_close_called); \
- tt_int_op(0, ==, mock_send_authenticate_called); \
- tt_int_op(0, ==, mock_send_netinfo_called); \
+ tt_int_op(1, OP_EQ, mock_close_called); \
+ tt_int_op(0, OP_EQ, mock_send_authenticate_called); \
+ tt_int_op(0, OP_EQ, mock_send_netinfo_called); \
if (require_failure_message) { \
expect_log_msg_containing(require_failure_message); \
} \
@@ -655,7 +1097,8 @@ AUTHCHALLENGE_FAIL(badproto,
AUTHCHALLENGE_FAIL(as_server,
require_failure_message = "We didn't originate this "
"connection";
- d->c->handshake_state->started_here = 0;)
+ d->c->handshake_state->started_here = 0;
+ d->c->handshake_state->certs->started_here = 0;)
AUTHCHALLENGE_FAIL(duplicate,
require_failure_message = "We already received one";
d->c->handshake_state->received_auth_challenge = 1)
@@ -673,15 +1116,6 @@ AUTHCHALLENGE_FAIL(nonzero_circid,
require_failure_message = "It had a nonzero circuit ID";
d->cell->circ_id = 1337)
-static tor_x509_cert_t *mock_peer_cert = NULL;
-
-static tor_x509_cert_t *
-mock_get_peer_cert(tor_tls_t *tls)
-{
- (void)tls;
- return tor_x509_cert_dup(mock_peer_cert);
-}
-
static int
mock_get_tlssecrets(tor_tls_t *tls, uint8_t *secrets_out)
{
@@ -701,6 +1135,7 @@ mock_set_circid_type(channel_t *chan,
}
typedef struct authenticate_data_s {
+ int is_ed;
or_connection_t *c1, *c2;
channel_tls_t *chan2;
var_cell_t *cell;
@@ -717,11 +1152,12 @@ authenticate_data_cleanup(const struct testcase_t *test, void *arg)
UNMOCK(tor_tls_get_tlssecrets);
UNMOCK(connection_or_close_for_error);
UNMOCK(channel_set_circid_type);
+ UNMOCK(tor_tls_export_key_material);
authenticate_data_t *d = arg;
if (d) {
tor_free(d->cell);
- connection_or_remove_from_identity_map(d->c1);
- connection_or_remove_from_identity_map(d->c2);
+ connection_or_clear_identity(d->c1);
+ connection_or_clear_identity(d->c2);
connection_free_(TO_CONN(d->c1));
connection_free_(TO_CONN(d->c2));
circuitmux_free(d->chan2->base_.cmux);
@@ -742,6 +1178,7 @@ static void *
authenticate_data_setup(const struct testcase_t *test)
{
authenticate_data_t *d = tor_malloc_zero(sizeof(*d));
+ int is_ed = d->is_ed = (test->setup_data == (void*)3);
scheduler_init();
@@ -751,6 +1188,7 @@ authenticate_data_setup(const struct testcase_t *test)
MOCK(tor_tls_get_tlssecrets, mock_get_tlssecrets);
MOCK(connection_or_close_for_error, mock_close_for_err);
MOCK(channel_set_circid_type, mock_set_circid_type);
+ MOCK(tor_tls_export_key_material, mock_export_key_material);
d->c1 = or_connection_new(CONN_TYPE_OR, AF_INET);
d->c2 = or_connection_new(CONN_TYPE_OR, AF_INET);
tor_addr_from_ipv4h(&d->c1->base_.addr, 0x01020304);
@@ -759,15 +1197,17 @@ authenticate_data_setup(const struct testcase_t *test)
d->key1 = pk_generate(2);
d->key2 = pk_generate(3);
tt_int_op(tor_tls_context_init(TOR_TLS_CTX_IS_PUBLIC_SERVER,
- d->key1, d->key2, 86400), ==, 0);
+ d->key1, d->key2, 86400), OP_EQ, 0);
+
+ init_mock_ed_keys(d->key2);
d->c1->base_.state = OR_CONN_STATE_OR_HANDSHAKING_V3;
d->c1->link_proto = 3;
- tt_int_op(connection_init_or_handshake_state(d->c1, 1), ==, 0);
+ tt_int_op(connection_init_or_handshake_state(d->c1, 1), OP_EQ, 0);
d->c2->base_.state = OR_CONN_STATE_OR_HANDSHAKING_V3;
d->c2->link_proto = 3;
- tt_int_op(connection_init_or_handshake_state(d->c2, 0), ==, 0);
+ tt_int_op(connection_init_or_handshake_state(d->c2, 0), OP_EQ, 0);
var_cell_t *cell = var_cell_new(16);
cell->command = CELL_CERTS;
or_handshake_state_record_var_cell(d->c1, d->c1->handshake_state, cell, 1);
@@ -791,21 +1231,37 @@ authenticate_data_setup(const struct testcase_t *test)
const uint8_t *der;
size_t sz;
tor_x509_cert_get_der(id_cert, &der, &sz);
- d->c1->handshake_state->id_cert = tor_x509_cert_decode(der, sz);
- d->c2->handshake_state->id_cert = tor_x509_cert_decode(der, sz);
+ d->c1->handshake_state->certs->id_cert = tor_x509_cert_decode(der, sz);
+ d->c2->handshake_state->certs->id_cert = tor_x509_cert_decode(der, sz);
+
+ if (is_ed) {
+ d->c1->handshake_state->certs->ed_id_sign =
+ tor_cert_dup(get_master_signing_key_cert());
+ d->c2->handshake_state->certs->ed_id_sign =
+ tor_cert_dup(get_master_signing_key_cert());
+ d->c2->handshake_state->certs->ed_sign_auth =
+ tor_cert_dup(get_current_auth_key_cert());
+ } else {
+ tt_assert(! tor_tls_get_my_certs(0, &auth_cert, &id_cert));
+ tor_x509_cert_get_der(auth_cert, &der, &sz);
+ d->c2->handshake_state->certs->auth_cert = tor_x509_cert_decode(der, sz);
+ }
tor_x509_cert_get_der(link_cert, &der, &sz);
mock_peer_cert = tor_x509_cert_decode(der, sz);
tt_assert(mock_peer_cert);
+
mock_own_cert = tor_x509_cert_decode(der, sz);
tt_assert(mock_own_cert);
- tt_assert(! tor_tls_get_my_certs(0, &auth_cert, &id_cert));
- tor_x509_cert_get_der(auth_cert, &der, &sz);
- d->c2->handshake_state->auth_cert = tor_x509_cert_decode(der, sz);
/* Make an authenticate cell ... */
- tt_int_op(0, ==, connection_or_send_authenticate_cell(d->c1,
- AUTHTYPE_RSA_SHA256_TLSSECRET));
+ int authtype;
+ if (is_ed)
+ authtype = AUTHTYPE_ED25519_SHA256_RFC5705;
+ else
+ authtype = AUTHTYPE_RSA_SHA256_TLSSECRET;
+ tt_int_op(0, OP_EQ, connection_or_send_authenticate_cell(d->c1, authtype));
+
tt_assert(mock_got_var_cell);
d->cell = mock_got_var_cell;
mock_got_var_cell = NULL;
@@ -829,44 +1285,66 @@ test_link_handshake_auth_cell(void *arg)
crypto_pk_t *auth_pubkey = NULL;
/* Is the cell well-formed on the outer layer? */
- tt_int_op(d->cell->command, ==, CELL_AUTHENTICATE);
- tt_int_op(d->cell->payload[0], ==, 0);
- tt_int_op(d->cell->payload[1], ==, 1);
- tt_int_op(ntohs(get_uint16(d->cell->payload + 2)), ==,
+ tt_int_op(d->cell->command, OP_EQ, CELL_AUTHENTICATE);
+ tt_int_op(d->cell->payload[0], OP_EQ, 0);
+ if (d->is_ed)
+ tt_int_op(d->cell->payload[1], OP_EQ, 3);
+ else
+ tt_int_op(d->cell->payload[1], OP_EQ, 1);
+ tt_int_op(ntohs(get_uint16(d->cell->payload + 2)), OP_EQ,
d->cell->payload_len - 4);
/* Check it out for plausibility... */
auth_ctx_t ctx;
- ctx.is_ed = 0;
- tt_int_op(d->cell->payload_len-4, ==, auth1_parse(&auth1,
+ ctx.is_ed = d->is_ed;
+ tt_int_op(d->cell->payload_len-4, OP_EQ, auth1_parse(&auth1,
d->cell->payload+4,
d->cell->payload_len - 4, &ctx));
tt_assert(auth1);
- tt_mem_op(auth1->type, ==, "AUTH0001", 8);
- tt_mem_op(auth1->tlssecrets, ==, "int getRandomNumber(){return 4;}", 32);
- tt_int_op(auth1_getlen_sig(auth1), >, 120);
+ if (d->is_ed) {
+ tt_mem_op(auth1->type, OP_EQ, "AUTH0003", 8);
+ } else {
+ tt_mem_op(auth1->type, OP_EQ, "AUTH0001", 8);
+ }
+ tt_mem_op(auth1->tlssecrets, OP_EQ, "int getRandomNumber(){return 4;}", 32);
/* Is the signature okay? */
- uint8_t sig[128];
- uint8_t digest[32];
-
- auth_pubkey = tor_tls_cert_get_key(d->c2->handshake_state->auth_cert);
- int n = crypto_pk_public_checksig(
+ const uint8_t *start = d->cell->payload+4, *end = auth1->end_of_signed;
+ if (d->is_ed) {
+ ed25519_signature_t sig;
+ tt_int_op(auth1_getlen_sig(auth1), OP_EQ, ED25519_SIG_LEN);
+ memcpy(&sig.sig, auth1_getarray_sig(auth1), ED25519_SIG_LEN);
+ tt_assert(!ed25519_checksig(&sig, start, end-start,
+ &get_current_auth_keypair()->pubkey));
+ } else {
+ uint8_t sig[128];
+ uint8_t digest[32];
+ tt_int_op(auth1_getlen_sig(auth1), OP_GT, 120);
+ auth_pubkey = tor_tls_cert_get_key(
+ d->c2->handshake_state->certs->auth_cert);
+ int n = crypto_pk_public_checksig(
auth_pubkey,
(char*)sig, sizeof(sig), (char*)auth1_getarray_sig(auth1),
auth1_getlen_sig(auth1));
- tt_int_op(n, ==, 32);
- const uint8_t *start = d->cell->payload+4, *end = auth1->end_of_signed;
- crypto_digest256((char*)digest,
- (const char*)start, end-start, DIGEST_SHA256);
- tt_mem_op(sig, ==, digest, 32);
+ tt_int_op(n, OP_EQ, 32);
+ crypto_digest256((char*)digest,
+ (const char*)start, end-start, DIGEST_SHA256);
+ tt_mem_op(sig, OP_EQ, digest, 32);
+ }
/* Then feed it to c2. */
- tt_int_op(d->c2->handshake_state->authenticated, ==, 0);
+ tt_int_op(d->c2->handshake_state->authenticated, OP_EQ, 0);
channel_tls_process_authenticate_cell(d->cell, d->chan2);
- tt_int_op(mock_close_called, ==, 0);
- tt_int_op(d->c2->handshake_state->authenticated, ==, 1);
+ tt_int_op(mock_close_called, OP_EQ, 0);
+ tt_int_op(d->c2->handshake_state->authenticated, OP_EQ, 1);
+ if (d->is_ed) {
+ tt_int_op(d->c2->handshake_state->authenticated_ed25519, OP_EQ, 1);
+ tt_int_op(d->c2->handshake_state->authenticated_rsa, OP_EQ, 1);
+ } else {
+ tt_int_op(d->c2->handshake_state->authenticated_ed25519, OP_EQ, 0);
+ tt_int_op(d->c2->handshake_state->authenticated_rsa, OP_EQ, 1);
+ }
done:
auth1_free(auth1);
@@ -881,10 +1359,10 @@ test_link_handshake_auth_cell(void *arg)
const char *require_failure_message = NULL; \
setup_capture_of_logs(LOG_INFO); \
{ code ; } \
- tt_int_op(d->c2->handshake_state->authenticated, ==, 0); \
+ tt_int_op(d->c2->handshake_state->authenticated, OP_EQ, 0); \
channel_tls_process_authenticate_cell(d->cell, d->chan2); \
- tt_int_op(mock_close_called, ==, 1); \
- tt_int_op(d->c2->handshake_state->authenticated, ==, 0); \
+ tt_int_op(mock_close_called, OP_EQ, 1); \
+ tt_int_op(d->c2->handshake_state->authenticated, OP_EQ, 0); \
if (require_failure_message) { \
expect_log_msg_containing(require_failure_message); \
} \
@@ -900,7 +1378,8 @@ AUTHENTICATE_FAIL(badproto,
d->c2->link_proto = 2)
AUTHENTICATE_FAIL(atclient,
require_failure_message = "We originated this connection";
- d->c2->handshake_state->started_here = 1)
+ d->c2->handshake_state->started_here = 1;
+ d->c2->handshake_state->certs->started_here = 1;)
AUTHENTICATE_FAIL(duplicate,
require_failure_message = "We already got one";
d->c2->handshake_state->received_authenticate = 1)
@@ -911,8 +1390,8 @@ test_link_handshake_auth_already_authenticated(void *arg)
setup_capture_of_logs(LOG_INFO);
d->c2->handshake_state->authenticated = 1;
channel_tls_process_authenticate_cell(d->cell, d->chan2);
- tt_int_op(mock_close_called, ==, 1);
- tt_int_op(d->c2->handshake_state->authenticated, ==, 1);
+ tt_int_op(mock_close_called, OP_EQ, 1);
+ tt_int_op(d->c2->handshake_state->authenticated, OP_EQ, 1);
expect_log_msg_containing("The peer is already authenticated");
done:
teardown_capture_of_logs();
@@ -924,13 +1403,13 @@ AUTHENTICATE_FAIL(nocerts,
AUTHENTICATE_FAIL(noidcert,
require_failure_message = "We never got an identity "
"certificate";
- tor_x509_cert_free(d->c2->handshake_state->id_cert);
- d->c2->handshake_state->id_cert = NULL)
+ tor_x509_cert_free(d->c2->handshake_state->certs->id_cert);
+ d->c2->handshake_state->certs->id_cert = NULL)
AUTHENTICATE_FAIL(noauthcert,
- require_failure_message = "We never got an authentication "
- "certificate";
- tor_x509_cert_free(d->c2->handshake_state->auth_cert);
- d->c2->handshake_state->auth_cert = NULL)
+ require_failure_message = "We never got an RSA "
+ "authentication certificate";
+ tor_x509_cert_free(d->c2->handshake_state->certs->auth_cert);
+ d->c2->handshake_state->certs->auth_cert = NULL)
AUTHENTICATE_FAIL(tooshort,
require_failure_message = "Cell was way too short";
d->cell->payload_len = 3)
@@ -946,7 +1425,7 @@ AUTHENTICATE_FAIL(truncated_2,
d->cell->payload[3]++)
AUTHENTICATE_FAIL(tooshort_1,
require_failure_message = "Authenticator was too short";
- tt_int_op(d->cell->payload_len, >=, 260);
+ tt_int_op(d->cell->payload_len, OP_GE, 260);
d->cell->payload[2] -= 1;
d->cell->payload_len -= 256;)
AUTHENTICATE_FAIL(badcontent,
@@ -954,11 +1433,33 @@ AUTHENTICATE_FAIL(badcontent,
"cell body was not as expected";
d->cell->payload[10] ^= 0xff)
AUTHENTICATE_FAIL(badsig_1,
- require_failure_message = "Signature wasn't valid";
+ if (d->is_ed)
+ require_failure_message = "Ed25519 signature wasn't valid";
+ else
+ require_failure_message = "RSA signature wasn't valid";
d->cell->payload[d->cell->payload_len - 5] ^= 0xff)
-
-#define TEST(name, flags) \
- { #name , test_link_handshake_ ## name, (flags), NULL, NULL }
+AUTHENTICATE_FAIL(missing_ed_id,
+ {
+ tor_cert_free(d->c2->handshake_state->certs->ed_id_sign);
+ d->c2->handshake_state->certs->ed_id_sign = NULL;
+ require_failure_message = "Ed authenticate without Ed ID "
+ "cert from peer";
+ })
+AUTHENTICATE_FAIL(missing_ed_auth,
+ {
+ tor_cert_free(d->c2->handshake_state->certs->ed_sign_auth);
+ d->c2->handshake_state->certs->ed_sign_auth = NULL;
+ require_failure_message = "We never got an Ed25519 "
+ "authentication certificate";
+ })
+
+#define TEST_RSA(name, flags) \
+ { #name , test_link_handshake_ ## name, (flags), \
+ &passthrough_setup, (void*)"RSA" }
+
+#define TEST_ED(name, flags) \
+ { #name "_ed25519" , test_link_handshake_ ## name, (flags), \
+ &passthrough_setup, (void*)"Ed25519" }
#define TEST_RCV_AUTHCHALLENGE(name) \
{ "recv_authchallenge/" #name , \
@@ -968,17 +1469,34 @@ AUTHENTICATE_FAIL(badsig_1,
#define TEST_RCV_CERTS(name) \
{ "recv_certs/" #name , \
test_link_handshake_recv_certs_ ## name, TT_FORK, \
- &setup_recv_certs, NULL }
+ &setup_recv_certs, (void*)"RSA-Link" }
+
+#define TEST_RCV_CERTS_RSA(name,type) \
+ { "recv_certs/" #name , \
+ test_link_handshake_recv_certs_ ## name, TT_FORK, \
+ &setup_recv_certs, (void*)type }
+
+#define TEST_RCV_CERTS_ED(name, type) \
+ { "recv_certs/" #name "_ed25519", \
+ test_link_handshake_recv_certs_ ## name, TT_FORK, \
+ &setup_recv_certs, (void*)type }
#define TEST_AUTHENTICATE(name) \
{ "authenticate/" #name , test_link_handshake_auth_ ## name, TT_FORK, \
&setup_authenticate, NULL }
+#define TEST_AUTHENTICATE_ED(name) \
+ { "authenticate/" #name "_ed25519" , test_link_handshake_auth_ ## name, \
+ TT_FORK, &setup_authenticate, (void*)3 }
+
struct testcase_t link_handshake_tests[] = {
- TEST(certs_ok, TT_FORK),
- //TEST(certs_bad, TT_FORK),
+ TEST_RSA(certs_ok, TT_FORK),
+ TEST_ED(certs_ok, TT_FORK),
+
TEST_RCV_CERTS(ok),
- TEST_RCV_CERTS(ok_server),
+ TEST_RCV_CERTS_ED(ok, "Ed25519-Link"),
+ TEST_RCV_CERTS_RSA(ok_server, "RSA-Auth"),
+ TEST_RCV_CERTS_ED(ok_server, "Ed25519-Auth"),
TEST_RCV_CERTS(badstate),
TEST_RCV_CERTS(badproto),
TEST_RCV_CERTS(duplicate),
@@ -988,18 +1506,41 @@ struct testcase_t link_handshake_tests[] = {
TEST_RCV_CERTS(truncated_1),
TEST_RCV_CERTS(truncated_2),
TEST_RCV_CERTS(truncated_3),
+ TEST_RCV_CERTS_ED(truncated_4, "Ed25519-Link"),
+ TEST_RCV_CERTS_ED(truncated_5, "Ed25519-Link"),
+ TEST_RCV_CERTS_ED(truncated_6, "Ed25519-Link"),
+ TEST_RCV_CERTS_ED(truncated_7, "Ed25519-Link"),
TEST_RCV_CERTS(not_x509),
TEST_RCV_CERTS(both_link),
TEST_RCV_CERTS(both_id_rsa),
TEST_RCV_CERTS(both_auth),
+ TEST_RCV_CERTS_ED(duplicate_id, "Ed25519-Link"),
+ TEST_RCV_CERTS_ED(duplicate_link, "Ed25519-Link"),
+ TEST_RCV_CERTS_ED(duplicate_crosscert, "Ed25519-Link"),
+ TEST_RCV_CERTS_ED(missing_crosscert, "Ed25519-Link"),
+ TEST_RCV_CERTS_ED(missing_id, "Ed25519-Link"),
+ TEST_RCV_CERTS_ED(missing_signing_key, "Ed25519-Link"),
+ TEST_RCV_CERTS_ED(missing_link, "Ed25519-Link"),
+ TEST_RCV_CERTS_ED(missing_auth, "Ed25519-Auth"),
+ TEST_RCV_CERTS_ED(missing_rsa_id, "Ed25519-Link"),
+ TEST_RCV_CERTS_ED(link_mismatch, "Ed25519-Link"),
+ TEST_RCV_CERTS_ED(bad_ed_sig, "Ed25519-Link"),
+ TEST_RCV_CERTS_ED(bad_rsa_id_cert, "Ed25519-Link"),
+ TEST_RCV_CERTS_ED(bad_crosscert, "Ed25519-Link"),
+ TEST_RCV_CERTS_RSA(expired_rsa_id, "RSA-Link"),
+ TEST_RCV_CERTS_ED(expired_rsa_id, "Ed25519-Link"),
+ TEST_RCV_CERTS_ED(expired_ed_id, "Ed25519-Link"),
+ TEST_RCV_CERTS_ED(expired_ed_link, "Ed25519-Link"),
+ TEST_RCV_CERTS_ED(expired_crosscert, "Ed25519-Link"),
TEST_RCV_CERTS(wrong_labels_1),
TEST_RCV_CERTS(wrong_labels_2),
TEST_RCV_CERTS(wrong_labels_3),
TEST_RCV_CERTS(server_missing_certs),
TEST_RCV_CERTS(server_wrong_labels_1),
- TEST(send_authchallenge, TT_FORK),
+ TEST_RSA(send_authchallenge, TT_FORK),
TEST_RCV_AUTHCHALLENGE(ok),
+ TEST_RCV_AUTHCHALLENGE(ok_ed25519),
TEST_RCV_AUTHCHALLENGE(ok_noserver),
TEST_RCV_AUTHCHALLENGE(ok_unrecognized),
TEST_RCV_AUTHCHALLENGE(badstate),
@@ -1012,6 +1553,7 @@ struct testcase_t link_handshake_tests[] = {
TEST_RCV_AUTHCHALLENGE(nonzero_circid),
TEST_AUTHENTICATE(cell),
+ TEST_AUTHENTICATE_ED(cell),
TEST_AUTHENTICATE(badstate),
TEST_AUTHENTICATE(badproto),
TEST_AUTHENTICATE(atclient),
@@ -1027,6 +1569,9 @@ struct testcase_t link_handshake_tests[] = {
TEST_AUTHENTICATE(tooshort_1),
TEST_AUTHENTICATE(badcontent),
TEST_AUTHENTICATE(badsig_1),
+ TEST_AUTHENTICATE_ED(badsig_1),
+ TEST_AUTHENTICATE_ED(missing_ed_id),
+ TEST_AUTHENTICATE_ED(missing_ed_auth),
//TEST_AUTHENTICATE(),
END_OF_TESTCASES
diff --git a/src/test/test_logging.c b/src/test/test_logging.c
index 15471e46d0..e373158e34 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"
@@ -107,7 +107,7 @@ test_sigsafe_err(void *arg)
close(STDERR_FILENO);
content = read_file_to_str(fn, 0, NULL);
- tt_assert(content != NULL);
+ tt_ptr_op(content, OP_NE, NULL);
tor_split_lines(lines, content, (int)strlen(content));
tt_int_op(smartlist_len(lines), OP_GE, 5);
@@ -140,7 +140,7 @@ test_ratelim(void *arg)
char *msg = NULL;
msg = rate_limit_log(&ten_min, now);
- tt_assert(msg != NULL);
+ tt_ptr_op(msg, OP_NE, NULL);
tt_str_op(msg, OP_EQ, ""); /* nothing was suppressed. */
tt_int_op(ten_min.last_allowed, OP_EQ, now);
@@ -150,14 +150,14 @@ test_ratelim(void *arg)
for (i = 0; i < 9; ++i) {
now += 60; /* one minute has passed. */
msg = rate_limit_log(&ten_min, now);
- tt_assert(msg == NULL);
+ tt_ptr_op(msg, OP_EQ, NULL);
tt_int_op(ten_min.last_allowed, OP_EQ, start);
tt_int_op(ten_min.n_calls_since_last_time, OP_EQ, i + 1);
}
now += 240; /* Okay, we can be done. */
msg = rate_limit_log(&ten_min, now);
- tt_assert(msg != NULL);
+ tt_ptr_op(msg, OP_NE, NULL);
tt_str_op(msg, OP_EQ,
" [9 similar message(s) suppressed in last 600 seconds]");
done:
diff --git a/src/test/test_microdesc.c b/src/test/test_microdesc.c
index 2ae605b8db..4f0ecd778b 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,18 +14,12 @@
#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>
#else
#include <dirent.h>
-#endif
+#endif /* defined(_WIN32) */
static const char test_md1[] =
"onion-key\n"
@@ -470,7 +464,7 @@ test_md_generate(void *arg)
microdesc_free(md);
md = NULL;
md = dirvote_create_microdescriptor(ri, 21);
- tt_str_op(md->body, ==, test_md_18);
+ tt_str_op(md->body, OP_EQ, test_md_18);
routerinfo_free(ri);
ri = router_parse_entry_from_string(test_ri2, NULL, 0, 0, NULL, NULL);
@@ -478,12 +472,12 @@ test_md_generate(void *arg)
microdesc_free(md);
md = NULL;
md = dirvote_create_microdescriptor(ri, 18);
- tt_str_op(md->body, ==, test_md2_18);
+ tt_str_op(md->body, OP_EQ, test_md2_18);
microdesc_free(md);
md = NULL;
md = dirvote_create_microdescriptor(ri, 21);
- tt_str_op(md->body, ==, test_md2_21);
+ tt_str_op(md->body, OP_EQ, test_md2_21);
tt_assert(ed25519_pubkey_eq(md->ed25519_identity_pkey,
&ri->cache_info.signing_key_cert->signing_key));
@@ -829,14 +823,14 @@ test_md_corrupt_desc(void *arg)
"@last-listed 2015-06-22 10:00:00\n"
"onion-k\n",
NULL, SAVED_IN_JOURNAL, 0, time(NULL), NULL);
- tt_int_op(smartlist_len(sl), ==, 0);
+ tt_int_op(smartlist_len(sl), OP_EQ, 0);
smartlist_free(sl);
sl = microdescs_add_to_cache(get_microdesc_cache(),
"@last-listed 2015-06-22 10:00:00\n"
"wiggly\n",
NULL, SAVED_IN_JOURNAL, 0, time(NULL), NULL);
- tt_int_op(smartlist_len(sl), ==, 0);
+ tt_int_op(smartlist_len(sl), OP_EQ, 0);
smartlist_free(sl);
tor_asprintf(&cp, "%s\n%s", test_md1, "@foobar\nonion-wobble\n");
@@ -844,7 +838,7 @@ test_md_corrupt_desc(void *arg)
sl = microdescs_add_to_cache(get_microdesc_cache(),
cp, cp+strlen(cp),
SAVED_IN_JOURNAL, 0, time(NULL), NULL);
- tt_int_op(smartlist_len(sl), ==, 0);
+ tt_int_op(smartlist_len(sl), OP_EQ, 0);
done:
tor_free(cp);
diff --git a/src/test/test_nodelist.c b/src/test/test_nodelist.c
index d58f8a7fca..a873003d72 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 */
/**
@@ -7,7 +7,9 @@
**/
#include "or.h"
+#include "networkstatus.h"
#include "nodelist.h"
+#include "torcert.h"
#include "test.h"
/** Test the case when node_get_by_id() returns NULL,
@@ -100,6 +102,107 @@ test_nodelist_node_is_dir(void *arg)
return;
}
+static networkstatus_t *dummy_ns = NULL;
+static networkstatus_t *
+mock_networkstatus_get_latest_consensus(void)
+{
+ return dummy_ns;
+}
+static networkstatus_t *
+mock_networkstatus_get_latest_consensus_by_flavor(consensus_flavor_t f)
+{
+ tor_assert(f == FLAV_MICRODESC);
+ return dummy_ns;
+}
+
+static void
+test_nodelist_ed_id(void *arg)
+{
+ routerstatus_t *rs[4];
+ microdesc_t *md[4];
+ routerinfo_t *ri[4];
+ networkstatus_t *ns;
+ int i;
+ (void)arg;
+
+ ns = tor_malloc_zero(sizeof(networkstatus_t));
+ ns->flavor = FLAV_MICRODESC;
+ ns->routerstatus_list = smartlist_new();
+ dummy_ns = ns;
+ MOCK(networkstatus_get_latest_consensus,
+ mock_networkstatus_get_latest_consensus);
+ MOCK(networkstatus_get_latest_consensus_by_flavor,
+ mock_networkstatus_get_latest_consensus_by_flavor);
+
+ /* Make a bunch of dummy objects that we can play around with. Only set the
+ necessary fields */
+
+ for (i = 0; i < 4; ++i) {
+ rs[i] = tor_malloc_zero(sizeof(*rs[i]));
+ md[i] = tor_malloc_zero(sizeof(*md[i]));
+ ri[i] = tor_malloc_zero(sizeof(*ri[i]));
+
+ crypto_rand(md[i]->digest, sizeof(md[i]->digest));
+ md[i]->ed25519_identity_pkey = tor_malloc(sizeof(ed25519_public_key_t));
+ crypto_rand((char*)md[i]->ed25519_identity_pkey,
+ sizeof(ed25519_public_key_t));
+ crypto_rand(rs[i]->identity_digest, sizeof(rs[i]->identity_digest));
+ memcpy(ri[i]->cache_info.identity_digest, rs[i]->identity_digest,
+ DIGEST_LEN);
+ memcpy(rs[i]->descriptor_digest, md[i]->digest, DIGEST256_LEN);
+ ri[i]->cache_info.signing_key_cert = tor_malloc_zero(sizeof(tor_cert_t));
+ memcpy(&ri[i]->cache_info.signing_key_cert->signing_key,
+ md[i]->ed25519_identity_pkey, sizeof(ed25519_public_key_t));
+
+ if (i != 3)
+ smartlist_add(ns->routerstatus_list, rs[i]);
+ }
+
+ tt_int_op(0, OP_EQ, smartlist_len(nodelist_get_list()));
+
+ nodelist_set_consensus(ns);
+
+ tt_int_op(3, OP_EQ, smartlist_len(nodelist_get_list()));
+
+ /* No Ed25519 info yet, so nothing has an ED id. */
+ tt_ptr_op(NULL, OP_EQ, node_get_by_ed25519_id(md[0]->ed25519_identity_pkey));
+
+ /* Register the first one by md, then look it up. */
+ node_t *n = nodelist_add_microdesc(md[0]);
+ tt_ptr_op(n, OP_EQ, node_get_by_ed25519_id(md[0]->ed25519_identity_pkey));
+
+ /* Register the second by ri, then look it up. */
+ routerinfo_t *ri_old = NULL;
+ n = nodelist_set_routerinfo(ri[1], &ri_old);
+ tt_ptr_op(n, OP_EQ, node_get_by_ed25519_id(md[1]->ed25519_identity_pkey));
+ tt_ptr_op(ri_old, OP_EQ, NULL);
+
+ /* Register it by md too. */
+ node_t *n2 = nodelist_add_microdesc(md[1]);
+ tt_ptr_op(n2, OP_EQ, n);
+ tt_ptr_op(n, OP_EQ, node_get_by_ed25519_id(md[1]->ed25519_identity_pkey));
+
+ /* Register the 4th by ri only -- we never put it into the networkstatus,
+ * so it has to be independent */
+ n = nodelist_set_routerinfo(ri[3], &ri_old);
+ tt_ptr_op(n, OP_EQ, node_get_by_ed25519_id(md[3]->ed25519_identity_pkey));
+ tt_ptr_op(ri_old, OP_EQ, NULL);
+ tt_int_op(4, OP_EQ, smartlist_len(nodelist_get_list()));
+
+ done:
+ for (i = 0; i < 4; ++i) {
+ tor_free(rs[i]);
+ tor_free(md[i]->ed25519_identity_pkey);
+ tor_free(md[i]);
+ tor_free(ri[i]->cache_info.signing_key_cert);
+ tor_free(ri[i]);
+ }
+ smartlist_clear(ns->routerstatus_list);
+ networkstatus_vote_free(ns);
+ UNMOCK(networkstatus_get_latest_consensus);
+ UNMOCK(networkstatus_get_latest_consensus_by_flavor);
+}
+
#define NODE(name, flags) \
{ #name, test_nodelist_##name, (flags), NULL, NULL }
@@ -107,6 +210,7 @@ struct testcase_t nodelist_tests[] = {
NODE(node_get_verbose_nickname_by_id_null_node, TT_FORK),
NODE(node_get_verbose_nickname_not_named, TT_FORK),
NODE(node_is_dir, TT_FORK),
+ NODE(ed_id, TT_FORK),
END_OF_TESTCASES
};
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 6102af01f5..cf28690a28 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 */
@@ -15,6 +15,7 @@
#include "config.h"
#include "relay.h"
#include "test.h"
+#include "test_helpers.h"
/* small replacement mock for circuit_mark_for_close_ to avoid doing all
* the other bookkeeping that comes with marking circuits. */
@@ -58,24 +59,6 @@ dummy_or_circuit_new(int n_p_cells, int n_n_cells)
return TO_CIRCUIT(circ);
}
-static circuit_t *
-dummy_origin_circuit_new(int n_cells)
-{
- origin_circuit_t *circ = origin_circuit_new();
- int i;
- cell_t cell;
-
- for (i=0; i < n_cells; ++i) {
- crypto_rand((void*)&cell, sizeof(cell));
- cell_queue_append_packed_copy(TO_CIRCUIT(circ),
- &TO_CIRCUIT(circ)->n_chan_cells,
- 1, &cell, 1, 0);
- }
-
- TO_CIRCUIT(circ)->purpose = CIRCUIT_PURPOSE_C_GENERAL;
- return TO_CIRCUIT(circ);
-}
-
static void
add_bytes_to_buf(buf_t *buf, size_t n_bytes)
{
@@ -84,7 +67,7 @@ add_bytes_to_buf(buf_t *buf, size_t n_bytes)
while (n_bytes) {
size_t this_add = n_bytes > sizeof(b) ? sizeof(b) : n_bytes;
crypto_rand(b, this_add);
- write_to_buf(b, this_add, buf);
+ buf_add(buf, b, this_add);
n_bytes -= this_add;
}
}
diff --git a/src/test/test_oos.c b/src/test/test_oos.c
index db06625116..e72fcf5de9 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 */
@@ -52,7 +52,7 @@ kill_conn_list_mock(smartlist_t *conns)
{
++kill_conn_list_calls;
- tt_assert(conns != NULL);
+ tt_ptr_op(conns, OP_NE, NULL);
kill_conn_list_killed += smartlist_len(conns);
@@ -248,7 +248,7 @@ close_for_error_mock(or_connection_t *orconn, int flush)
{
(void)flush;
- tt_assert(orconn != NULL);
+ tt_ptr_op(orconn, OP_NE, NULL);
++cfe_calls;
done:
@@ -264,7 +264,7 @@ mark_for_close_oos_mock(connection_t *conn,
(void)line;
(void)file;
- tt_assert(conn != NULL);
+ tt_ptr_op(conn, OP_NE, NULL);
++mark_calls;
done:
@@ -298,8 +298,8 @@ test_oos_kill_conn_list(void *arg)
dir_c2->base_.purpose = DIR_PURPOSE_MIN_;
c2 = TO_CONN(dir_c2);
- tt_assert(c1 != NULL);
- tt_assert(c2 != NULL);
+ tt_ptr_op(c1, OP_NE, NULL);
+ tt_ptr_op(c2, OP_NE, NULL);
/* Make list */
l = smartlist_new();
@@ -345,7 +345,7 @@ get_num_circuits_mock(or_connection_t *conn)
{
int circs = 0;
- tt_assert(conn != NULL);
+ tt_ptr_op(conn, OP_NE, NULL);
if (conns_with_circs &&
smartlist_contains(conns_with_circs, TO_CONN(conn))) {
@@ -397,7 +397,7 @@ test_oos_pick_oos_victims(void *arg)
/* Try picking one */
picked = pick_oos_victims(1);
/* It should be the one with circuits */
- tt_assert(picked != NULL);
+ tt_ptr_op(picked, OP_NE, NULL);
tt_int_op(smartlist_len(picked), OP_EQ, 1);
tt_assert(smartlist_contains(picked, smartlist_get(conns_for_mock, 0)));
smartlist_free(picked);
@@ -405,14 +405,14 @@ test_oos_pick_oos_victims(void *arg)
/* Try picking none */
picked = pick_oos_victims(0);
/* We should get an empty list */
- tt_assert(picked != NULL);
+ tt_ptr_op(picked, OP_NE, NULL);
tt_int_op(smartlist_len(picked), OP_EQ, 0);
smartlist_free(picked);
/* Try picking two */
picked = pick_oos_victims(2);
/* We should get both active orconns */
- tt_assert(picked != NULL);
+ tt_ptr_op(picked, OP_NE, NULL);
tt_int_op(smartlist_len(picked), OP_EQ, 2);
tt_assert(smartlist_contains(picked, smartlist_get(conns_for_mock, 0)));
tt_assert(smartlist_contains(picked, smartlist_get(conns_for_mock, 1)));
diff --git a/src/test/test_options.c b/src/test/test_options.c
index e85e11805b..62732cabf7 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
@@ -18,6 +18,7 @@
#include "sandbox.h"
#include "memarea.h"
#include "policies.h"
+#include "test_helpers.h"
#define NS_MODULE test_options
@@ -104,11 +105,71 @@ clear_log_messages(void)
"EDE6D711294FADF8E7951F4DE6CA56B58 194.109.206.212:80 7EA6 EAD6 FD83" \
" 083C 538F 4403 8BBF A077 587D D755\n"
+static int
+test_options_checklog(const char *configuration, int expect_log_severity,
+ const char *expect_log)
+{
+ int found = 0, ret = -1;
+ char *actual_log = NULL;
+
+ if (messages) {
+ SMARTLIST_FOREACH_BEGIN(messages, logmsg_t *, m) {
+ if (m->severity == expect_log_severity &&
+ strstr(m->msg, expect_log)) {
+ found = 1;
+ break;
+ }
+ } SMARTLIST_FOREACH_END(m);
+ }
+ if (!found) {
+ actual_log = dump_logs();
+ TT_DIE(("Expected log message [%s] %s from <%s>, but got <%s>.",
+ log_level_to_string(expect_log_severity), expect_log,
+ configuration, actual_log));
+ }
+ ret = 0;
+
+ done:
+ tor_free(actual_log);
+ return ret;
+}
+
+static int
+test_options_checkmsgs(const char *configuration,
+ const char *expect_errmsg,
+ int expect_log_severity,
+ const char *expect_log,
+ char *msg)
+{
+ if (expect_errmsg && !msg) {
+ TT_DIE(("Expected error message <%s> from <%s>, but got none.",
+ expect_errmsg, configuration));
+ } else if (expect_errmsg && !strstr(msg, expect_errmsg)) {
+ TT_DIE(("Expected error message <%s> from <%s>, but got <%s>.",
+ expect_errmsg, configuration, msg));
+ } else if (!expect_errmsg && msg) {
+ TT_DIE(("Expected no error message from <%s> but got <%s>.",
+ configuration, msg));
+ }
+ if (expect_log) {
+ return test_options_checklog(configuration, expect_log_severity,
+ expect_log);
+ }
+ 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)
+ const char *expect_log,
+ int phase)
{
or_options_t *opt=NULL;
or_options_t *dflt;
@@ -119,43 +180,34 @@ test_options_validate_impl(const char *configuration,
setup_options(opt, dflt);
r = config_get_lines(configuration, &cl, 1);
- tt_int_op(r, OP_EQ, 0);
+ if (phase == PH_GETLINES) {
+ if (test_options_checkmsgs(configuration, expect_errmsg,
+ expect_log_severity,
+ expect_log, msg))
+ goto done;
+ }
+ if (r)
+ goto done;
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));
- } else if (expect_errmsg && !strstr(msg, expect_errmsg)) {
- TT_DIE(("Expected error message <%s> from <%s>, but got <%s>.",
- expect_errmsg, configuration, msg));
- } else if (!expect_errmsg && msg) {
- TT_DIE(("Expected no error message from <%s> but got <%s>.",
- configuration, msg));
+ 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));
+ if (r)
+ goto done;
- if (expect_log) {
- int found = 0;
- if (messages) {
- SMARTLIST_FOREACH_BEGIN(messages, logmsg_t *, m) {
- if (m->severity == expect_log_severity &&
- strstr(m->msg, expect_log)) {
- found = 1;
- break;
- }
- } SMARTLIST_FOREACH_END(m);
- }
- if (!found) {
- tor_free(msg);
- msg = dump_logs();
- TT_DIE(("Expected log message [%s] %s from <%s>, but got <%s>.",
- log_level_to_string(expect_log_severity), expect_log,
- configuration, msg));
- }
+ 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);
@@ -167,14 +219,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)
@@ -183,21 +235,39 @@ 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);
+
+ WANT_LOG("ControlSocket \"string with trailing garbage\" bogus", LOG_WARN,
+ "Error while parsing configuration: "
+ "Excess data after quoted string", PH_GETLINES);
+ WANT_LOG("ControlSocket \"bogus escape \\@\"", LOG_WARN,
+ "Error while parsing configuration: "
+ "Invalid escape sequence in quoted string", PH_GETLINES);
close_temp_logs();
clear_log_messages();
@@ -212,7 +282,7 @@ test_have_enough_mem_for_dircache(void *arg)
or_options_t *opt=NULL;
or_options_t *dflt=NULL;
config_line_t *cl=NULL;
- char *msg=NULL;;
+ char *msg=NULL;
int r;
const char *configuration = "ORPort 8080\nDirCache 1", *expect_errmsg;
@@ -229,7 +299,7 @@ test_have_enough_mem_for_dircache(void *arg)
/* 300 MB RAM available, DirCache enabled */
r = have_enough_mem_for_dircache(opt, MEGABYTEIFY(300), &msg);
tt_int_op(r, OP_EQ, 0);
- tt_assert(!msg);
+ tt_ptr_op(msg, OP_EQ, NULL);
/* 200 MB RAM available, DirCache enabled */
r = have_enough_mem_for_dircache(opt, MEGABYTEIFY(200), &msg);
@@ -252,7 +322,7 @@ test_have_enough_mem_for_dircache(void *arg)
/* 300 MB RAM available, DirCache enabled, Bridge */
r = have_enough_mem_for_dircache(opt, MEGABYTEIFY(300), &msg);
tt_int_op(r, OP_EQ, 0);
- tt_assert(!msg);
+ tt_ptr_op(msg, OP_EQ, NULL);
/* 200 MB RAM available, DirCache enabled, Bridge */
r = have_enough_mem_for_dircache(opt, MEGABYTEIFY(200), &msg);
@@ -275,7 +345,7 @@ test_have_enough_mem_for_dircache(void *arg)
/* 200 MB RAM available, DirCache disabled */
r = have_enough_mem_for_dircache(opt, MEGABYTEIFY(200), &msg);
tt_int_op(r, OP_EQ, 0);
- tt_assert(!msg);
+ tt_ptr_op(msg, OP_EQ, NULL);
/* 300 MB RAM available, DirCache disabled */
r = have_enough_mem_for_dircache(opt, MEGABYTEIFY(300), &msg);
@@ -328,11 +398,12 @@ fixed_get_uname(void)
"V3AuthVoteDelay 20\n" \
"V3AuthDistDelay 20\n" \
"V3AuthNIntervalsValid 3\n" \
- "ClientUseIPv4 1\n" \
+ "ClientUseIPv4 1\n" \
"VirtualAddrNetworkIPv4 127.192.0.0/10\n" \
"VirtualAddrNetworkIPv6 [FE80::]/10\n" \
- "SchedulerHighWaterMark__ 42\n" \
- "SchedulerLowWaterMark__ 10\n"
+ "UseEntryGuards 1\n" \
+ "Schedulers Vanilla\n" \
+ "ClientDNSRejectInternalAddresses 1\n"
typedef struct {
or_options_t *old_opt;
@@ -352,25 +423,31 @@ get_options_test_data(const char *conf)
result->opt = options_new();
result->old_opt = options_new();
result->def_opt = options_new();
+
+ // XXX: Really, all of these options should be set to defaults
+ // with options_init(), but about a dozen tests break when I do that.
+ // Being kinda lame and just fixing the immedate breakage for now..
+ result->opt->ConnectionPadding = -1; // default must be "auto"
+
rv = config_get_lines(conf, &cl, 1);
- tt_assert(rv == 0);
+ tt_int_op(rv, OP_EQ, 0);
rv = config_assign(&options_format, result->opt, cl, 0, &msg);
if (msg) {
/* Display the parse error message by comparing it with an empty string */
tt_str_op(msg, OP_EQ, "");
}
- tt_assert(rv == 0);
+ tt_int_op(rv, OP_EQ, 0);
config_free_lines(cl);
result->opt->LogTimeGranularity = 1;
result->opt->TokenBucketRefillInterval = 1;
rv = config_get_lines(TEST_OPTIONS_OLD_VALUES, &cl, 1);
- tt_assert(rv == 0);
+ tt_int_op(rv, OP_EQ, 0);
rv = config_assign(&options_format, result->def_opt, cl, 0, &msg);
if (msg) {
/* Display the parse error message by comparing it with an empty string */
tt_str_op(msg, OP_EQ, "");
}
- tt_assert(rv == 0);
+ tt_int_op(rv, OP_EQ, 0);
done:
config_free_lines(cl);
@@ -400,7 +477,7 @@ test_options_validate__uname_for_server(void *ignored)
(void)ignored;
char *msg;
options_test_data_t *tdata = get_options_test_data(
- "ORListenAddress 127.0.0.1:5555");
+ "ORPort 127.0.0.1:5555");
setup_capture_of_logs(LOG_WARN);
MOCK(get_uname, fixed_get_uname);
@@ -430,7 +507,7 @@ test_options_validate__uname_for_server(void *ignored)
fixed_get_uname_result = "Windows 2000";
mock_clean_saved_logs();
options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- expect_log_entry();
+ expect_no_log_entry();
tor_free(msg);
done:
@@ -451,6 +528,8 @@ test_options_validate__outbound_addresses(void *ignored)
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
+ tt_str_op(msg, OP_EQ, "Multiple outbound bind addresses configured: "
+ "xxyy!!!sdfaf");
done:
free_options_test_data(tdata);
@@ -514,13 +593,14 @@ test_options_validate__nickname(void *ignored)
tdata = get_options_test_data("Nickname AMoreValidNick");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
- tt_assert(!msg);
+ tt_str_op(msg, OP_EQ, "ConnLimit must be greater than 0, but was set to 0");
+ tor_free(msg);
free_options_test_data(tdata);
tdata = get_options_test_data("DataDirectory /tmp/somewhere");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
- tt_assert(!msg);
+ tt_str_op(msg, OP_EQ, "ConnLimit must be greater than 0, but was set to 0");
done:
free_options_test_data(tdata);
@@ -534,7 +614,7 @@ test_options_validate__contactinfo(void *ignored)
int ret;
char *msg;
options_test_data_t *tdata = get_options_test_data(
- "ORListenAddress 127.0.0.1:5555\nORPort 955");
+ "ORPort 127.0.0.1:5555");
setup_capture_of_logs(LOG_DEBUG);
tdata->opt->ContactInfo = NULL;
@@ -547,7 +627,7 @@ test_options_validate__contactinfo(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("ORListenAddress 127.0.0.1:5555\nORPort 955\n"
+ tdata = get_options_test_data("ORPort 127.0.0.1:5555\n"
"ContactInfo hella@example.org");
mock_clean_saved_logs();
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
@@ -580,6 +660,7 @@ test_options_validate__logs(void *ignored)
tt_str_op(tdata->opt->Logs->key, OP_EQ, "Log");
tt_str_op(tdata->opt->Logs->value, OP_EQ, "notice stdout");
tor_free(msg);
+ tt_int_op(ret, OP_EQ, -1);
free_options_test_data(tdata);
tdata = get_options_test_data("");
@@ -590,6 +671,7 @@ test_options_validate__logs(void *ignored)
tt_str_op(tdata->opt->Logs->key, OP_EQ, "Log");
tt_str_op(tdata->opt->Logs->value, OP_EQ, "warn stdout");
tor_free(msg);
+ tt_int_op(ret, OP_EQ, -1);
free_options_test_data(tdata);
tdata = get_options_test_data("");
@@ -599,6 +681,7 @@ test_options_validate__logs(void *ignored)
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_assert(!tdata->opt->Logs);
tor_free(msg);
+ tt_int_op(ret, OP_EQ, -1);
free_options_test_data(tdata);
tdata = get_options_test_data("");
@@ -607,6 +690,7 @@ test_options_validate__logs(void *ignored)
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 1, &msg);
tt_assert(!tdata->opt->Logs);
tor_free(msg);
+ tt_int_op(ret, OP_EQ, -1);
free_options_test_data(tdata);
tdata = get_options_test_data("");
@@ -615,6 +699,7 @@ test_options_validate__logs(void *ignored)
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_assert(!tdata->opt->Logs);
tor_free(msg);
+ tt_int_op(ret, OP_EQ, -1);
free_options_test_data(tdata);
tdata = get_options_test_data("");
@@ -624,6 +709,7 @@ test_options_validate__logs(void *ignored)
tdata->opt->Logs = cl;
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op((intptr_t)tdata->opt->Logs, OP_EQ, (intptr_t)cl);
+ tt_int_op(ret, OP_EQ, -1);
done:
quiet_level = orig_quiet_level;
@@ -650,16 +736,18 @@ test_options_validate__authdir(void *ignored)
setup_capture_of_logs(LOG_INFO);
options_test_data_t *tdata = get_options_test_data(
"AuthoritativeDirectory 1\n"
- "Address this.should.not_exist.example.org");
+ "Address this.should.not!exist!.example.org");
sandbox_disable_getaddrinfo_cache();
+ MOCK(tor_addr_lookup, mock_tor_addr_lookup__fail_on_bad_addrs);
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ UNMOCK(tor_addr_lookup);
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "Failed to resolve/guess local address. See logs for"
" details.");
expect_log_msg("Could not resolve local Address "
- "'this.should.not_exist.example.org'. Failing.\n");
+ "'this.should.not!exist!.example.org'. Failing.\n");
tor_free(msg);
free_options_test_data(tdata);
@@ -668,13 +756,13 @@ test_options_validate__authdir(void *ignored)
mock_clean_saved_logs();
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
- tt_assert(!msg);
+ tt_str_op(msg, OP_EQ, "Authoritative directory servers must set "
+ "ContactInfo");
+ tor_free(msg);
free_options_test_data(tdata);
tdata = get_options_test_data("AuthoritativeDirectory 1\n"
- "Address 100.200.10.1\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "Address 100.200.10.1\n");
mock_clean_saved_logs();
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
@@ -685,9 +773,7 @@ test_options_validate__authdir(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data("AuthoritativeDirectory 1\n"
"Address 100.200.10.1\n"
- "TestingTorNetwork 1\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "TestingTorNetwork 1\n");
mock_clean_saved_logs();
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
@@ -698,9 +784,7 @@ test_options_validate__authdir(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data("AuthoritativeDirectory 1\n"
"Address 100.200.10.1\n"
- "ContactInfo hello@hello.com\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "ContactInfo hello@hello.com\n");
mock_clean_saved_logs();
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
@@ -712,9 +796,7 @@ test_options_validate__authdir(void *ignored)
tdata = get_options_test_data("AuthoritativeDirectory 1\n"
"Address 100.200.10.1\n"
"RecommendedVersions 1.2, 3.14\n"
- "ContactInfo hello@hello.com\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "ContactInfo hello@hello.com\n");
mock_clean_saved_logs();
options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_str_op(tdata->opt->RecommendedClientVersions->value, OP_EQ, "1.2, 3.14");
@@ -727,9 +809,7 @@ test_options_validate__authdir(void *ignored)
"RecommendedVersions 1.2, 3.14\n"
"RecommendedClientVersions 25\n"
"RecommendedServerVersions 4.18\n"
- "ContactInfo hello@hello.com\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "ContactInfo hello@hello.com\n");
mock_clean_saved_logs();
options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_str_op(tdata->opt->RecommendedClientVersions->value, OP_EQ, "25");
@@ -743,9 +823,7 @@ test_options_validate__authdir(void *ignored)
"RecommendedVersions 1.2, 3.14\n"
"RecommendedClientVersions 25\n"
"RecommendedServerVersions 4.18\n"
- "ContactInfo hello@hello.com\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "ContactInfo hello@hello.com\n");
mock_clean_saved_logs();
options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_str_op(msg, OP_EQ, "AuthoritativeDir is set, but none of (Bridge/V3)"
@@ -757,9 +835,7 @@ test_options_validate__authdir(void *ignored)
"Address 100.200.10.1\n"
"VersioningAuthoritativeDirectory 1\n"
"RecommendedServerVersions 4.18\n"
- "ContactInfo hello@hello.com\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "ContactInfo hello@hello.com\n");
mock_clean_saved_logs();
options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_str_op(msg, OP_EQ, "Versioning authoritative dir servers must set "
@@ -771,9 +847,7 @@ test_options_validate__authdir(void *ignored)
"Address 100.200.10.1\n"
"VersioningAuthoritativeDirectory 1\n"
"RecommendedClientVersions 4.18\n"
- "ContactInfo hello@hello.com\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "ContactInfo hello@hello.com\n");
mock_clean_saved_logs();
options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_str_op(msg, OP_EQ, "Versioning authoritative dir servers must set "
@@ -784,9 +858,7 @@ test_options_validate__authdir(void *ignored)
tdata = get_options_test_data("AuthoritativeDirectory 1\n"
"Address 100.200.10.1\n"
"UseEntryGuards 1\n"
- "ContactInfo hello@hello.com\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "ContactInfo hello@hello.com\n");
mock_clean_saved_logs();
options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
expect_log_msg("Authoritative directory servers "
@@ -798,9 +870,7 @@ test_options_validate__authdir(void *ignored)
tdata = get_options_test_data("AuthoritativeDirectory 1\n"
"Address 100.200.10.1\n"
"V3AuthoritativeDir 1\n"
- "ContactInfo hello@hello.com\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "ContactInfo hello@hello.com\n");
mock_clean_saved_logs();
options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
expect_log_msg("Authoritative directories always try"
@@ -813,9 +883,7 @@ test_options_validate__authdir(void *ignored)
"Address 100.200.10.1\n"
"DownloadExtraInfo 1\n"
"V3AuthoritativeDir 1\n"
- "ContactInfo hello@hello.com\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "ContactInfo hello@hello.com\n");
mock_clean_saved_logs();
options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
expect_no_log_msg("Authoritative directories always try"
@@ -826,9 +894,7 @@ test_options_validate__authdir(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data("AuthoritativeDirectory 1\n"
"Address 100.200.10.1\n"
- "ContactInfo hello@hello.com\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "ContactInfo hello@hello.com\n");
mock_clean_saved_logs();
options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_str_op(msg, OP_EQ, "AuthoritativeDir is set, but none of (Bridge/V3)"
@@ -840,9 +906,7 @@ test_options_validate__authdir(void *ignored)
"Address 100.200.10.1\n"
"BridgeAuthoritativeDir 1\n"
"ContactInfo hello@hello.com\n"
- "V3BandwidthsFile non-existant-file\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "V3BandwidthsFile non-existant-file\n");
mock_clean_saved_logs();
options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_str_op(msg, OP_EQ,
@@ -854,9 +918,7 @@ test_options_validate__authdir(void *ignored)
"Address 100.200.10.1\n"
"BridgeAuthoritativeDir 1\n"
"ContactInfo hello@hello.com\n"
- "V3BandwidthsFile non-existant-file\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "V3BandwidthsFile non-existant-file\n");
mock_clean_saved_logs();
options_validate(NULL, tdata->opt, tdata->def_opt, 0, &msg);
tt_str_op(msg, OP_EQ,
@@ -868,9 +930,7 @@ test_options_validate__authdir(void *ignored)
"Address 100.200.10.1\n"
"BridgeAuthoritativeDir 1\n"
"ContactInfo hello@hello.com\n"
- "GuardfractionFile non-existant-file\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "GuardfractionFile non-existant-file\n");
mock_clean_saved_logs();
options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_str_op(msg, OP_EQ,
@@ -882,9 +942,7 @@ test_options_validate__authdir(void *ignored)
"Address 100.200.10.1\n"
"BridgeAuthoritativeDir 1\n"
"ContactInfo hello@hello.com\n"
- "GuardfractionFile non-existant-file\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "GuardfractionFile non-existant-file\n");
mock_clean_saved_logs();
options_validate(NULL, tdata->opt, tdata->def_opt, 0, &msg);
tt_str_op(msg, OP_EQ,
@@ -895,9 +953,7 @@ test_options_validate__authdir(void *ignored)
tdata = get_options_test_data("AuthoritativeDirectory 1\n"
"Address 100.200.10.1\n"
"BridgeAuthoritativeDir 1\n"
- "ContactInfo hello@hello.com\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "ContactInfo hello@hello.com\n");
mock_clean_saved_logs();
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
@@ -910,9 +966,7 @@ test_options_validate__authdir(void *ignored)
"Address 100.200.10.1\n"
"DirPort 999\n"
"BridgeAuthoritativeDir 1\n"
- "ContactInfo hello@hello.com\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "ContactInfo hello@hello.com\n");
mock_clean_saved_logs();
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
@@ -929,9 +983,7 @@ test_options_validate__authdir(void *ignored)
/* "ORPort 888\n" */
/* "ClientOnly 1\n" */
/* "BridgeAuthoritativeDir 1\n" */
- /* "ContactInfo hello@hello.com\n" */
- /* "SchedulerHighWaterMark__ 42\n" */
- /* "SchedulerLowWaterMark__ 10\n"); */
+ /* "ContactInfo hello@hello.com\n" ); */
/* mock_clean_saved_logs(); */
/* ret = options_validate(tdata->old_opt, tdata->opt, */
/* tdata->def_opt, 0, &msg); */
@@ -953,8 +1005,7 @@ test_options_validate__relay_with_hidden_services(void *ignored)
char *msg;
setup_capture_of_logs(LOG_DEBUG);
options_test_data_t *tdata = get_options_test_data(
- "ORListenAddress 127.0.0.1:5555\n"
- "ORPort 955\n"
+ "ORPort 127.0.0.1:5555\n"
"HiddenServiceDir "
"/Library/Tor/var/lib/tor/hidden_service/\n"
"HiddenServicePort 80 127.0.0.1:8080\n"
@@ -1018,14 +1069,14 @@ test_options_validate__transproxy(void *ignored)
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
-#if !defined(__OpenBSD__) && !defined( DARWIN )
+#if !defined(OpenBSD) && !defined( DARWIN )
tt_str_op(msg, OP_EQ,
"pf-divert is a OpenBSD-specific and OS X/Darwin-specific feature.");
#else
tt_int_op(tdata->opt->TransProxyType_parsed, OP_EQ, TPT_PF_DIVERT);
tt_str_op(msg, OP_EQ, "Cannot use TransProxyType without "
- "any valid TransPort or TransListenAddress.");
-#endif
+ "any valid TransPort.");
+#endif /* !defined(OpenBSD) && !defined( DARWIN ) */
tor_free(msg);
// Test tproxy trans proxy
@@ -1039,8 +1090,8 @@ test_options_validate__transproxy(void *ignored)
#else
tt_int_op(tdata->opt->TransProxyType_parsed, OP_EQ, TPT_TPROXY);
tt_str_op(msg, OP_EQ, "Cannot use TransProxyType without any valid "
- "TransPort or TransListenAddress.");
-#endif
+ "TransPort.");
+#endif /* !defined(__linux__) */
tor_free(msg);
// Test ipfw trans proxy
@@ -1055,8 +1106,8 @@ test_options_validate__transproxy(void *ignored)
#else
tt_int_op(tdata->opt->TransProxyType_parsed, OP_EQ, TPT_IPFW);
tt_str_op(msg, OP_EQ, "Cannot use TransProxyType without any valid "
- "TransPort or TransListenAddress.");
-#endif
+ "TransPort.");
+#endif /* !defined(KERNEL_MAY_SUPPORT_IPFW) */
tor_free(msg);
// Test unknown trans proxy
@@ -1076,47 +1127,41 @@ test_options_validate__transproxy(void *ignored)
"TransPort 127.0.0.1:123\n");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
- if (msg) {
- TT_DIE(("Expected NULL but got '%s'", msg));
- }
+ tt_str_op(msg, OP_EQ, "ConnLimit must be greater than 0, but was set to 0");
#elif defined(KERNEL_MAY_SUPPORT_IPFW)
tdata = get_options_test_data("TransProxyType ipfw\n"
"TransPort 127.0.0.1:123\n");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
- if (msg) {
- TT_DIE(("Expected NULL but got '%s'", msg));
- }
-#elif defined(__OpenBSD__)
+ tt_str_op(msg, OP_EQ, "ConnLimit must be greater than 0, but was set to 0");
+ tor_free(msg);
+#elif defined(OpenBSD)
tdata = get_options_test_data("TransProxyType pf-divert\n"
"TransPort 127.0.0.1:123\n");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
- if (msg) {
- TT_DIE(("Expected NULL but got '%s'", msg));
- }
+ tt_str_op(msg, OP_EQ, "ConnLimit must be greater than 0, but was set to 0");
+ tor_free(msg);
#elif defined(__NetBSD__)
tdata = get_options_test_data("TransProxyType default\n"
"TransPort 127.0.0.1:123\n");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
- if (msg) {
- TT_DIE(("Expected NULL but got '%s'", msg));
- }
-#endif
+ tt_str_op(msg, OP_EQ, "ConnLimit must be greater than 0, but was set to 0");
+ tor_free(msg);
+#endif /* defined(__linux__) || ... */
// Assert that a test has run for some TransProxyType
tt_assert(tdata);
-#else
+#else /* !(defined(USE_TRANSPARENT)) */
tdata = get_options_test_data("TransPort 127.0.0.1:555\n");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
- tt_str_op(msg, OP_EQ, "TransPort and TransListenAddress are disabled in "
- "this build.");
+ tt_str_op(msg, OP_EQ, "TransPort is disabled in this build.");
tor_free(msg);
-#endif
+#endif /* defined(USE_TRANSPARENT) */
done:
free_options_test_data(tdata);
@@ -1181,9 +1226,7 @@ test_options_validate__exclude_nodes(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data("ExcludeNodes {cn}\n"
- "StrictNodes 1\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "StrictNodes 1\n");
mock_clean_saved_logs();
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
@@ -1194,9 +1237,7 @@ test_options_validate__exclude_nodes(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("ExcludeNodes {cn}\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ tdata = get_options_test_data("ExcludeNodes {cn}\n");
mock_clean_saved_logs();
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
@@ -1214,49 +1255,6 @@ test_options_validate__exclude_nodes(void *ignored)
}
static void
-test_options_validate__scheduler(void *ignored)
-{
- (void)ignored;
- int ret;
- char *msg;
- setup_capture_of_logs(LOG_DEBUG);
- options_test_data_t *tdata = get_options_test_data(
- "SchedulerLowWaterMark__ 0\n");
-
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
- expect_log_msg("Bad SchedulerLowWaterMark__ option\n");
- tor_free(msg);
-
- // TODO: this test cannot run on platforms where UINT32_MAX == UINT64_MAX.
- // I suspect it's unlikely this branch can actually happen
- /* free_options_test_data(tdata); */
- /* tdata = get_options_test_data( */
- /* "SchedulerLowWaterMark 10000000000000000000\n"); */
- /* tdata->opt->SchedulerLowWaterMark__ = (uint64_t)UINT32_MAX; */
- /* tdata->opt->SchedulerLowWaterMark__++; */
- /* mock_clean_saved_logs(); */
- /* ret = options_validate(tdata->old_opt, tdata->opt, */
- /* tdata->def_opt, 0, &msg); */
- /* tt_int_op(ret, OP_EQ, -1); */
- /* expect_log_msg("Bad SchedulerLowWaterMark__ option\n"); */
-
- free_options_test_data(tdata);
- tdata = get_options_test_data("SchedulerLowWaterMark__ 42\n"
- "SchedulerHighWaterMark__ 42\n");
- mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
- expect_log_msg("Bad SchedulerHighWaterMark option\n");
- tor_free(msg);
-
- done:
- teardown_capture_of_logs();
- free_options_test_data(tdata);
- tor_free(msg);
-}
-
-static void
test_options_validate__node_families(void *ignored)
{
(void)ignored;
@@ -1264,9 +1262,7 @@ test_options_validate__node_families(void *ignored)
char *msg;
options_test_data_t *tdata = get_options_test_data(
"NodeFamily flux, flax\n"
- "NodeFamily somewhere\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "NodeFamily somewhere\n");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
@@ -1284,8 +1280,7 @@ test_options_validate__node_families(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ tdata = get_options_test_data("");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
@@ -1293,9 +1288,7 @@ test_options_validate__node_families(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("NodeFamily !flux\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ tdata = get_options_test_data("NodeFamily !flux\n");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
@@ -1309,54 +1302,6 @@ test_options_validate__node_families(void *ignored)
}
static void
-test_options_validate__tlsec(void *ignored)
-{
- (void)ignored;
- int ret;
- char *msg;
- setup_capture_of_logs(LOG_DEBUG);
- options_test_data_t *tdata = get_options_test_data(
- "TLSECGroup ed25519\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
-
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
- expect_log_msg("Unrecognized TLSECGroup: Falling back to the default.\n");
- tt_assert(!tdata->opt->TLSECGroup);
- tor_free(msg);
-
- free_options_test_data(tdata);
- tdata = get_options_test_data("TLSECGroup P224\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
- mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
- expect_no_log_msg(
- "Unrecognized TLSECGroup: Falling back to the default.\n");
- tt_assert(tdata->opt->TLSECGroup);
- tor_free(msg);
-
- free_options_test_data(tdata);
- tdata = get_options_test_data("TLSECGroup P256\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
- mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
- expect_no_log_msg(
- "Unrecognized TLSECGroup: Falling back to the default.\n");
- tt_assert(tdata->opt->TLSECGroup);
- tor_free(msg);
-
- done:
- teardown_capture_of_logs();
- free_options_test_data(tdata);
- tor_free(msg);
-}
-
-static void
test_options_validate__token_bucket(void *ignored)
{
(void)ignored;
@@ -1392,9 +1337,7 @@ test_options_validate__recommended_packages(void *ignored)
setup_capture_of_logs(LOG_WARN);
options_test_data_t *tdata = get_options_test_data(
"RecommendedPackages foo 1.2 http://foo.com sha1=123123123123\n"
- "RecommendedPackages invalid-package-line\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "RecommendedPackages invalid-package-line\n");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
@@ -1416,9 +1359,7 @@ test_options_validate__fetch_dir(void *ignored)
char *msg;
options_test_data_t *tdata = get_options_test_data(
"FetchDirInfoExtraEarly 1\n"
- "FetchDirInfoEarly 0\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "FetchDirInfoEarly 0\n");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
@@ -1428,9 +1369,7 @@ test_options_validate__fetch_dir(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data("FetchDirInfoExtraEarly 1\n"
- "FetchDirInfoEarly 1\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "FetchDirInfoEarly 1\n");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
@@ -1450,9 +1389,7 @@ test_options_validate__conn_limit(void *ignored)
int ret;
char *msg;
options_test_data_t *tdata = get_options_test_data(
- "ConnLimit 0\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "ConnLimit 0\n");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
@@ -1460,9 +1397,7 @@ test_options_validate__conn_limit(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
- tdata = get_options_test_data("ConnLimit 1\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ tdata = get_options_test_data("ConnLimit 1\n");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
@@ -1484,9 +1419,7 @@ test_options_validate__paths_needed(void *ignored)
setup_capture_of_logs(LOG_WARN);
options_test_data_t *tdata = get_options_test_data(
"PathsNeededToBuildCircuits 0.1\n"
- "ConnLimit 1\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "ConnLimit 1\n");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
@@ -1499,9 +1432,7 @@ test_options_validate__paths_needed(void *ignored)
free_options_test_data(tdata);
mock_clean_saved_logs();
tdata = get_options_test_data("PathsNeededToBuildCircuits 0.99\n"
- "ConnLimit 1\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "ConnLimit 1\n");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
@@ -1514,9 +1445,7 @@ test_options_validate__paths_needed(void *ignored)
free_options_test_data(tdata);
mock_clean_saved_logs();
tdata = get_options_test_data("PathsNeededToBuildCircuits 0.91\n"
- "ConnLimit 1\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "ConnLimit 1\n");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
@@ -1539,9 +1468,7 @@ test_options_validate__max_client_circuits(void *ignored)
char *msg;
options_test_data_t *tdata = get_options_test_data(
"MaxClientCircuitsPending 0\n"
- "ConnLimit 1\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "ConnLimit 1\n");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
@@ -1551,9 +1478,7 @@ test_options_validate__max_client_circuits(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data("MaxClientCircuitsPending 1025\n"
- "ConnLimit 1\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "ConnLimit 1\n");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
@@ -1563,9 +1488,7 @@ test_options_validate__max_client_circuits(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data("MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "ConnLimit 1\n");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
@@ -1586,9 +1509,7 @@ test_options_validate__ports(void *ignored)
options_test_data_t *tdata = get_options_test_data(
"FirewallPorts 65537\n"
"MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "ConnLimit 1\n");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
@@ -1599,9 +1520,7 @@ test_options_validate__ports(void *ignored)
tdata = get_options_test_data("FirewallPorts 1\n"
"LongLivedPorts 124444\n"
"MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "ConnLimit 1\n");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
@@ -1613,9 +1532,7 @@ test_options_validate__ports(void *ignored)
"LongLivedPorts 2\n"
"RejectPlaintextPorts 112233\n"
"MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "ConnLimit 1\n");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
@@ -1628,9 +1545,7 @@ test_options_validate__ports(void *ignored)
"RejectPlaintextPorts 3\n"
"WarnPlaintextPorts 65536\n"
"MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "ConnLimit 1\n");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
@@ -1643,9 +1558,7 @@ test_options_validate__ports(void *ignored)
"RejectPlaintextPorts 3\n"
"WarnPlaintextPorts 4\n"
"MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "ConnLimit 1\n");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
@@ -1667,9 +1580,7 @@ test_options_validate__reachable_addresses(void *ignored)
options_test_data_t *tdata = get_options_test_data(
"FascistFirewall 1\n"
"MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "ConnLimit 1\n");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
@@ -1687,9 +1598,7 @@ test_options_validate__reachable_addresses(void *ignored)
"ReachableDirAddresses *:81\n"
"ReachableORAddresses *:444\n"
"MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "ConnLimit 1\n");
tdata->opt->FirewallPorts = smartlist_new();
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
@@ -1703,9 +1612,7 @@ test_options_validate__reachable_addresses(void *ignored)
tdata = get_options_test_data("FascistFirewall 1\n"
"FirewallPort 123\n"
"MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "ConnLimit 1\n");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
@@ -1722,9 +1629,7 @@ test_options_validate__reachable_addresses(void *ignored)
"ReachableAddresses *:83\n"
"ReachableAddresses reject *:*\n"
"MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "ConnLimit 1\n");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
@@ -1738,12 +1643,9 @@ test_options_validate__reachable_addresses(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data("ReachableAddresses *:82\n"
- "ORListenAddress 127.0.0.1:5555\n"
- "ORPort 955\n"
+ "ORPort 127.0.0.1:5555\n"
"MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "ConnLimit 1\n");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
@@ -1752,12 +1654,9 @@ test_options_validate__reachable_addresses(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data("ReachableORAddresses *:82\n"
- "ORListenAddress 127.0.0.1:5555\n"
- "ORPort 955\n"
+ "ORPort 127.0.0.1:5555\n"
"MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "ConnLimit 1\n");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
@@ -1766,12 +1665,9 @@ test_options_validate__reachable_addresses(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data("ReachableDirAddresses *:82\n"
- "ORListenAddress 127.0.0.1:5555\n"
- "ORPort 955\n"
+ "ORPort 127.0.0.1:5555\n"
"MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "ConnLimit 1\n");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
@@ -1780,12 +1676,9 @@ test_options_validate__reachable_addresses(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data("ClientUseIPv4 0\n"
- "ORListenAddress 127.0.0.1:5555\n"
- "ORPort 955\n"
+ "ORPort 127.0.0.1:5555\n"
"MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "ConnLimit 1\n");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
@@ -1794,14 +1687,6 @@ test_options_validate__reachable_addresses(void *ignored)
/* Test IPv4-only clients setting IPv6 preferences */
-#define WARN_PLEASE_USE_IPV6_OR_LOG_MSG \
- "ClientPreferIPv6ORPort 1 is ignored unless tor is using IPv6. " \
- "Please set ClientUseIPv6 1, ClientUseIPv4 0, or configure bridges.\n"
-
-#define WARN_PLEASE_USE_IPV6_DIR_LOG_MSG \
- "ClientPreferIPv6DirPort 1 is ignored unless tor is using IPv6. " \
- "Please set ClientUseIPv6 1, ClientUseIPv4 0, or configure bridges.\n"
-
free_options_test_data(tdata);
tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
"ClientUseIPv4 1\n"
@@ -1811,7 +1696,6 @@ test_options_validate__reachable_addresses(void *ignored)
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, 0);
- expect_log_msg(WARN_PLEASE_USE_IPV6_OR_LOG_MSG);
tor_free(msg);
free_options_test_data(tdata);
@@ -1823,7 +1707,6 @@ test_options_validate__reachable_addresses(void *ignored)
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, 0);
- expect_log_msg(WARN_PLEASE_USE_IPV6_DIR_LOG_MSG);
tor_free(msg);
/* Now test an IPv4/IPv6 client setting IPv6 preferences */
@@ -1891,12 +1774,9 @@ test_options_validate__use_bridges(void *ignored)
options_test_data_t *tdata = get_options_test_data(
"UseBridges 1\n"
"ClientUseIPv4 1\n"
- "ORListenAddress 127.0.0.1:5555\n"
- "ORPort 955\n"
+ "ORPort 127.0.0.1:5555\n"
"MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "ConnLimit 1\n");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
@@ -1907,9 +1787,7 @@ test_options_validate__use_bridges(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data("UseBridges 1\n"
"MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "ConnLimit 1\n");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
@@ -1922,9 +1800,7 @@ test_options_validate__use_bridges(void *ignored)
tdata = get_options_test_data("UseBridges 1\n"
"EntryNodes {cn}\n"
"MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "ConnLimit 1\n");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
@@ -1945,6 +1821,19 @@ test_options_validate__use_bridges(void *ignored)
tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
"UseBridges 1\n"
"Bridge 10.0.0.1\n"
+ "UseEntryGuards 0\n"
+ );
+
+ ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tt_int_op(ret, OP_EQ, -1);
+ tt_str_op(msg, OP_EQ,
+ "Setting UseBridges requires also setting UseEntryGuards.");
+ tor_free(msg);
+
+ free_options_test_data(tdata);
+ tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
+ "UseBridges 1\n"
+ "Bridge 10.0.0.1\n"
"Bridge !!!\n"
);
@@ -1971,9 +1860,7 @@ test_options_validate__entry_nodes(void *ignored)
"EntryNodes {cn}\n"
"UseEntryGuards 0\n"
"MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "ConnLimit 1\n");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
@@ -1985,9 +1872,7 @@ test_options_validate__entry_nodes(void *ignored)
tdata = get_options_test_data("EntryNodes {cn}\n"
"UseEntryGuards 1\n"
"MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "ConnLimit 1\n");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
@@ -2001,56 +1886,6 @@ test_options_validate__entry_nodes(void *ignored)
}
static void
-test_options_validate__invalid_nodes(void *ignored)
-{
- (void)ignored;
- int ret;
- char *msg;
- options_test_data_t *tdata = get_options_test_data(
- "AllowInvalidNodes something_stupid\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
-
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
- tt_str_op(msg, OP_EQ,
- "Unrecognized value 'something_stupid' in AllowInvalidNodes");
- tor_free(msg);
-
- free_options_test_data(tdata);
- tdata = get_options_test_data("AllowInvalidNodes entry, middle, exit\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
-
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
- tt_int_op(tdata->opt->AllowInvalid_, OP_EQ, ALLOW_INVALID_ENTRY |
- ALLOW_INVALID_EXIT | ALLOW_INVALID_MIDDLE);
- tor_free(msg);
-
- free_options_test_data(tdata);
- tdata = get_options_test_data("AllowInvalidNodes introduction, rendezvous\n"
- "MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
-
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, -1);
- tt_int_op(tdata->opt->AllowInvalid_, OP_EQ, ALLOW_INVALID_INTRODUCTION |
- ALLOW_INVALID_RENDEZVOUS);
- tor_free(msg);
-
- done:
- free_options_test_data(tdata);
- tor_free(msg);
-}
-
-static void
test_options_validate__safe_logging(void *ignored)
{
(void)ignored;
@@ -2058,9 +1893,7 @@ test_options_validate__safe_logging(void *ignored)
char *msg;
options_test_data_t *tdata = get_options_test_data(
"MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "ConnLimit 1\n");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
@@ -2070,9 +1903,7 @@ test_options_validate__safe_logging(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data("SafeLogging 0\n"
"MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "ConnLimit 1\n");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
@@ -2082,9 +1913,7 @@ test_options_validate__safe_logging(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data("SafeLogging Relay\n"
"MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "ConnLimit 1\n");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
@@ -2094,9 +1923,7 @@ test_options_validate__safe_logging(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data("SafeLogging 1\n"
"MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "ConnLimit 1\n");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
@@ -2106,9 +1933,7 @@ test_options_validate__safe_logging(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data("SafeLogging stuffy\n"
"MaxClientCircuitsPending 1\n"
- "ConnLimit 1\n"
- "SchedulerHighWaterMark__ 42\n"
- "SchedulerLowWaterMark__ 10\n");
+ "ConnLimit 1\n");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
@@ -2253,6 +2078,7 @@ test_options_validate__testing(void *ignored)
ENSURE_DEFAULT(TestingServerConsensusDownloadSchedule, 3000);
ENSURE_DEFAULT(TestingClientConsensusDownloadSchedule, 3000);
ENSURE_DEFAULT(TestingBridgeDownloadSchedule, 3000);
+ ENSURE_DEFAULT(TestingBridgeBootstrapDownloadSchedule, 3000);
ENSURE_DEFAULT(TestingClientMaxIntervalWithoutRequest, 3000);
ENSURE_DEFAULT(TestingDirConnectionMaxStall, 3000);
ENSURE_DEFAULT(TestingConsensusMaxDownloadTries, 3000);
@@ -2320,30 +2146,6 @@ test_options_validate__hidserv(void *ignored)
}
static void
-test_options_validate__predicted_ports(void *ignored)
-{
- (void)ignored;
- int ret;
- char *msg;
- setup_capture_of_logs(LOG_WARN);
-
- options_test_data_t *tdata = get_options_test_data(
- "PredictedPortsRelevanceTime 100000000\n"
- TEST_OPTIONS_DEFAULT_VALUES);
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, 0);
- expect_log_msg("PredictedPortsRelevanceTime is too "
- "large; clipping to 3600s.\n");
- tt_int_op(tdata->opt->PredictedPortsRelevanceTime, OP_EQ, 3600);
-
- done:
- teardown_capture_of_logs();
- policies_free_all();
- free_options_test_data(tdata);
- tor_free(msg);
-}
-
-static void
test_options_validate__path_bias(void *ignored)
{
(void)ignored;
@@ -2489,8 +2291,7 @@ test_options_validate__bandwidth(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ORListenAddress 127.0.0.1:5555\n"
- "ORPort 955\n"
+ "ORPort 127.0.0.1:5555\n"
"BandwidthRate 1\n"
);
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
@@ -2501,8 +2302,7 @@ test_options_validate__bandwidth(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ORListenAddress 127.0.0.1:5555\n"
- "ORPort 955\n"
+ "ORPort 127.0.0.1:5555\n"
"BandwidthRate 76800\n"
"MaxAdvertisedBandwidth 30000\n"
);
@@ -2514,8 +2314,7 @@ test_options_validate__bandwidth(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ORListenAddress 127.0.0.1:5555\n"
- "ORPort 955\n"
+ "ORPort 127.0.0.1:5555\n"
"BandwidthRate 76800\n"
"RelayBandwidthRate 1\n"
"MaxAdvertisedBandwidth 38400\n"
@@ -2528,8 +2327,7 @@ test_options_validate__bandwidth(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "ORListenAddress 127.0.0.1:5555\n"
- "ORPort 955\n"
+ "ORPort 127.0.0.1:5555\n"
"BandwidthRate 76800\n"
"BandwidthBurst 76800\n"
"RelayBandwidthRate 76800\n"
@@ -2819,8 +2617,8 @@ test_options_validate__single_onion(void *ignored)
tt_int_op(ret, OP_EQ, -1);
tt_str_op(msg, OP_EQ, "HiddenServiceNonAnonymousMode is incompatible with "
"using Tor as an anonymous client. Please set "
- "Socks/Trans/NATD/DNSPort to 0, or HiddenServiceNonAnonymousMode "
- "to 0, or use the non-anonymous Tor2webMode.");
+ "Socks/Trans/NATD/DNSPort to 0, or revert "
+ "HiddenServiceNonAnonymousMode to 0.");
tor_free(msg);
free_options_test_data(tdata);
@@ -2967,8 +2765,7 @@ test_options_validate__accounting(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data(
TEST_OPTIONS_DEFAULT_VALUES
- "ORListenAddress 127.0.0.1:5555\n"
- "ORPort 955\n"
+ "ORPort 127.0.0.1:5555\n"
"BandwidthRate 76800\n"
"BandwidthBurst 76800\n"
"MaxAdvertisedBandwidth 38400\n"
@@ -3037,6 +2834,7 @@ test_options_validate__proxy(void *ignored)
options_test_data_t *tdata = NULL;
sandbox_disable_getaddrinfo_cache();
setup_capture_of_logs(LOG_WARN);
+ MOCK(tor_addr_lookup, mock_tor_addr_lookup__fail_on_bad_addrs);
free_options_test_data(tdata);
tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
@@ -3057,6 +2855,7 @@ test_options_validate__proxy(void *ignored)
tor_free(msg);
free_options_test_data(tdata);
+
tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
"HttpProxy not_so_valid!\n"
);
@@ -3357,6 +3156,7 @@ test_options_validate__proxy(void *ignored)
policies_free_all();
// sandbox_free_getaddrinfo_cache();
tor_free(msg);
+ UNMOCK(tor_addr_lookup);
}
static void
@@ -3550,7 +3350,7 @@ test_options_validate__control(void *ignored)
"can reconfigure your Tor. That's bad! You should upgrade your "
"Tor controller as soon as possible.\n");
tor_free(msg);
-#endif
+#endif /* defined(HAVE_SYS_UN_H) */
free_options_test_data(tdata);
tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
@@ -3599,8 +3399,7 @@ test_options_validate__families(void *ignored)
tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
"MyFamily home\n"
"BridgeRelay 1\n"
- "ORListenAddress 127.0.0.1:5555\n"
- "ORPort 955\n"
+ "ORPort 127.0.0.1:5555\n"
"BandwidthRate 51300\n"
"BandwidthBurst 51300\n"
"MaxAdvertisedBandwidth 25700\n"
@@ -3829,8 +3628,7 @@ test_options_validate__transport(void *ignored)
free_options_test_data(tdata);
tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
"ServerTransportPlugin foo exec bar\n"
- "ORListenAddress 127.0.0.1:5555\n"
- "ORPort 955\n"
+ "ORPort 127.0.0.1:5555\n"
"BandwidthRate 76900\n"
"BandwidthBurst 76900\n"
"MaxAdvertisedBandwidth 38500\n"
@@ -3872,8 +3670,7 @@ test_options_validate__transport(void *ignored)
tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
"ServerTransportListenAddr foo 127.0.0.42:55\n"
"ServerTransportPlugin foo exec bar\n"
- "ORListenAddress 127.0.0.1:5555\n"
- "ORPort 955\n"
+ "ORPort 127.0.0.1:5555\n"
"BandwidthRate 76900\n"
"BandwidthBurst 76900\n"
"MaxAdvertisedBandwidth 38500\n"
@@ -4230,48 +4027,6 @@ test_options_validate__virtual_addr(void *ignored)
}
static void
-test_options_validate__exits(void *ignored)
-{
- (void)ignored;
- int ret;
- char *msg;
- options_test_data_t *tdata = NULL;
- setup_capture_of_logs(LOG_WARN);
-
- free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "AllowSingleHopExits 1"
- );
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, 0);
- expect_log_msg("You have set AllowSingleHopExits; "
- "now your relay will allow others to make one-hop exits. However,"
- " since by default most clients avoid relays that set this option,"
- " most clients will ignore you.\n");
- tor_free(msg);
-
- free_options_test_data(tdata);
- tdata = get_options_test_data(TEST_OPTIONS_DEFAULT_VALUES
- "AllowSingleHopExits 1\n"
- VALID_DIR_AUTH
- );
- mock_clean_saved_logs();
- ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
- tt_int_op(ret, OP_EQ, 0);
- expect_no_log_msg("You have set AllowSingleHopExits; "
- "now your relay will allow others to make one-hop exits. However,"
- " since by default most clients avoid relays that set this option,"
- " most clients will ignore you.\n");
- tor_free(msg);
-
- done:
- policies_free_all();
- teardown_capture_of_logs();
- free_options_test_data(tdata);
- tor_free(msg);
-}
-
-static void
test_options_validate__testing_options(void *ignored)
{
(void)ignored;
@@ -4507,9 +4262,7 @@ struct testcase_t options_tests[] = {
LOCAL_VALIDATE_TEST(relay_with_hidden_services),
LOCAL_VALIDATE_TEST(transproxy),
LOCAL_VALIDATE_TEST(exclude_nodes),
- LOCAL_VALIDATE_TEST(scheduler),
LOCAL_VALIDATE_TEST(node_families),
- LOCAL_VALIDATE_TEST(tlsec),
LOCAL_VALIDATE_TEST(token_bucket),
LOCAL_VALIDATE_TEST(recommended_packages),
LOCAL_VALIDATE_TEST(fetch_dir),
@@ -4520,12 +4273,10 @@ struct testcase_t options_tests[] = {
LOCAL_VALIDATE_TEST(reachable_addresses),
LOCAL_VALIDATE_TEST(use_bridges),
LOCAL_VALIDATE_TEST(entry_nodes),
- LOCAL_VALIDATE_TEST(invalid_nodes),
LOCAL_VALIDATE_TEST(safe_logging),
LOCAL_VALIDATE_TEST(publish_server_descriptor),
LOCAL_VALIDATE_TEST(testing),
LOCAL_VALIDATE_TEST(hidserv),
- LOCAL_VALIDATE_TEST(predicted_ports),
LOCAL_VALIDATE_TEST(path_bias),
LOCAL_VALIDATE_TEST(bandwidth),
LOCAL_VALIDATE_TEST(circuits),
@@ -4543,7 +4294,6 @@ struct testcase_t options_tests[] = {
LOCAL_VALIDATE_TEST(constrained_sockets),
LOCAL_VALIDATE_TEST(v3_auth),
LOCAL_VALIDATE_TEST(virtual_addr),
- LOCAL_VALIDATE_TEST(exits),
LOCAL_VALIDATE_TEST(testing_options),
LOCAL_VALIDATE_TEST(accel),
END_OF_TESTCASES /* */
diff --git a/src/test/test_policy.c b/src/test/test_policy.c
index 1ffdc2cd51..83dca2d431 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"
@@ -59,7 +59,7 @@ test_policy_summary_helper_family_flags(const char *policy_str,
summary = policy_summarize(policy, family);
- tt_assert(summary != NULL);
+ tt_ptr_op(summary, OP_NE, NULL);
tt_str_op(summary,OP_EQ, expected_summary);
short_policy = parse_short_policy(summary);
@@ -147,7 +147,7 @@ test_policies_general(void *arg)
p = router_parse_addr_policy_item_from_string("reject 192.168.0.0/16:*", -1,
&malformed_list);
- tt_assert(p != NULL);
+ tt_ptr_op(p, OP_NE, NULL);
tt_int_op(ADDR_POLICY_REJECT,OP_EQ, p->policy_type);
tor_addr_from_ipv4h(&tar, 0xc0a80000u);
tt_int_op(0,OP_EQ, tor_addr_compare(&p->addr, &tar, CMP_EXACT));
@@ -192,75 +192,75 @@ test_policies_general(void *arg)
policy3 = smartlist_new();
p = router_parse_addr_policy_item_from_string("reject *:*", -1,
&malformed_list);
- tt_assert(p != NULL);
+ tt_ptr_op(p, OP_NE, NULL);
smartlist_add(policy3, p);
p = router_parse_addr_policy_item_from_string("accept *:*", -1,
&malformed_list);
- tt_assert(p != NULL);
+ tt_ptr_op(p, OP_NE, NULL);
smartlist_add(policy3, p);
policy4 = smartlist_new();
p = router_parse_addr_policy_item_from_string("accept *:443", -1,
&malformed_list);
- tt_assert(p != NULL);
+ tt_ptr_op(p, OP_NE, NULL);
smartlist_add(policy4, p);
p = router_parse_addr_policy_item_from_string("accept *:443", -1,
&malformed_list);
- tt_assert(p != NULL);
+ tt_ptr_op(p, OP_NE, NULL);
smartlist_add(policy4, p);
policy5 = smartlist_new();
p = router_parse_addr_policy_item_from_string("reject 0.0.0.0/8:*", -1,
&malformed_list);
- tt_assert(p != NULL);
+ tt_ptr_op(p, OP_NE, NULL);
smartlist_add(policy5, p);
p = router_parse_addr_policy_item_from_string("reject 169.254.0.0/16:*", -1,
&malformed_list);
- tt_assert(p != NULL);
+ tt_ptr_op(p, OP_NE, NULL);
smartlist_add(policy5, p);
p = router_parse_addr_policy_item_from_string("reject 127.0.0.0/8:*", -1,
&malformed_list);
- tt_assert(p != NULL);
+ tt_ptr_op(p, OP_NE, NULL);
smartlist_add(policy5, p);
p = router_parse_addr_policy_item_from_string("reject 192.168.0.0/16:*",
-1, &malformed_list);
- tt_assert(p != NULL);
+ tt_ptr_op(p, OP_NE, NULL);
smartlist_add(policy5, p);
p = router_parse_addr_policy_item_from_string("reject 10.0.0.0/8:*", -1,
&malformed_list);
- tt_assert(p != NULL);
+ tt_ptr_op(p, OP_NE, NULL);
smartlist_add(policy5, p);
p = router_parse_addr_policy_item_from_string("reject 172.16.0.0/12:*", -1,
&malformed_list);
- tt_assert(p != NULL);
+ tt_ptr_op(p, OP_NE, NULL);
smartlist_add(policy5, p);
p = router_parse_addr_policy_item_from_string("reject 80.190.250.90:*", -1,
&malformed_list);
- tt_assert(p != NULL);
+ tt_ptr_op(p, OP_NE, NULL);
smartlist_add(policy5, p);
p = router_parse_addr_policy_item_from_string("reject *:1-65534", -1,
&malformed_list);
- tt_assert(p != NULL);
+ tt_ptr_op(p, OP_NE, NULL);
smartlist_add(policy5, p);
p = router_parse_addr_policy_item_from_string("reject *:65535", -1,
&malformed_list);
- tt_assert(p != NULL);
+ tt_ptr_op(p, OP_NE, NULL);
smartlist_add(policy5, p);
p = router_parse_addr_policy_item_from_string("accept *:1-65535", -1,
&malformed_list);
- tt_assert(p != NULL);
+ tt_ptr_op(p, OP_NE, NULL);
smartlist_add(policy5, p);
policy6 = smartlist_new();
p = router_parse_addr_policy_item_from_string("accept 43.3.0.0/9:*", -1,
&malformed_list);
- tt_assert(p != NULL);
+ tt_ptr_op(p, OP_NE, NULL);
smartlist_add(policy6, p);
policy7 = smartlist_new();
p = router_parse_addr_policy_item_from_string("accept 0.0.0.0/8:*", -1,
&malformed_list);
- tt_assert(p != NULL);
+ tt_ptr_op(p, OP_NE, NULL);
smartlist_add(policy7, p);
tt_int_op(0, OP_EQ, policies_parse_exit_policy(NULL, &policy8,
@@ -282,13 +282,13 @@ test_policies_general(void *arg)
policy10 = smartlist_new();
p = router_parse_addr_policy_item_from_string("accept6 *:*", -1,
&malformed_list);
- tt_assert(p != NULL);
+ tt_ptr_op(p, OP_NE, NULL);
smartlist_add(policy10, p);
policy11 = smartlist_new();
p = router_parse_addr_policy_item_from_string("reject6 *:*", -1,
&malformed_list);
- tt_assert(p != NULL);
+ tt_ptr_op(p, OP_NE, NULL);
smartlist_add(policy11, p);
tt_assert(!exit_policy_is_general_exit(policy));
@@ -392,21 +392,21 @@ test_policies_general(void *arg)
p = router_parse_addr_policy_item_from_string("acce::abcd",
ADDR_POLICY_ACCEPT,
&malformed_list);
- tt_assert(!p);
+ tt_ptr_op(p, OP_EQ, NULL);
tt_assert(malformed_list);
malformed_list = 0;
p = router_parse_addr_policy_item_from_string("7:1234",
ADDR_POLICY_ACCEPT,
&malformed_list);
- tt_assert(!p);
+ tt_ptr_op(p, OP_EQ, NULL);
tt_assert(malformed_list);
malformed_list = 0;
p = router_parse_addr_policy_item_from_string("::",
ADDR_POLICY_ACCEPT,
&malformed_list);
- tt_assert(!p);
+ tt_ptr_op(p, OP_EQ, NULL);
tt_assert(malformed_list);
malformed_list = 0;
@@ -968,73 +968,73 @@ test_policies_general(void *arg)
/* Make sure that IPv4 addresses are ignored in accept6/reject6 lines. */
p = router_parse_addr_policy_item_from_string("accept6 1.2.3.4:*", -1,
&malformed_list);
- tt_assert(p == NULL);
+ tt_ptr_op(p, OP_EQ, NULL);
tt_assert(!malformed_list);
p = router_parse_addr_policy_item_from_string("reject6 2.4.6.0/24:*", -1,
&malformed_list);
- tt_assert(p == NULL);
+ tt_ptr_op(p, OP_EQ, NULL);
tt_assert(!malformed_list);
p = router_parse_addr_policy_item_from_string("accept6 *4:*", -1,
&malformed_list);
- tt_assert(p == NULL);
+ tt_ptr_op(p, OP_EQ, NULL);
tt_assert(!malformed_list);
/* Make sure malformed policies are detected as such. */
p = router_parse_addr_policy_item_from_string("bad_token *4:*", -1,
&malformed_list);
- tt_assert(p == NULL);
+ tt_ptr_op(p, OP_EQ, NULL);
tt_assert(malformed_list);
p = router_parse_addr_policy_item_from_string("accept6 **:*", -1,
&malformed_list);
- tt_assert(p == NULL);
+ tt_ptr_op(p, OP_EQ, NULL);
tt_assert(malformed_list);
p = router_parse_addr_policy_item_from_string("accept */15:*", -1,
&malformed_list);
- tt_assert(p == NULL);
+ tt_ptr_op(p, OP_EQ, NULL);
tt_assert(malformed_list);
p = router_parse_addr_policy_item_from_string("reject6 */:*", -1,
&malformed_list);
- tt_assert(p == NULL);
+ tt_ptr_op(p, OP_EQ, NULL);
tt_assert(malformed_list);
p = router_parse_addr_policy_item_from_string("accept 127.0.0.1/33:*", -1,
&malformed_list);
- tt_assert(p == NULL);
+ tt_ptr_op(p, OP_EQ, NULL);
tt_assert(malformed_list);
p = router_parse_addr_policy_item_from_string("accept6 [::1]/129:*", -1,
&malformed_list);
- tt_assert(p == NULL);
+ tt_ptr_op(p, OP_EQ, NULL);
tt_assert(malformed_list);
p = router_parse_addr_policy_item_from_string("reject 8.8.8.8/-1:*", -1,
&malformed_list);
- tt_assert(p == NULL);
+ tt_ptr_op(p, OP_EQ, NULL);
tt_assert(malformed_list);
p = router_parse_addr_policy_item_from_string("reject 8.8.4.4:10-5", -1,
&malformed_list);
- tt_assert(p == NULL);
+ tt_ptr_op(p, OP_EQ, NULL);
tt_assert(malformed_list);
p = router_parse_addr_policy_item_from_string("reject 1.2.3.4:-1", -1,
&malformed_list);
- tt_assert(p == NULL);
+ tt_ptr_op(p, OP_EQ, NULL);
tt_assert(malformed_list);
/* Test a too-long policy. */
{
char *policy_strng = NULL;
smartlist_t *chunks = smartlist_new();
- smartlist_add(chunks, tor_strdup("accept "));
+ smartlist_add_strdup(chunks, "accept ");
for (i=1; i<10000; ++i)
smartlist_add_asprintf(chunks, "%d,", i);
- smartlist_add(chunks, tor_strdup("20000"));
+ smartlist_add_strdup(chunks, "20000");
policy_strng = smartlist_join_strings(chunks, "", 0, NULL);
SMARTLIST_FOREACH(chunks, char *, ch, tor_free(ch));
smartlist_free(chunks);
@@ -1048,9 +1048,9 @@ test_policies_general(void *arg)
for (i=1; i<2000; i+=2) {
char buf[POLICY_BUF_LEN];
tor_snprintf(buf, sizeof(buf), "reject *:%d", i);
- smartlist_add(sm, tor_strdup(buf));
+ smartlist_add_strdup(sm, buf);
}
- smartlist_add(sm, tor_strdup("accept *:*"));
+ smartlist_add_strdup(sm, "accept *:*");
policy_str = smartlist_join_strings(sm, ",", 0, NULL);
test_policy_summary_helper( policy_str,
"accept 2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,"
@@ -1148,7 +1148,7 @@ test_policies_reject_exit_address(void *arg)
/* test that IPv4 addresses are rejected on an IPv4-only exit */
policies_parse_exit_policy_reject_private(&policy, 0, ipv4_list, 0, 0);
tt_assert(policy);
- tt_assert(smartlist_len(policy) == 1);
+ tt_int_op(smartlist_len(policy), OP_EQ, 1);
tt_assert(test_policy_has_address_helper(policy, &ipv4_addr));
addr_policy_list_free(policy);
policy = NULL;
@@ -1158,12 +1158,12 @@ test_policies_reject_exit_address(void *arg)
* on IPv4-only exits, so policies_parse_exit_policy_reject_private doesn't
* need to do anything) */
policies_parse_exit_policy_reject_private(&policy, 0, ipv6_list, 0, 0);
- tt_assert(policy == NULL);
+ tt_ptr_op(policy, OP_EQ, NULL);
/* test that only IPv4 addresses are rejected on an IPv4-only exit */
policies_parse_exit_policy_reject_private(&policy, 0, both_list, 0, 0);
tt_assert(policy);
- tt_assert(smartlist_len(policy) == 1);
+ tt_int_op(smartlist_len(policy), OP_EQ, 1);
tt_assert(test_policy_has_address_helper(policy, &ipv4_addr));
addr_policy_list_free(policy);
policy = NULL;
@@ -1171,7 +1171,7 @@ test_policies_reject_exit_address(void *arg)
/* Test that lists with duplicate entries produce the same results */
policies_parse_exit_policy_reject_private(&policy, 0, dupl_list, 0, 0);
tt_assert(policy);
- tt_assert(smartlist_len(policy) == 1);
+ tt_int_op(smartlist_len(policy), OP_EQ, 1);
tt_assert(test_policy_has_address_helper(policy, &ipv4_addr));
addr_policy_list_free(policy);
policy = NULL;
@@ -1181,7 +1181,7 @@ test_policies_reject_exit_address(void *arg)
/* test that IPv4 addresses are rejected on an IPv4/IPv6 exit */
policies_parse_exit_policy_reject_private(&policy, 1, ipv4_list, 0, 0);
tt_assert(policy);
- tt_assert(smartlist_len(policy) == 1);
+ tt_int_op(smartlist_len(policy), OP_EQ, 1);
tt_assert(test_policy_has_address_helper(policy, &ipv4_addr));
addr_policy_list_free(policy);
policy = NULL;
@@ -1189,7 +1189,7 @@ test_policies_reject_exit_address(void *arg)
/* test that IPv6 addresses are rejected on an IPv4/IPv6 exit */
policies_parse_exit_policy_reject_private(&policy, 1, ipv6_list, 0, 0);
tt_assert(policy);
- tt_assert(smartlist_len(policy) == 1);
+ tt_int_op(smartlist_len(policy), OP_EQ, 1);
tt_assert(test_policy_has_address_helper(policy, &ipv6_addr));
addr_policy_list_free(policy);
policy = NULL;
@@ -1197,7 +1197,7 @@ test_policies_reject_exit_address(void *arg)
/* test that IPv4 and IPv6 addresses are rejected on an IPv4/IPv6 exit */
policies_parse_exit_policy_reject_private(&policy, 1, both_list, 0, 0);
tt_assert(policy);
- tt_assert(smartlist_len(policy) == 2);
+ tt_int_op(smartlist_len(policy), OP_EQ, 2);
tt_assert(test_policy_has_address_helper(policy, &ipv4_addr));
tt_assert(test_policy_has_address_helper(policy, &ipv6_addr));
addr_policy_list_free(policy);
@@ -1206,7 +1206,7 @@ test_policies_reject_exit_address(void *arg)
/* Test that lists with duplicate entries produce the same results */
policies_parse_exit_policy_reject_private(&policy, 1, dupl_list, 0, 0);
tt_assert(policy);
- tt_assert(smartlist_len(policy) == 2);
+ tt_int_op(smartlist_len(policy), OP_EQ, 2);
tt_assert(test_policy_has_address_helper(policy, &ipv4_addr));
tt_assert(test_policy_has_address_helper(policy, &ipv6_addr));
addr_policy_list_free(policy);
@@ -1258,7 +1258,7 @@ test_policies_reject_port_address(void *arg)
* with IPv6 addresses on IPv4-only exits) */
policies_parse_exit_policy_reject_private(&policy, 0, NULL, 0, 1);
tt_assert(policy);
- tt_assert(smartlist_len(policy) == 1);
+ tt_int_op(smartlist_len(policy), OP_EQ, 1);
tt_assert(test_policy_has_address_helper(policy, &ipv4_port->addr));
addr_policy_list_free(policy);
policy = NULL;
@@ -1266,7 +1266,7 @@ test_policies_reject_port_address(void *arg)
/* test that IPv4 and IPv6 ports are rejected on an IPv4/IPv6 exit */
policies_parse_exit_policy_reject_private(&policy, 1, NULL, 0, 1);
tt_assert(policy);
- tt_assert(smartlist_len(policy) == 2);
+ tt_int_op(smartlist_len(policy), OP_EQ, 2);
tt_assert(test_policy_has_address_helper(policy, &ipv4_port->addr));
tt_assert(test_policy_has_address_helper(policy, &ipv6_port->addr));
addr_policy_list_free(policy);
@@ -1337,7 +1337,7 @@ test_policies_reject_interface_address(void *arg)
/* test that no addresses are rejected when none are supplied/requested */
policies_parse_exit_policy_reject_private(&policy, 0, NULL, 0, 0);
- tt_assert(policy == NULL);
+ tt_ptr_op(policy, OP_EQ, NULL);
/* test that only IPv4 interface addresses are rejected on an IPv4-only exit
* (and allow for duplicates)
@@ -1372,7 +1372,7 @@ test_policies_reject_interface_address(void *arg)
/* test that no addresses are rejected when none are supplied/requested */
policies_parse_exit_policy_reject_private(&policy, 0, NULL, 0, 0);
- tt_assert(policy == NULL);
+ tt_ptr_op(policy, OP_EQ, NULL);
/* test that only IPv4 interface addresses are rejected on an IPv4-only exit
*/
@@ -1528,15 +1528,15 @@ test_policies_getinfo_helper_policies(void *arg)
memset(&mock_my_routerinfo, 0, sizeof(mock_my_routerinfo));
rv = getinfo_helper_policies(NULL, "exit-policy/default", &answer, &errmsg);
- tt_assert(rv == 0);
- tt_assert(answer != NULL);
+ tt_int_op(rv, OP_EQ, 0);
+ tt_ptr_op(answer, OP_NE, NULL);
tt_assert(strlen(answer) > 0);
tor_free(answer);
rv = getinfo_helper_policies(NULL, "exit-policy/reject-private/default",
&answer, &errmsg);
- tt_assert(rv == 0);
- tt_assert(answer != NULL);
+ tt_int_op(rv, OP_EQ, 0);
+ tt_ptr_op(answer, OP_NE, NULL);
tt_assert(strlen(answer) > 0);
tor_free(answer);
@@ -1550,15 +1550,15 @@ test_policies_getinfo_helper_policies(void *arg)
rv = getinfo_helper_policies(NULL, "exit-policy/reject-private/relay",
&answer, &errmsg);
- tt_assert(rv == 0);
- tt_assert(answer != NULL);
+ tt_int_op(rv, OP_EQ, 0);
+ tt_ptr_op(answer, OP_NE, NULL);
tt_assert(strlen(answer) == 0);
tor_free(answer);
rv = getinfo_helper_policies(NULL, "exit-policy/ipv4", &answer,
&errmsg);
- tt_assert(rv == 0);
- tt_assert(answer != NULL);
+ tt_int_op(rv, OP_EQ, 0);
+ tt_ptr_op(answer, OP_NE, NULL);
ipv4_len = strlen(answer);
tt_assert(ipv4_len == 0 || ipv4_len == strlen(DEFAULT_POLICY_STRING));
tt_assert(ipv4_len == 0 || !strcasecmp(answer, DEFAULT_POLICY_STRING));
@@ -1566,8 +1566,8 @@ test_policies_getinfo_helper_policies(void *arg)
rv = getinfo_helper_policies(NULL, "exit-policy/ipv6", &answer,
&errmsg);
- tt_assert(rv == 0);
- tt_assert(answer != NULL);
+ tt_int_op(rv, OP_EQ, 0);
+ tt_ptr_op(answer, OP_NE, NULL);
ipv6_len = strlen(answer);
tt_assert(ipv6_len == 0 || ipv6_len == strlen(DEFAULT_POLICY_STRING));
tt_assert(ipv6_len == 0 || !strcasecmp(answer, DEFAULT_POLICY_STRING));
@@ -1575,8 +1575,8 @@ test_policies_getinfo_helper_policies(void *arg)
rv = getinfo_helper_policies(NULL, "exit-policy/full", &answer,
&errmsg);
- tt_assert(rv == 0);
- tt_assert(answer != NULL);
+ tt_int_op(rv, OP_EQ, 0);
+ tt_ptr_op(answer, OP_NE, NULL);
/* It's either empty or it's the default */
tt_assert(strlen(answer) == 0 || !strcasecmp(answer, DEFAULT_POLICY_STRING));
tor_free(answer);
@@ -1587,16 +1587,20 @@ test_policies_getinfo_helper_policies(void *arg)
append_exit_policy_string(&mock_my_routerinfo.exit_policy, "reject *6:*");
mock_options.IPv6Exit = 1;
- tor_addr_from_ipv4h(&mock_options.OutboundBindAddressIPv4_, TEST_IPV4_ADDR);
- tor_addr_parse(&mock_options.OutboundBindAddressIPv6_, TEST_IPV6_ADDR);
+ tor_addr_from_ipv4h(
+ &mock_options.OutboundBindAddresses[OUTBOUND_ADDR_EXIT][0],
+ TEST_IPV4_ADDR);
+ tor_addr_parse(
+ &mock_options.OutboundBindAddresses[OUTBOUND_ADDR_EXIT][1],
+ TEST_IPV6_ADDR);
mock_options.ExitPolicyRejectPrivate = 1;
mock_options.ExitPolicyRejectLocalInterfaces = 1;
rv = getinfo_helper_policies(NULL, "exit-policy/reject-private/relay",
&answer, &errmsg);
- tt_assert(rv == 0);
- tt_assert(answer != NULL);
+ tt_int_op(rv, OP_EQ, 0);
+ tt_ptr_op(answer, OP_NE, NULL);
tt_assert(strlen(answer) > 0);
tor_free(answer);
@@ -1605,8 +1609,8 @@ test_policies_getinfo_helper_policies(void *arg)
rv = getinfo_helper_policies(NULL, "exit-policy/reject-private/relay",
&answer, &errmsg);
- tt_assert(rv == 0);
- tt_assert(answer != NULL);
+ tt_int_op(rv, OP_EQ, 0);
+ tt_ptr_op(answer, OP_NE, NULL);
tt_assert(strlen(answer) > 0);
tor_free(answer);
@@ -1615,8 +1619,8 @@ test_policies_getinfo_helper_policies(void *arg)
rv = getinfo_helper_policies(NULL, "exit-policy/reject-private/relay",
&answer, &errmsg);
- tt_assert(rv == 0);
- tt_assert(answer != NULL);
+ tt_int_op(rv, OP_EQ, 0);
+ tt_ptr_op(answer, OP_NE, NULL);
tt_assert(strlen(answer) > 0);
tor_free(answer);
@@ -1625,31 +1629,31 @@ test_policies_getinfo_helper_policies(void *arg)
rv = getinfo_helper_policies(NULL, "exit-policy/reject-private/relay",
&answer, &errmsg);
- tt_assert(rv == 0);
- tt_assert(answer != NULL);
+ tt_int_op(rv, OP_EQ, 0);
+ tt_ptr_op(answer, OP_NE, NULL);
tt_assert(strlen(answer) == 0);
tor_free(answer);
rv = getinfo_helper_policies(NULL, "exit-policy/ipv4", &answer,
&errmsg);
- tt_assert(rv == 0);
- tt_assert(answer != NULL);
+ tt_int_op(rv, OP_EQ, 0);
+ tt_ptr_op(answer, OP_NE, NULL);
ipv4_len = strlen(answer);
tt_assert(ipv4_len > 0);
tor_free(answer);
rv = getinfo_helper_policies(NULL, "exit-policy/ipv6", &answer,
&errmsg);
- tt_assert(rv == 0);
- tt_assert(answer != NULL);
+ tt_int_op(rv, OP_EQ, 0);
+ tt_ptr_op(answer, OP_NE, NULL);
ipv6_len = strlen(answer);
tt_assert(ipv6_len > 0);
tor_free(answer);
rv = getinfo_helper_policies(NULL, "exit-policy/full", &answer,
&errmsg);
- tt_assert(rv == 0);
- tt_assert(answer != NULL);
+ tt_int_op(rv, OP_EQ, 0);
+ tt_ptr_op(answer, OP_NE, NULL);
tt_assert(strlen(answer) > 0);
tt_assert(strlen(answer) == ipv4_len + ipv6_len + 1);
tor_free(answer);
@@ -1742,34 +1746,34 @@ test_policies_fascist_firewall_allows_address(void *arg)
mock_options.ClientUseIPv6 = 1;
mock_options.UseBridges = 0;
- tt_assert(fascist_firewall_allows_address(&ipv4_addr, port, policy, 0, 0)
- == 1);
- tt_assert(fascist_firewall_allows_address(&ipv6_addr, port, policy, 0, 0)
- == 1);
- tt_assert(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 0, 0)
- == 0);
- tt_assert(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 0, 0)
- == 0);
+ tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, policy, 0, 0),
+ OP_EQ, 1);
+ tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, policy, 0, 0),
+ OP_EQ, 1);
+ tt_int_op(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 0, 0),
+ OP_EQ, 0);
+ tt_int_op(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 0, 0),
+ OP_EQ, 0);
/* Preferring IPv4 */
- tt_assert(fascist_firewall_allows_address(&ipv4_addr, port, policy, 1, 0)
- == 1);
- tt_assert(fascist_firewall_allows_address(&ipv6_addr, port, policy, 1, 0)
- == 0);
- tt_assert(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 1, 0)
- == 0);
- tt_assert(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 1, 0)
- == 0);
+ tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, policy, 1, 0),
+ OP_EQ, 1);
+ tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, policy, 1, 0),
+ OP_EQ, 0);
+ tt_int_op(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 1, 0),
+ OP_EQ, 0);
+ tt_int_op(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 1, 0),
+ OP_EQ, 0);
/* Preferring IPv6 */
- tt_assert(fascist_firewall_allows_address(&ipv4_addr, port, policy, 1, 1)
- == 0);
- tt_assert(fascist_firewall_allows_address(&ipv6_addr, port, policy, 1, 1)
- == 1);
- tt_assert(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 1, 1)
- == 0);
- tt_assert(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 1, 1)
- == 0);
+ tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, policy, 1, 1),
+ OP_EQ, 0);
+ tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, policy, 1, 1),
+ OP_EQ, 1);
+ tt_int_op(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 1, 1),
+ OP_EQ, 0);
+ tt_int_op(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 1, 1),
+ OP_EQ, 0);
/* Test the function's address matching with UseBridges on */
memset(&mock_options, 0, sizeof(or_options_t));
@@ -1777,46 +1781,46 @@ test_policies_fascist_firewall_allows_address(void *arg)
mock_options.ClientUseIPv6 = 1;
mock_options.UseBridges = 1;
- tt_assert(fascist_firewall_allows_address(&ipv4_addr, port, policy, 0, 0)
- == 1);
- tt_assert(fascist_firewall_allows_address(&ipv6_addr, port, policy, 0, 0)
- == 1);
- tt_assert(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 0, 0)
- == 0);
- tt_assert(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 0, 0)
- == 0);
+ tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, policy, 0, 0),
+ OP_EQ, 1);
+ tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, policy, 0, 0),
+ OP_EQ, 1);
+ tt_int_op(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 0, 0),
+ OP_EQ, 0);
+ tt_int_op(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 0, 0),
+ OP_EQ, 0);
/* Preferring IPv4 */
- tt_assert(fascist_firewall_allows_address(&ipv4_addr, port, policy, 1, 0)
- == 1);
- tt_assert(fascist_firewall_allows_address(&ipv6_addr, port, policy, 1, 0)
- == 0);
- tt_assert(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 1, 0)
- == 0);
- tt_assert(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 1, 0)
- == 0);
+ tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, policy, 1, 0),
+ OP_EQ, 1);
+ tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, policy, 1, 0),
+ OP_EQ, 0);
+ tt_int_op(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 1, 0),
+ OP_EQ, 0);
+ tt_int_op(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 1, 0),
+ OP_EQ, 0);
/* Preferring IPv6 */
- tt_assert(fascist_firewall_allows_address(&ipv4_addr, port, policy, 1, 1)
- == 0);
- tt_assert(fascist_firewall_allows_address(&ipv6_addr, port, policy, 1, 1)
- == 1);
- tt_assert(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 1, 1)
- == 0);
- tt_assert(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 1, 1)
- == 0);
+ tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, policy, 1, 1),
+ OP_EQ, 0);
+ tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, policy, 1, 1),
+ OP_EQ, 1);
+ tt_int_op(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 1, 1),
+ OP_EQ, 0);
+ tt_int_op(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 1, 1),
+ OP_EQ, 0);
/* bridge clients always use IPv6, regardless of ClientUseIPv6 */
mock_options.ClientUseIPv4 = 1;
mock_options.ClientUseIPv6 = 0;
- tt_assert(fascist_firewall_allows_address(&ipv4_addr, port, policy, 0, 0)
- == 1);
- tt_assert(fascist_firewall_allows_address(&ipv6_addr, port, policy, 0, 0)
- == 1);
- tt_assert(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 0, 0)
- == 0);
- tt_assert(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 0, 0)
- == 0);
+ tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, policy, 0, 0),
+ OP_EQ, 1);
+ tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, policy, 0, 0),
+ OP_EQ, 1);
+ tt_int_op(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 0, 0),
+ OP_EQ, 0);
+ tt_int_op(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 0, 0),
+ OP_EQ, 0);
/* Test the function's address matching with IPv4 on */
memset(&mock_options, 0, sizeof(or_options_t));
@@ -1824,14 +1828,14 @@ test_policies_fascist_firewall_allows_address(void *arg)
mock_options.ClientUseIPv6 = 0;
mock_options.UseBridges = 0;
- tt_assert(fascist_firewall_allows_address(&ipv4_addr, port, policy, 0, 0)
- == 1);
- tt_assert(fascist_firewall_allows_address(&ipv6_addr, port, policy, 0, 0)
- == 0);
- tt_assert(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 0, 0)
- == 0);
- tt_assert(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 0, 0)
- == 0);
+ tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, policy, 0, 0),
+ OP_EQ, 1);
+ tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, policy, 0, 0),
+ OP_EQ, 0);
+ tt_int_op(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 0, 0),
+ OP_EQ, 0);
+ tt_int_op(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 0, 0),
+ OP_EQ, 0);
/* Test the function's address matching with IPv6 on */
memset(&mock_options, 0, sizeof(or_options_t));
@@ -1839,14 +1843,14 @@ test_policies_fascist_firewall_allows_address(void *arg)
mock_options.ClientUseIPv6 = 1;
mock_options.UseBridges = 0;
- tt_assert(fascist_firewall_allows_address(&ipv4_addr, port, policy, 0, 0)
- == 0);
- tt_assert(fascist_firewall_allows_address(&ipv6_addr, port, policy, 0, 0)
- == 1);
- tt_assert(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 0, 0)
- == 0);
- tt_assert(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 0, 0)
- == 0);
+ tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, policy, 0, 0),
+ OP_EQ, 0);
+ tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, policy, 0, 0),
+ OP_EQ, 1);
+ tt_int_op(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 0, 0),
+ OP_EQ, 0);
+ tt_int_op(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 0, 0),
+ OP_EQ, 0);
/* Test the function's address matching with ClientUseIPv4 0.
* This means "use IPv6" regardless of the other settings. */
@@ -1855,14 +1859,14 @@ test_policies_fascist_firewall_allows_address(void *arg)
mock_options.ClientUseIPv6 = 0;
mock_options.UseBridges = 0;
- tt_assert(fascist_firewall_allows_address(&ipv4_addr, port, policy, 0, 0)
- == 0);
- tt_assert(fascist_firewall_allows_address(&ipv6_addr, port, policy, 0, 0)
- == 1);
- tt_assert(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 0, 0)
- == 0);
- tt_assert(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 0, 0)
- == 0);
+ tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, policy, 0, 0),
+ OP_EQ, 0);
+ tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, policy, 0, 0),
+ OP_EQ, 1);
+ tt_int_op(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 0, 0),
+ OP_EQ, 0);
+ tt_int_op(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 0, 0),
+ OP_EQ, 0);
/* Test the function's address matching for unusual inputs */
memset(&mock_options, 0, sizeof(or_options_t));
@@ -1871,27 +1875,28 @@ test_policies_fascist_firewall_allows_address(void *arg)
mock_options.UseBridges = 1;
/* NULL and tor_addr_is_null addresses are rejected */
- tt_assert(fascist_firewall_allows_address(NULL, port, policy, 0, 0) == 0);
- tt_assert(fascist_firewall_allows_address(&n_ipv4_addr, port, policy, 0, 0)
- == 0);
- tt_assert(fascist_firewall_allows_address(&n_ipv6_addr, port, policy, 0, 0)
- == 0);
+ tt_int_op(fascist_firewall_allows_address(NULL, port, policy, 0, 0), OP_EQ,
+ 0);
+ tt_int_op(fascist_firewall_allows_address(&n_ipv4_addr, port, policy, 0, 0),
+ OP_EQ, 0);
+ tt_int_op(fascist_firewall_allows_address(&n_ipv6_addr, port, policy, 0, 0),
+ OP_EQ, 0);
/* zero ports are rejected */
- tt_assert(fascist_firewall_allows_address(&ipv4_addr, 0, policy, 0, 0)
- == 0);
- tt_assert(fascist_firewall_allows_address(&ipv6_addr, 0, policy, 0, 0)
- == 0);
+ tt_int_op(fascist_firewall_allows_address(&ipv4_addr, 0, policy, 0, 0),
+ OP_EQ, 0);
+ tt_int_op(fascist_firewall_allows_address(&ipv6_addr, 0, policy, 0, 0),
+ OP_EQ, 0);
/* NULL and empty policies accept everything */
- tt_assert(fascist_firewall_allows_address(&ipv4_addr, port, NULL, 0, 0)
- == 1);
- tt_assert(fascist_firewall_allows_address(&ipv6_addr, port, NULL, 0, 0)
- == 1);
- tt_assert(fascist_firewall_allows_address(&ipv4_addr, port, e_policy, 0, 0)
- == 1);
- tt_assert(fascist_firewall_allows_address(&ipv6_addr, port, e_policy, 0, 0)
- == 1);
+ tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, NULL, 0, 0),
+ OP_EQ, 1);
+ tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, NULL, 0, 0),
+ OP_EQ, 1);
+ tt_int_op(fascist_firewall_allows_address(&ipv4_addr, port, e_policy, 0, 0),
+ OP_EQ, 1);
+ tt_int_op(fascist_firewall_allows_address(&ipv6_addr, port, e_policy, 0, 0),
+ OP_EQ, 1);
done:
addr_policy_free(item);
@@ -2028,12 +2033,12 @@ test_policies_fascist_firewall_choose_address(void *arg)
== &ipv6_or_ap);
/* null both OR addresses */
- tt_assert(fascist_firewall_choose_address(&n_ipv4_ap, &n_ipv6_ap, 0,
- FIREWALL_OR_CONNECTION, 0, 1)
- == NULL);
- tt_assert(fascist_firewall_choose_address(&n_ipv4_ap, &n_ipv6_ap, 1,
- FIREWALL_OR_CONNECTION, 0, 0)
- == NULL);
+ tt_ptr_op(fascist_firewall_choose_address(&n_ipv4_ap, &n_ipv6_ap, 0,
+ FIREWALL_OR_CONNECTION, 0, 1),
+ OP_EQ, NULL);
+ tt_ptr_op(fascist_firewall_choose_address(&n_ipv4_ap, &n_ipv6_ap, 1,
+ FIREWALL_OR_CONNECTION, 0, 0),
+ OP_EQ, NULL);
/* null preferred Dir addresses */
tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &n_ipv6_ap, 0,
@@ -2044,12 +2049,12 @@ test_policies_fascist_firewall_choose_address(void *arg)
== &ipv6_dir_ap);
/* null both Dir addresses */
- tt_assert(fascist_firewall_choose_address(&n_ipv4_ap, &n_ipv6_ap, 0,
- FIREWALL_DIR_CONNECTION, 0, 1)
- == NULL);
- tt_assert(fascist_firewall_choose_address(&n_ipv4_ap, &n_ipv6_ap, 1,
- FIREWALL_DIR_CONNECTION, 0, 0)
- == NULL);
+ tt_ptr_op(fascist_firewall_choose_address(&n_ipv4_ap, &n_ipv6_ap, 0,
+ FIREWALL_DIR_CONNECTION, 0, 1),
+ OP_EQ, NULL);
+ tt_ptr_op(fascist_firewall_choose_address(&n_ipv4_ap, &n_ipv6_ap, 1,
+ FIREWALL_DIR_CONNECTION, 0, 0),
+ OP_EQ, NULL);
/* Prefer IPv4 but want IPv6 (contradictory) */
tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0,
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_proto_http.c b/src/test/test_proto_http.c
new file mode 100644
index 0000000000..2f36fbccd7
--- /dev/null
+++ b/src/test/test_proto_http.c
@@ -0,0 +1,213 @@
+/* Copyright (c) 2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file test_proto_http.c
+ * \brief Tests for our HTTP protocol parser code
+ */
+
+#include "or.h"
+#include "test.h"
+#include "buffers.h"
+#include "proto_http.h"
+#include "log_test_helpers.h"
+
+#define S(str) str, sizeof(str)-1
+
+static void
+test_proto_http_peek(void *arg)
+{
+ (void) arg;
+ const struct {
+ int is_http;
+ const char *message;
+ size_t len;
+ } cases[] = {
+ { 1, S("GET /index HTTP/1.0\r\n") },
+ { 1, S("GET /index HTTP/1.1\r\n") },
+ { 1, S("GET ") },
+ { 0, S("GIT ") },
+ { 0, S("GET") },
+ { 0, S("get ") },
+ { 0, S("GETAWAY") },
+ };
+ unsigned i;
+ buf_t *buf = buf_new();
+ for (i = 0; i < ARRAY_LENGTH(cases); ++i) {
+ TT_BLATHER(("Trying case %u", i));
+ buf_add(buf, cases[i].message, cases[i].len);
+ tt_int_op(cases[i].is_http, OP_EQ, peek_buf_has_http_command(buf));
+ buf_clear(buf);
+ }
+ done:
+ buf_free(buf);
+}
+
+static void
+test_proto_http_valid(void *arg)
+{
+ (void) arg;
+ const struct {
+ const char *message;
+ size_t len;
+ const char *headers;
+ const char *body;
+ size_t bodylen;
+ int should_detect_truncated;
+ int bytes_left_over;
+ } cases[] = {
+ { S("GET /index.html HTTP/1.0\r\n\r\n"),
+ "GET /index.html HTTP/1.0\r\n\r\n",
+ S(""),
+ 1, 0,
+ },
+ { S("PUT /tor/foo HTTP/1.1\r\n"
+ "Content-Length: 51\r\n\r\n"
+ "this is a test of the http parsing system . test te"),
+ "PUT /tor/foo HTTP/1.1\r\n" "Content-Length: 51\r\n\r\n",
+ S("this is a test of the http parsing system . test te"),
+ 1, 0,
+ },
+ { S("PUT /tor/foo HTTP/1.1\r\n"
+ "Content-Length: 5\r\n\r\n"
+ "there are more than 5 characters in this body."),
+ "PUT /tor/foo HTTP/1.1\r\n" "Content-Length: 5\r\n\r\n",
+ S("there"),
+ 0, 41,
+ },
+ { S("PUT /tor/bar HTTP/1.1\r\n\r\n"
+ "this is another \x00test"),
+ "PUT /tor/bar HTTP/1.1\r\n\r\n",
+ S("this is another \x00test"),
+ 0, 0,
+ }
+ };
+ unsigned i;
+ buf_t *buf = buf_new();
+ char *h = NULL, *b = NULL;
+
+ for (i = 0; i < ARRAY_LENGTH(cases); ++i) {
+ TT_BLATHER(("Trying case %u", i));
+ size_t bl = 0;
+ // truncate by 2 chars
+ buf_add(buf, cases[i].message, cases[i].len - 2);
+
+ if (cases[i].should_detect_truncated) {
+ tt_int_op(0, OP_EQ, fetch_from_buf_http(buf, &h, 1024*16,
+ &b, &bl, 1024*16, 0));
+ tt_ptr_op(h, OP_EQ, NULL);
+ tt_ptr_op(b, OP_EQ, NULL);
+ tt_u64_op(bl, OP_EQ, 0);
+ tt_int_op(buf_datalen(buf), OP_EQ, cases[i].len - 2);
+ }
+
+ // add the rest.
+ buf_add(buf, cases[i].message+cases[i].len-2, 2);
+ tt_int_op(1, OP_EQ, fetch_from_buf_http(buf, &h, 1024*16,
+ &b, &bl, 1024*16, 0));
+ tt_str_op(h, OP_EQ, cases[i].headers);
+ tt_u64_op(bl, OP_EQ, cases[i].bodylen);
+ tt_mem_op(b, OP_EQ, cases[i].body, bl);
+ tt_int_op(buf_datalen(buf), OP_EQ, cases[i].bytes_left_over);
+
+ buf_clear(buf);
+ tor_free(h);
+ tor_free(b);
+ }
+ done:
+ tor_free(h);
+ tor_free(b);
+ buf_free(buf);
+}
+
+static void
+test_proto_http_invalid(void *arg)
+{
+ (void) arg;
+ const struct {
+ const char *message;
+ size_t len;
+ const char *expect;
+ } cases[] = {
+ /* Overlong headers, headers not finished. */
+ { S("GET /index.xhml HTTP/1.0\r\n"
+ "X-My-headers-are-too-long: yes indeed they are. They might be\r\n"
+ "X-My-headers-are-too-long: normal under other circumstances, but\r\n"
+ "X-My-headers-are-too-long: the 128-byte limit makes them bad\r\n"),
+ "headers too long." },
+ /* Overlong finished headers. */
+ { S("GET /index.xhml HTTP/1.0\r\n"
+ "X-My-headers-are-too-long: yes indeed they are. They might be\r\n"
+ "X-My-headers-are-too-long: normal under other circumstances, but\r\n"
+ "X-My-headers-are-too-long: the 128-byte limit makes them bad\r\n"
+ "\r\n"),
+ "headers too long." },
+ /* Exactly too long finished headers. */
+ { S("GET /index.xhml HTTP/1.0\r\n"
+ "X-My-headers-are-too-long: yes indeed they are. They might be\r\n"
+ "X-My-headers-are-too-long: normal un\r\n\r\n"),
+ "headerlen 129 larger than 127. Failing." },
+ /* Body too long, with content-length */
+ { S("GET /index.html HTTP/1.0\r\n"
+ "Content-Length: 129\r\n\r\n"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "xxxxxxxxxxxxxxxxxxx"),
+ "bodylen 129 larger than 127" },
+ /* Body too long, with content-length lying */
+ { S("GET /index.html HTTP/1.0\r\n"
+ "Content-Length: 99999\r\n\r\n"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxx"),
+ "bodylen 138 larger than 127" },
+ /* Body too long, no content-length. */
+ { S("GET /index.html HTTP/1.0\r\n\r\n"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxz"),
+ "bodylen 139 larger than 127" },
+ /* Content-Length is junk. */
+ { S("GET /index.html HTTP/1.0\r\n"
+ "Content-Length: Cheese\r\n\r\n"
+ "foo"),
+ "Content-Length is bogus; maybe someone is trying to crash us." },
+ };
+ unsigned i;
+ buf_t *buf = buf_new();
+ char *h = NULL, *b = NULL;
+ setup_capture_of_logs(LOG_DEBUG);
+
+ for (i = 0; i < ARRAY_LENGTH(cases); ++i) {
+ TT_BLATHER(("Trying case %u", i));
+ size_t bl = 0;
+ buf_add(buf, cases[i].message, cases[i].len);
+
+ /* Use low body limits here so we can force over-sized object warnings */
+ tt_int_op(-1, OP_EQ, fetch_from_buf_http(buf, &h, 128,
+ &b, &bl, 128, 0));
+ tt_ptr_op(h, OP_EQ, NULL);
+ tt_ptr_op(b, OP_EQ, NULL);
+ tt_u64_op(bl, OP_EQ, 0);
+ expect_log_msg_containing(cases[i].expect);
+
+ buf_clear(buf);
+ tor_free(h);
+ tor_free(b);
+ mock_clean_saved_logs();
+ }
+ done:
+ tor_free(h);
+ tor_free(b);
+ buf_free(buf);
+ teardown_capture_of_logs();
+}
+
+struct testcase_t proto_http_tests[] = {
+ { "peek", test_proto_http_peek, 0, NULL, NULL },
+ { "valid", test_proto_http_valid, 0, NULL, NULL },
+ { "invalid", test_proto_http_invalid, 0, NULL, NULL },
+
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_proto_misc.c b/src/test/test_proto_misc.c
new file mode 100644
index 0000000000..263ca47447
--- /dev/null
+++ b/src/test/test_proto_misc.c
@@ -0,0 +1,263 @@
+/* Copyright (c) 2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file test_proto_misc.c
+ * \brief Test our smaller buffer-based protocol functions
+ */
+
+#include "or.h"
+#include "test.h"
+#include "buffers.h"
+#include "connection_or.h"
+#include "ext_orport.h"
+#include "proto_cell.h"
+#include "proto_control0.h"
+#include "proto_ext_or.h"
+
+static void
+test_proto_var_cell(void *arg)
+{
+ (void)arg;
+ char *mem_op_hex_tmp = NULL;
+ char tmp[1024];
+ buf_t *buf = NULL;
+ var_cell_t *cell = NULL;
+
+ buf = buf_new();
+ memset(tmp, 0xf0, sizeof(tmp));
+
+ /* Short little commands will make us say "no cell yet." */
+ tt_int_op(0, OP_EQ, fetch_var_cell_from_buf(buf, &cell, 4));
+ tt_ptr_op(cell, OP_EQ, NULL);
+ buf_add(buf, "\x01\x02\x02\0x2", 4);
+ tt_int_op(0, OP_EQ, fetch_var_cell_from_buf(buf, &cell, 4));
+ /* An incomplete fixed-length cell makes us say "no cell yet". */
+ buf_add(buf, "\x03", 1);
+ tt_int_op(0, OP_EQ, fetch_var_cell_from_buf(buf, &cell, 4));
+ /* A complete fixed length-cell makes us say "not a variable-length cell" */
+ buf_add(buf, tmp, 509);
+ tt_int_op(0, OP_EQ, fetch_var_cell_from_buf(buf, &cell, 4));
+ buf_clear(buf);
+
+ /* An incomplete versions cell is a variable-length cell that isn't ready
+ * yet. */
+ buf_add(buf,
+ "\x01\x02\x03\x04" /* circid */
+ "\x07" /* VERSIONS */
+ "\x00\x04" /* 4 bytes long */
+ "\x00" /* incomplete */, 8);
+ tt_int_op(1, OP_EQ, fetch_var_cell_from_buf(buf, &cell, 4));
+ tt_ptr_op(cell, OP_EQ, NULL);
+ /* Complete it, and it's a variable-length cell. Leave a byte on the end for
+ * fun. */
+ buf_add(buf, "\x09\x00\x25\ff", 4);
+ tt_int_op(1, OP_EQ, fetch_var_cell_from_buf(buf, &cell, 4));
+ tt_ptr_op(cell, OP_NE, NULL);
+ tt_int_op(cell->command, OP_EQ, CELL_VERSIONS);
+ tt_uint_op(cell->circ_id, OP_EQ, 0x01020304);
+ tt_int_op(cell->payload_len, OP_EQ, 4);
+ test_mem_op_hex(cell->payload, OP_EQ, "00090025");
+ var_cell_free(cell);
+ cell = NULL;
+ tt_int_op(buf_datalen(buf), OP_EQ, 1);
+ buf_clear(buf);
+
+ /* In link protocol 3 and earlier, circid fields were two bytes long. Let's
+ * ensure that gets handled correctly. */
+ buf_add(buf,
+ "\x23\x45\x81\x00\x06" /* command 81; 6 bytes long */
+ "coraje", 11);
+ tt_int_op(1, OP_EQ, fetch_var_cell_from_buf(buf, &cell, 3));
+ tt_ptr_op(cell, OP_NE, NULL);
+ tt_int_op(cell->command, OP_EQ, 129);
+ tt_uint_op(cell->circ_id, OP_EQ, 0x2345);
+ tt_int_op(cell->payload_len, OP_EQ, 6);
+ tt_mem_op(cell->payload, OP_EQ, "coraje", 6);
+ var_cell_free(cell);
+ cell = NULL;
+ tt_int_op(buf_datalen(buf), OP_EQ, 0);
+
+ /* In link protocol 2, only VERSIONS cells counted as variable-length */
+ buf_add(buf,
+ "\x23\x45\x81\x00\x06"
+ "coraje", 11); /* As above */
+ tt_int_op(0, OP_EQ, fetch_var_cell_from_buf(buf, &cell, 2));
+ buf_clear(buf);
+ buf_add(buf,
+ "\x23\x45\x07\x00\x06"
+ "futuro", 11);
+ tt_int_op(1, OP_EQ, fetch_var_cell_from_buf(buf, &cell, 2));
+ tt_ptr_op(cell, OP_NE, NULL);
+ tt_int_op(cell->command, OP_EQ, 7);
+ tt_uint_op(cell->circ_id, OP_EQ, 0x2345);
+ tt_int_op(cell->payload_len, OP_EQ, 6);
+ tt_mem_op(cell->payload, OP_EQ, "futuro", 6);
+ var_cell_free(cell);
+ cell = NULL;
+
+ done:
+ buf_free(buf);
+ var_cell_free(cell);
+ tor_free(mem_op_hex_tmp);
+}
+
+static void
+test_proto_control0(void *arg)
+{
+ (void)arg;
+ buf_t *buf = buf_new();
+
+ /* The only remaining function for the v0 control protocol is the function
+ that detects whether the user has stumbled across an old controller
+ that's using it. The format was:
+ u16 length;
+ u16 command;
+ u8 body[length];
+ */
+
+ /* Empty buffer -- nothing to do. */
+ tt_int_op(0, OP_EQ, peek_buf_has_control0_command(buf));
+ /* 3 chars in buf -- can't tell */
+ buf_add(buf, "AUT", 3);
+ tt_int_op(0, OP_EQ, peek_buf_has_control0_command(buf));
+ /* command in buf -- easy to tell */
+ buf_add(buf, "HENTICATE ", 10);
+ tt_int_op(0, OP_EQ, peek_buf_has_control0_command(buf));
+
+ /* Control0 command header in buf: make sure we detect it. */
+ buf_clear(buf);
+ buf_add(buf, "\x09\x05" "\x00\x05" "blah", 8);
+ tt_int_op(1, OP_EQ, peek_buf_has_control0_command(buf));
+
+ done:
+ buf_free(buf);
+}
+
+static void
+test_proto_ext_or_cmd(void *arg)
+{
+ ext_or_cmd_t *cmd = NULL;
+ buf_t *buf = buf_new();
+ char *tmp = NULL;
+ (void) arg;
+
+ /* Empty -- should give "not there. */
+ tt_int_op(0, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd));
+ tt_ptr_op(NULL, OP_EQ, cmd);
+
+ /* Three bytes: shouldn't work. */
+ buf_add(buf, "\x00\x20\x00", 3);
+ tt_int_op(0, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd));
+ tt_ptr_op(NULL, OP_EQ, cmd);
+ tt_int_op(3, OP_EQ, buf_datalen(buf));
+
+ /* 0020 0000: That's a nil command. It should work. */
+ buf_add(buf, "\x00", 1);
+ tt_int_op(1, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd));
+ tt_ptr_op(NULL, OP_NE, cmd);
+ tt_int_op(0x20, OP_EQ, cmd->cmd);
+ tt_int_op(0, OP_EQ, cmd->len);
+ tt_int_op(0, OP_EQ, buf_datalen(buf));
+ ext_or_cmd_free(cmd);
+ cmd = NULL;
+
+ /* Now try a length-6 command with one byte missing. */
+ buf_add(buf, "\x10\x21\x00\x06""abcde", 9);
+ tt_int_op(0, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd));
+ tt_ptr_op(NULL, OP_EQ, cmd);
+ buf_add(buf, "f", 1);
+ tt_int_op(1, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd));
+ tt_ptr_op(NULL, OP_NE, cmd);
+ tt_int_op(0x1021, OP_EQ, cmd->cmd);
+ tt_int_op(6, OP_EQ, cmd->len);
+ tt_mem_op("abcdef", OP_EQ, cmd->body, 6);
+ tt_int_op(0, OP_EQ, buf_datalen(buf));
+ ext_or_cmd_free(cmd);
+ cmd = NULL;
+
+ /* Now try a length-10 command with 4 extra bytes. */
+ buf_add(buf, "\xff\xff\x00\x0aloremipsum\x10\x00\xff\xff", 18);
+ tt_int_op(1, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd));
+ tt_ptr_op(NULL, OP_NE, cmd);
+ tt_int_op(0xffff, OP_EQ, cmd->cmd);
+ tt_int_op(10, OP_EQ, cmd->len);
+ tt_mem_op("loremipsum", OP_EQ, cmd->body, 10);
+ tt_int_op(4, OP_EQ, buf_datalen(buf));
+ ext_or_cmd_free(cmd);
+ cmd = NULL;
+
+ /* Finally, let's try a maximum-length command. We already have the header
+ * waiting. */
+ tt_int_op(0, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd));
+ tmp = tor_malloc_zero(65535);
+ buf_add(buf, tmp, 65535);
+ tt_int_op(1, OP_EQ, fetch_ext_or_command_from_buf(buf, &cmd));
+ tt_ptr_op(NULL, OP_NE, cmd);
+ tt_int_op(0x1000, OP_EQ, cmd->cmd);
+ tt_int_op(0xffff, OP_EQ, cmd->len);
+ tt_mem_op(tmp, OP_EQ, cmd->body, 65535);
+ tt_int_op(0, OP_EQ, buf_datalen(buf));
+ ext_or_cmd_free(cmd);
+ cmd = NULL;
+
+ done:
+ ext_or_cmd_free(cmd);
+ buf_free(buf);
+ tor_free(tmp);
+}
+
+static void
+test_proto_line(void *arg)
+{
+ (void)arg;
+ char tmp[60];
+ buf_t *buf = buf_new();
+#define S(str) str, sizeof(str)-1
+ const struct {
+ const char *input;
+ size_t input_len;
+ size_t line_len;
+ const char *output;
+ int returnval;
+ } cases[] = {
+ { S("Hello world"), 0, NULL, 0 },
+ { S("Hello world\n"), 12, "Hello world\n", 1 },
+ { S("Hello world\nMore"), 12, "Hello world\n", 1 },
+ { S("\n oh hello world\nMore"), 1, "\n", 1 },
+ { S("Hello worpd\n\nMore"), 12, "Hello worpd\n", 1 },
+ { S("------------------------------------------------------------\n"), 0,
+ NULL, -1 },
+ };
+ unsigned i;
+ for (i = 0; i < ARRAY_LENGTH(cases); ++i) {
+ buf_add(buf, cases[i].input, cases[i].input_len);
+ memset(tmp, 0xfe, sizeof(tmp));
+ size_t sz = sizeof(tmp);
+ int rv = buf_get_line(buf, tmp, &sz);
+ tt_int_op(rv, OP_EQ, cases[i].returnval);
+ if (rv == 1) {
+ tt_int_op(sz, OP_LT, sizeof(tmp));
+ tt_mem_op(cases[i].output, OP_EQ, tmp, sz+1);
+ tt_int_op(buf_datalen(buf), OP_EQ, cases[i].input_len - strlen(tmp));
+ tt_int_op(sz, OP_EQ, cases[i].line_len);
+ } else {
+ tt_int_op(buf_datalen(buf), OP_EQ, cases[i].input_len);
+ // tt_int_op(sz, OP_EQ, sizeof(tmp));
+ }
+ buf_clear(buf);
+ }
+
+ done:
+ buf_free(buf);
+}
+
+struct testcase_t proto_misc_tests[] = {
+ { "var_cell", test_proto_var_cell, 0, NULL, NULL },
+ { "control0", test_proto_control0, 0, NULL, NULL },
+ { "ext_or_cmd", test_proto_ext_or_cmd, TT_FORK, NULL, NULL },
+ { "line", test_proto_line, 0, NULL, NULL },
+
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_protover.c b/src/test/test_protover.c
index c4379a15e1..768332bb69 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
@@ -88,27 +88,27 @@ test_protover_parse_fail(void *arg)
/* random junk */
elts = parse_protocol_list("!!3@*");
- tt_assert(elts == NULL);
+ tt_ptr_op(elts, OP_EQ, NULL);
/* Missing equals sign in an entry */
elts = parse_protocol_list("Link=4 Haprauxymatyve Desc=9");
- tt_assert(elts == NULL);
+ tt_ptr_op(elts, OP_EQ, NULL);
/* Missing word. */
elts = parse_protocol_list("Link=4 =3 Desc=9");
- tt_assert(elts == NULL);
+ tt_ptr_op(elts, OP_EQ, NULL);
/* Broken numbers */
elts = parse_protocol_list("Link=fred");
- tt_assert(elts == NULL);
+ tt_ptr_op(elts, OP_EQ, NULL);
elts = parse_protocol_list("Link=1,fred");
- tt_assert(elts == NULL);
+ tt_ptr_op(elts, OP_EQ, NULL);
elts = parse_protocol_list("Link=1,fred,3");
- tt_assert(elts == NULL);
+ tt_ptr_op(elts, OP_EQ, NULL);
/* Broken range */
elts = parse_protocol_list("Link=1,9-8,3");
- tt_assert(elts == NULL);
+ tt_ptr_op(elts, OP_EQ, NULL);
done:
;
@@ -215,16 +215,16 @@ test_protover_all_supported(void *arg)
char *msg = NULL;
tt_assert(protover_all_supported(NULL, &msg));
- tt_assert(msg == NULL);
+ tt_ptr_op(msg, OP_EQ, NULL);
tt_assert(protover_all_supported("", &msg));
- tt_assert(msg == NULL);
+ tt_ptr_op(msg, OP_EQ, NULL);
// Some things that we do support
tt_assert(protover_all_supported("Link=3-4", &msg));
- tt_assert(msg == NULL);
+ tt_ptr_op(msg, OP_EQ, NULL);
tt_assert(protover_all_supported("Link=3-4 Desc=2", &msg));
- tt_assert(msg == NULL);
+ tt_ptr_op(msg, OP_EQ, NULL);
// Some things we don't support
tt_assert(! protover_all_supported("Wombat=9", &msg));
diff --git a/src/test/test_pt.c b/src/test/test_pt.c
index e5cdc5f3cd..07b6712ff9 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"
@@ -40,34 +40,34 @@ test_pt_parsing(void *arg)
/* incomplete cmethod */
strlcpy(line,"CMETHOD trebuchet",sizeof(line));
- tt_assert(parse_cmethod_line(line, mp) < 0);
+ tt_int_op(parse_cmethod_line(line, mp), OP_LT, 0);
reset_mp(mp);
/* wrong proxy type */
strlcpy(line,"CMETHOD trebuchet dog 127.0.0.1:1999",sizeof(line));
- tt_assert(parse_cmethod_line(line, mp) < 0);
+ tt_int_op(parse_cmethod_line(line, mp), OP_LT, 0);
reset_mp(mp);
/* wrong addrport */
strlcpy(line,"CMETHOD trebuchet socks4 abcd",sizeof(line));
- tt_assert(parse_cmethod_line(line, mp) < 0);
+ tt_int_op(parse_cmethod_line(line, mp), OP_LT, 0);
reset_mp(mp);
/* correct line */
strlcpy(line,"CMETHOD trebuchet socks5 127.0.0.1:1999",sizeof(line));
- tt_assert(parse_cmethod_line(line, mp) == 0);
- tt_assert(smartlist_len(mp->transports) == 1);
+ tt_int_op(parse_cmethod_line(line, mp), OP_EQ, 0);
+ tt_int_op(smartlist_len(mp->transports), OP_EQ, 1);
transport = smartlist_get(mp->transports, 0);
/* test registered address of transport */
tor_addr_parse(&test_addr, "127.0.0.1");
tt_assert(tor_addr_eq(&test_addr, &transport->addr));
/* test registered port of transport */
- tt_assert(transport->port == 1999);
+ tt_uint_op(transport->port, OP_EQ, 1999);
/* test registered SOCKS version of transport */
- tt_assert(transport->socks_version == PROXY_SOCKS5);
+ tt_int_op(transport->socks_version, OP_EQ, PROXY_SOCKS5);
/* test registered name of transport */
tt_str_op(transport->name,OP_EQ, "trebuchet");
@@ -75,26 +75,26 @@ test_pt_parsing(void *arg)
/* incomplete smethod */
strlcpy(line,"SMETHOD trebuchet",sizeof(line));
- tt_assert(parse_smethod_line(line, mp) < 0);
+ tt_int_op(parse_smethod_line(line, mp), OP_LT, 0);
reset_mp(mp);
/* wrong addr type */
strlcpy(line,"SMETHOD trebuchet abcd",sizeof(line));
- tt_assert(parse_smethod_line(line, mp) < 0);
+ tt_int_op(parse_smethod_line(line, mp), OP_LT, 0);
reset_mp(mp);
/* cowwect */
strlcpy(line,"SMETHOD trebuchy 127.0.0.2:2999",sizeof(line));
- tt_assert(parse_smethod_line(line, mp) == 0);
- tt_assert(smartlist_len(mp->transports) == 1);
+ tt_int_op(parse_smethod_line(line, mp), OP_EQ, 0);
+ tt_int_op(smartlist_len(mp->transports), OP_EQ, 1);
transport = smartlist_get(mp->transports, 0);
/* test registered address of transport */
tor_addr_parse(&test_addr, "127.0.0.2");
tt_assert(tor_addr_eq(&test_addr, &transport->addr));
/* test registered port of transport */
- tt_assert(transport->port == 2999);
+ tt_uint_op(transport->port, OP_EQ, 2999);
/* test registered name of transport */
tt_str_op(transport->name,OP_EQ, "trebuchy");
@@ -104,7 +104,7 @@ test_pt_parsing(void *arg)
strlcpy(line,"SMETHOD trebuchet 127.0.0.1:9999 "
"ARGS:counterweight=3,sling=snappy",
sizeof(line));
- tt_assert(parse_smethod_line(line, mp) == 0);
+ tt_int_op(parse_smethod_line(line, mp), OP_EQ, 0);
tt_int_op(1, OP_EQ, smartlist_len(mp->transports));
{
const transport_t *transport_ = smartlist_get(mp->transports, 0);
@@ -119,15 +119,15 @@ test_pt_parsing(void *arg)
/* unsupported version */
strlcpy(line,"VERSION 666",sizeof(line));
- tt_assert(parse_version(line, mp) < 0);
+ tt_int_op(parse_version(line, mp), OP_LT, 0);
/* incomplete VERSION */
strlcpy(line,"VERSION ",sizeof(line));
- tt_assert(parse_version(line, mp) < 0);
+ tt_int_op(parse_version(line, mp), OP_LT, 0);
/* correct VERSION */
strlcpy(line,"VERSION 1",sizeof(line));
- tt_assert(parse_version(line, mp) == 0);
+ tt_int_op(parse_version(line, mp), OP_EQ, 0);
done:
reset_mp(mp);
@@ -155,9 +155,9 @@ test_pt_get_transport_options(void *arg)
opt_str = get_transport_options_for_server_proxy(mp);
tt_ptr_op(opt_str, OP_EQ, NULL);
- smartlist_add(mp->transports_to_launch, tor_strdup("gruyere"));
- smartlist_add(mp->transports_to_launch, tor_strdup("roquefort"));
- smartlist_add(mp->transports_to_launch, tor_strdup("stnectaire"));
+ smartlist_add_strdup(mp->transports_to_launch, "gruyere");
+ smartlist_add_strdup(mp->transports_to_launch, "roquefort");
+ smartlist_add_strdup(mp->transports_to_launch, "stnectaire");
tt_assert(options);
@@ -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;
@@ -305,7 +305,7 @@ tor_get_lines_from_handle_replacement(STDIN_HANDLE *handle,
smartlist_add_asprintf(retval_sl, "SMETHOD mock%d 127.0.0.1:555%d",
times_called, times_called);
} else {
- smartlist_add(retval_sl, tor_strdup("SMETHODS DONE"));
+ smartlist_add_strdup(retval_sl, "SMETHODS DONE");
}
return retval_sl;
@@ -461,7 +461,7 @@ test_get_pt_proxy_uri(void *arg)
/* Test with no proxy. */
uri = get_pt_proxy_uri();
- tt_assert(uri == NULL);
+ tt_ptr_op(uri, OP_EQ, NULL);
/* Test with a SOCKS4 proxy. */
options->Socks4Proxy = tor_strdup("192.0.2.1:1080");
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..e3489627a0 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"
@@ -91,14 +91,14 @@ test_relay_append_cell_to_circuit_queue(void *arg)
append_cell_to_circuit_queue(TO_CIRCUIT(orcirc), nchan, cell,
CELL_DIRECTION_OUT, 0);
new_count = get_mock_scheduler_has_waiting_cells_count();
- tt_int_op(new_count, ==, old_count + 1);
+ tt_int_op(new_count, OP_EQ, old_count + 1);
/* Now try the reverse direction */
old_count = get_mock_scheduler_has_waiting_cells_count();
append_cell_to_circuit_queue(TO_CIRCUIT(orcirc), pchan, cell,
CELL_DIRECTION_IN, 0);
new_count = get_mock_scheduler_has_waiting_cells_count();
- tt_int_op(new_count, ==, old_count + 1);
+ tt_int_op(new_count, OP_EQ, old_count + 1);
UNMOCK(scheduler_channel_has_waiting_cells);
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 a5d3f351f8..9354dd0480 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"
@@ -10,7 +10,7 @@
#include "router.h"
#include "routerlist.h"
#include "config.h"
-#include <openssl/rsa.h>
+#include "hs_common.h"
#include "rend_test_helpers.h"
#include "log_test_helpers.h"
@@ -21,21 +21,6 @@ static const int TIME_IN_THE_PAST = -(REND_CACHE_MAX_AGE + \
REND_CACHE_MAX_SKEW + 60);
static const int TIME_IN_THE_FUTURE = REND_CACHE_MAX_SKEW + 60;
-static rend_data_t *
-mock_rend_data(const char *onion_address)
-{
- rend_data_t *rend_query = tor_malloc_zero(sizeof(rend_data_t));
-
- strlcpy(rend_query->onion_address, onion_address,
- sizeof(rend_query->onion_address));
- rend_query->auth_type = REND_NO_AUTH;
- rend_query->hsdirs_fp = smartlist_new();
- smartlist_add(rend_query->hsdirs_fp, tor_memdup("aaaaaaaaaaaaaaaaaaaaaaaa",
- DIGEST_LEN));
-
- return rend_query;
-}
-
static void
test_rend_cache_lookup_entry(void *data)
{
@@ -73,6 +58,7 @@ test_rend_cache_lookup_entry(void *data)
tt_int_op(ret, OP_EQ, 0);
ret = rend_cache_lookup_entry(service_id, 2, &entry);
+ tt_int_op(ret, OP_EQ, 0);
tt_assert(entry);
tt_int_op(entry->len, OP_EQ, strlen(desc_holder->desc_str));
tt_str_op(entry->desc, OP_EQ, desc_holder->desc_str);
@@ -144,7 +130,8 @@ test_rend_cache_store_v2_desc_as_client(void *data)
// Test mismatch between service ID and onion address
rend_cache_init();
- strncpy(mock_rend_query->onion_address, "abc", REND_SERVICE_ID_LEN_BASE32+1);
+ strncpy(TO_REND_DATA_V2(mock_rend_query)->onion_address, "abc",
+ REND_SERVICE_ID_LEN_BASE32+1);
ret = rend_cache_store_v2_desc_as_client(desc_holder->desc_str,
desc_id_base32,
mock_rend_query, NULL);
@@ -155,12 +142,16 @@ test_rend_cache_store_v2_desc_as_client(void *data)
// Test incorrect descriptor ID
rend_cache_init();
mock_rend_query = mock_rend_data(service_id);
- desc_id_base32[0]++;
+ char orig = desc_id_base32[0];
+ if (desc_id_base32[0] == 'a')
+ desc_id_base32[0] = 'b';
+ else
+ desc_id_base32[0] = 'a';
ret = rend_cache_store_v2_desc_as_client(desc_holder->desc_str,
desc_id_base32, mock_rend_query,
NULL);
tt_int_op(ret, OP_EQ, -1);
- desc_id_base32[0]--;
+ desc_id_base32[0] = orig;
rend_cache_free_all();
// Test too old descriptor
@@ -230,9 +221,9 @@ test_rend_cache_store_v2_desc_as_client(void *data)
generate_desc(RECENT_TIME, &desc_holder, &service_id, 3);
mock_rend_query = mock_rend_data(service_id);
- mock_rend_query->auth_type = REND_BASIC_AUTH;
+ TO_REND_DATA_V2(mock_rend_query)->auth_type = REND_BASIC_AUTH;
client_cookie[0] = 'A';
- memcpy(mock_rend_query->descriptor_cookie, client_cookie,
+ memcpy(TO_REND_DATA_V2(mock_rend_query)->descriptor_cookie, client_cookie,
REND_DESC_COOKIE_LEN);
base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_holder->desc_id,
DIGEST_LEN);
@@ -250,7 +241,7 @@ test_rend_cache_store_v2_desc_as_client(void *data)
generate_desc(RECENT_TIME, &desc_holder, &service_id, 3);
mock_rend_query = mock_rend_data(service_id);
- mock_rend_query->auth_type = REND_BASIC_AUTH;
+ TO_REND_DATA_V2(mock_rend_query)->auth_type = REND_BASIC_AUTH;
base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_holder->desc_id,
DIGEST_LEN);
ret = rend_cache_store_v2_desc_as_client(desc_holder->desc_str,
@@ -956,9 +947,9 @@ test_rend_cache_free_all(void *data)
rend_cache_free_all();
- tt_assert(!rend_cache);
- tt_assert(!rend_cache_v2_dir);
- tt_assert(!rend_cache_failure);
+ tt_ptr_op(rend_cache, OP_EQ, NULL);
+ tt_ptr_op(rend_cache_v2_dir, OP_EQ, NULL);
+ tt_ptr_op(rend_cache_failure, OP_EQ, NULL);
tt_assert(!rend_cache_total_allocation);
done:
@@ -1078,9 +1069,10 @@ static void
test_rend_cache_clean_v2_descs_as_dir(void *data)
{
rend_cache_entry_t *e;
- time_t now;
+ time_t now, cutoff;
rend_service_descriptor_t *desc;
now = time(NULL);
+ cutoff = now - (REND_CACHE_MAX_AGE + REND_CACHE_MAX_SKEW);
const char key[DIGEST_LEN] = "abcde";
(void)data;
@@ -1088,7 +1080,7 @@ test_rend_cache_clean_v2_descs_as_dir(void *data)
rend_cache_init();
// Test running with an empty cache
- rend_cache_clean_v2_descs_as_dir(now, 0);
+ rend_cache_clean_v2_descs_as_dir(cutoff);
tt_int_op(digestmap_size(rend_cache_v2_dir), OP_EQ, 0);
// Test with only one new entry
@@ -1100,38 +1092,15 @@ test_rend_cache_clean_v2_descs_as_dir(void *data)
e->parsed = desc;
digestmap_set(rend_cache_v2_dir, key, e);
- rend_cache_clean_v2_descs_as_dir(now, 0);
+ /* Set the cutoff to minus 10 seconds. */
+ rend_cache_clean_v2_descs_as_dir(cutoff - 10);
tt_int_op(digestmap_size(rend_cache_v2_dir), OP_EQ, 1);
// Test with one old entry
- desc->timestamp = now - (REND_CACHE_MAX_AGE + REND_CACHE_MAX_SKEW + 1000);
- rend_cache_clean_v2_descs_as_dir(now, 0);
- tt_int_op(digestmap_size(rend_cache_v2_dir), OP_EQ, 0);
-
- // Test with one entry that has an old last served
- e = tor_malloc_zero(sizeof(rend_cache_entry_t));
- e->last_served = now - (REND_CACHE_MAX_AGE + REND_CACHE_MAX_SKEW + 1000);
- desc = tor_malloc_zero(sizeof(rend_service_descriptor_t));
- desc->timestamp = now;
- desc->pk = pk_generate(0);
- e->parsed = desc;
- digestmap_set(rend_cache_v2_dir, key, e);
-
- rend_cache_clean_v2_descs_as_dir(now, 0);
+ desc->timestamp = cutoff - 1000;
+ rend_cache_clean_v2_descs_as_dir(cutoff);
tt_int_op(digestmap_size(rend_cache_v2_dir), OP_EQ, 0);
- // Test a run through asking for a large force_remove
- e = tor_malloc_zero(sizeof(rend_cache_entry_t));
- e->last_served = now;
- desc = tor_malloc_zero(sizeof(rend_service_descriptor_t));
- desc->timestamp = now;
- desc->pk = pk_generate(0);
- e->parsed = desc;
- digestmap_set(rend_cache_v2_dir, key, e);
-
- rend_cache_clean_v2_descs_as_dir(now, 20000);
- tt_int_op(digestmap_size(rend_cache_v2_dir), OP_EQ, 1);
-
done:
rend_cache_free_all();
}
diff --git a/src/test/test_replay.c b/src/test/test_replay.c
index e882bc6164..c379cafa7c 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
@@ -38,7 +38,7 @@ test_replaycache_alloc(void *arg)
(void)arg;
r = replaycache_new(600, 300);
- tt_assert(r != NULL);
+ tt_ptr_op(r, OP_NE, NULL);
done:
if (r) replaycache_free(r);
@@ -54,15 +54,15 @@ test_replaycache_badalloc(void *arg)
/* Negative horizon should fail */
(void)arg;
r = replaycache_new(-600, 300);
- tt_assert(r == NULL);
+ tt_ptr_op(r, OP_EQ, NULL);
/* Negative interval should get adjusted to zero */
r = replaycache_new(600, -300);
- tt_assert(r != NULL);
+ tt_ptr_op(r, OP_NE, NULL);
tt_int_op(r->scrub_interval,OP_EQ, 0);
replaycache_free(r);
/* Negative horizon and negative interval should still fail */
r = replaycache_new(-600, -300);
- tt_assert(r == NULL);
+ tt_ptr_op(r, OP_EQ, NULL);
done:
if (r) replaycache_free(r);
@@ -90,7 +90,7 @@ test_replaycache_miss(void *arg)
(void)arg;
r = replaycache_new(600, 300);
- tt_assert(r != NULL);
+ tt_ptr_op(r, OP_NE, NULL);
result =
replaycache_add_and_test_internal(1200, r, test_buffer,
@@ -123,7 +123,7 @@ test_replaycache_hit(void *arg)
(void)arg;
r = replaycache_new(600, 300);
- tt_assert(r != NULL);
+ tt_ptr_op(r, OP_NE, NULL);
result =
replaycache_add_and_test_internal(1200, r, test_buffer,
@@ -161,7 +161,7 @@ test_replaycache_age(void *arg)
(void)arg;
r = replaycache_new(600, 300);
- tt_assert(r != NULL);
+ tt_ptr_op(r, OP_NE, NULL);
result =
replaycache_add_and_test_internal(1200, r, test_buffer,
@@ -193,7 +193,7 @@ test_replaycache_elapsed(void *arg)
(void)arg;
r = replaycache_new(600, 300);
- tt_assert(r != NULL);
+ tt_ptr_op(r, OP_NE, NULL);
result =
replaycache_add_and_test_internal(1200, r, test_buffer,
@@ -220,7 +220,7 @@ test_replaycache_noexpire(void *arg)
(void)arg;
r = replaycache_new(0, 0);
- tt_assert(r != NULL);
+ tt_ptr_op(r, OP_NE, NULL);
result =
replaycache_add_and_test_internal(1200, r, test_buffer,
@@ -251,7 +251,7 @@ test_replaycache_scrub(void *arg)
(void)arg;
r = replaycache_new(600, 300);
- tt_assert(r != NULL);
+ tt_ptr_op(r, OP_NE, NULL);
/* Set up like in test_replaycache_hit() */
result =
@@ -294,7 +294,7 @@ test_replaycache_future(void *arg)
(void)arg;
r = replaycache_new(600, 300);
- tt_assert(r != NULL);
+ tt_ptr_op(r, OP_NE, NULL);
/* Set up like in test_replaycache_hit() */
result =
@@ -343,7 +343,7 @@ test_replaycache_realtime(void *arg)
/* Test the realtime as well as *_internal() entry points */
(void)arg;
r = replaycache_new(600, 300);
- tt_assert(r != NULL);
+ tt_ptr_op(r, OP_NE, NULL);
/* This should miss */
result =
diff --git a/src/test/test_router.c b/src/test/test_router.c
new file mode 100644
index 0000000000..4e96e24534
--- /dev/null
+++ b/src/test/test_router.c
@@ -0,0 +1,112 @@
+/* Copyright (c) 2017, The Tor Project, Inc. */
+/* Copyright (c) 2017, isis agora lovecruft */
+/* See LICENSE for licensing information */
+
+/**
+ * \file test_router.c
+ * \brief Unittests for code in src/or/router.c
+ **/
+
+#include "or.h"
+#include "config.h"
+#include "crypto_curve25519.h"
+#include "crypto_ed25519.h"
+#include "router.h"
+#include "routerlist.h"
+
+/* Test suite stuff */
+#include "test.h"
+
+NS_DECL(const routerinfo_t *, router_get_my_routerinfo, (void));
+
+static routerinfo_t* mock_routerinfo;
+
+static const routerinfo_t*
+NS(router_get_my_routerinfo)(void)
+{
+ crypto_pk_t* ident_key;
+ crypto_pk_t* tap_key;
+ time_t now;
+
+ if (!mock_routerinfo) {
+ /* Mock the published timestamp, otherwise router_dump_router_to_string()
+ * will poop its pants. */
+ time(&now);
+
+ /* We'll need keys, or router_dump_router_to_string() would return NULL. */
+ ident_key = pk_generate(0);
+ tap_key = pk_generate(0);
+
+ tor_assert(ident_key != NULL);
+ tor_assert(tap_key != NULL);
+
+ mock_routerinfo = tor_malloc_zero(sizeof(routerinfo_t));
+ mock_routerinfo->nickname = tor_strdup("ConlonNancarrow");
+ mock_routerinfo->addr = 123456789;
+ mock_routerinfo->or_port = 443;
+ mock_routerinfo->platform = tor_strdup("unittest");
+ mock_routerinfo->cache_info.published_on = now;
+ mock_routerinfo->identity_pkey = crypto_pk_dup_key(ident_key);
+ mock_routerinfo->onion_pkey = crypto_pk_dup_key(tap_key);
+ mock_routerinfo->bandwidthrate = 9001;
+ mock_routerinfo->bandwidthburst = 9002;
+ }
+
+ return mock_routerinfo;
+}
+
+/* If no distribution option was set, then check_bridge_distribution_setting()
+ * should have set it to "any". */
+static void
+test_router_dump_router_to_string_no_bridge_distribution_method(void *arg)
+{
+ const char* needle = "bridge-distribution-request any";
+ or_options_t* options = get_options_mutable();
+ routerinfo_t* router = NULL;
+ curve25519_keypair_t ntor_keypair;
+ ed25519_keypair_t signing_keypair;
+ char* desc = NULL;
+ char* found = NULL;
+ (void)arg;
+
+ NS_MOCK(router_get_my_routerinfo);
+
+ options->ORPort_set = 1;
+ options->BridgeRelay = 1;
+
+ /* Generate keys which router_dump_router_to_string() expects to exist. */
+ tt_int_op(0, ==, curve25519_keypair_generate(&ntor_keypair, 0));
+ tt_int_op(0, ==, ed25519_keypair_generate(&signing_keypair, 0));
+
+ /* Set up part of our routerinfo_t so that we don't trigger any other
+ * assertions in router_dump_router_to_string(). */
+ router = (routerinfo_t*)router_get_my_routerinfo();
+ tt_ptr_op(router, !=, NULL);
+
+ router->onion_curve25519_pkey = &ntor_keypair.pubkey;
+
+ /* Generate our server descriptor and ensure that the substring
+ * "bridge-distribution-request any" occurs somewhere within it. */
+ desc = router_dump_router_to_string(router,
+ router->identity_pkey,
+ router->onion_pkey,
+ &ntor_keypair,
+ &signing_keypair);
+ tt_ptr_op(desc, !=, NULL);
+ found = strstr(desc, needle);
+ tt_ptr_op(found, !=, NULL);
+
+ done:
+ NS_UNMOCK(router_get_my_routerinfo);
+
+ tor_free(desc);
+}
+
+#define ROUTER_TEST(name, flags) \
+ { #name, test_router_ ## name, flags, NULL, NULL }
+
+struct testcase_t router_tests[] = {
+ ROUTER_TEST(dump_router_to_string_no_bridge_distribution_method, TT_FORK),
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_routerkeys.c b/src/test/test_routerkeys.c
index 24b0da1c46..d8b72651a0 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"
@@ -92,8 +92,8 @@ test_routerkeys_ed_certs(void *args)
uint8_t *junk = NULL;
char *base64 = NULL;
- tt_int_op(0,==,ed25519_keypair_generate(&kp1, 0));
- tt_int_op(0,==,ed25519_keypair_generate(&kp2, 0));
+ tt_int_op(0,OP_EQ,ed25519_keypair_generate(&kp1, 0));
+ tt_int_op(0,OP_EQ,ed25519_keypair_generate(&kp2, 0));
for (int i = 0; i <= 1; ++i) {
uint32_t flags = i ? CERT_FLAG_INCLUDE_SIGNING_KEY : 0;
@@ -101,45 +101,45 @@ test_routerkeys_ed_certs(void *args)
cert[i] = tor_cert_create(&kp1, 5, &kp2.pubkey, now, 10000, flags);
tt_assert(cert[i]);
- tt_assert(cert[i]->sig_bad == 0);
- tt_assert(cert[i]->sig_ok == 1);
- tt_assert(cert[i]->cert_expired == 0);
- tt_assert(cert[i]->cert_valid == 1);
- tt_int_op(cert[i]->cert_type, ==, 5);
- tt_mem_op(cert[i]->signed_key.pubkey, ==, &kp2.pubkey.pubkey, 32);
- tt_mem_op(cert[i]->signing_key.pubkey, ==, &kp1.pubkey.pubkey, 32);
- tt_int_op(cert[i]->signing_key_included, ==, i);
+ tt_uint_op(cert[i]->sig_bad, OP_EQ, 0);
+ tt_uint_op(cert[i]->sig_ok, OP_EQ, 1);
+ tt_uint_op(cert[i]->cert_expired, OP_EQ, 0);
+ tt_uint_op(cert[i]->cert_valid, OP_EQ, 1);
+ tt_int_op(cert[i]->cert_type, OP_EQ, 5);
+ tt_mem_op(cert[i]->signed_key.pubkey, OP_EQ, &kp2.pubkey.pubkey, 32);
+ tt_mem_op(cert[i]->signing_key.pubkey, OP_EQ, &kp1.pubkey.pubkey, 32);
+ tt_int_op(cert[i]->signing_key_included, OP_EQ, i);
tt_assert(cert[i]->encoded);
- tt_int_op(cert[i]->encoded_len, ==, 104 + 36 * i);
- tt_int_op(cert[i]->encoded[0], ==, 1);
- tt_int_op(cert[i]->encoded[1], ==, 5);
+ tt_int_op(cert[i]->encoded_len, OP_EQ, 104 + 36 * i);
+ tt_int_op(cert[i]->encoded[0], OP_EQ, 1);
+ tt_int_op(cert[i]->encoded[1], OP_EQ, 5);
parsed_cert[i] = tor_cert_parse(cert[i]->encoded, cert[i]->encoded_len);
tt_assert(parsed_cert[i]);
- tt_int_op(cert[i]->encoded_len, ==, parsed_cert[i]->encoded_len);
- tt_mem_op(cert[i]->encoded, ==, parsed_cert[i]->encoded,
+ tt_int_op(cert[i]->encoded_len, OP_EQ, parsed_cert[i]->encoded_len);
+ tt_mem_op(cert[i]->encoded, OP_EQ, parsed_cert[i]->encoded,
cert[i]->encoded_len);
- tt_assert(parsed_cert[i]->sig_bad == 0);
- tt_assert(parsed_cert[i]->sig_ok == 0);
- tt_assert(parsed_cert[i]->cert_expired == 0);
- tt_assert(parsed_cert[i]->cert_valid == 0);
+ tt_uint_op(parsed_cert[i]->sig_bad, OP_EQ, 0);
+ tt_uint_op(parsed_cert[i]->sig_ok, OP_EQ, 0);
+ tt_uint_op(parsed_cert[i]->cert_expired, OP_EQ, 0);
+ tt_uint_op(parsed_cert[i]->cert_valid, OP_EQ, 0);
/* Expired */
tt_int_op(tor_cert_checksig(parsed_cert[i], &kp1.pubkey, now + 30000),
- <, 0);
- tt_assert(parsed_cert[i]->cert_expired == 1);
+ OP_LT, 0);
+ tt_uint_op(parsed_cert[i]->cert_expired, OP_EQ, 1);
parsed_cert[i]->cert_expired = 0;
/* Wrong key */
- tt_int_op(tor_cert_checksig(parsed_cert[i], &kp2.pubkey, now), <, 0);
- tt_assert(parsed_cert[i]->sig_bad== 1);
+ tt_int_op(tor_cert_checksig(parsed_cert[i], &kp2.pubkey, now), OP_LT, 0);
+ tt_uint_op(parsed_cert[i]->sig_bad, OP_EQ, 1);
parsed_cert[i]->sig_bad = 0;
/* Missing key */
int ok = tor_cert_checksig(parsed_cert[i], NULL, now);
- tt_int_op(ok < 0, ==, i == 0);
- tt_assert(parsed_cert[i]->sig_bad == 0);
+ tt_int_op(ok < 0, OP_EQ, i == 0);
+ tt_uint_op(parsed_cert[i]->sig_bad, OP_EQ, 0);
tt_assert(parsed_cert[i]->sig_ok == (i != 0));
tt_assert(parsed_cert[i]->cert_valid == (i != 0));
parsed_cert[i]->sig_bad = 0;
@@ -147,29 +147,29 @@ test_routerkeys_ed_certs(void *args)
parsed_cert[i]->cert_valid = 0;
/* Right key */
- tt_int_op(tor_cert_checksig(parsed_cert[i], &kp1.pubkey, now), ==, 0);
- tt_assert(parsed_cert[i]->sig_bad == 0);
- tt_assert(parsed_cert[i]->sig_ok == 1);
- tt_assert(parsed_cert[i]->cert_expired == 0);
- tt_assert(parsed_cert[i]->cert_valid == 1);
+ tt_int_op(tor_cert_checksig(parsed_cert[i], &kp1.pubkey, now), OP_EQ, 0);
+ tt_uint_op(parsed_cert[i]->sig_bad, OP_EQ, 0);
+ tt_uint_op(parsed_cert[i]->sig_ok, OP_EQ, 1);
+ tt_uint_op(parsed_cert[i]->cert_expired, OP_EQ, 0);
+ tt_uint_op(parsed_cert[i]->cert_valid, OP_EQ, 1);
}
/* Now try some junky certs. */
/* - Truncated */
nocert = tor_cert_parse(cert[0]->encoded, cert[0]->encoded_len-1);
- tt_ptr_op(NULL, ==, nocert);
+ tt_ptr_op(NULL, OP_EQ, nocert);
/* - First byte modified */
cert[0]->encoded[0] = 99;
nocert = tor_cert_parse(cert[0]->encoded, cert[0]->encoded_len);
- tt_ptr_op(NULL, ==, nocert);
+ tt_ptr_op(NULL, OP_EQ, nocert);
cert[0]->encoded[0] = 1;
/* - Extra byte at the end*/
junk = tor_malloc_zero(cert[0]->encoded_len + 1);
memcpy(junk, cert[0]->encoded, cert[0]->encoded_len);
nocert = tor_cert_parse(junk, cert[0]->encoded_len+1);
- tt_ptr_op(NULL, ==, nocert);
+ tt_ptr_op(NULL, OP_EQ, nocert);
/* - Multiple signing key instances */
tor_free(junk);
@@ -183,7 +183,7 @@ test_routerkeys_ed_certs(void *args)
junk[77] = 32; /* extlen */
junk[78] = 4; /* exttype */
nocert = tor_cert_parse(junk, 104 + 36 * 2);
- tt_ptr_op(NULL, ==, nocert);
+ tt_ptr_op(NULL, OP_EQ, nocert);
done:
tor_cert_free(cert[0]);
@@ -211,11 +211,12 @@ test_routerkeys_ed_key_create(void *arg)
kp2 = ed_key_new(kp1, INIT_ED_KEY_NEEDCERT, now, 3600, 4, &cert);
tt_assert(kp2);
tt_assert(cert);
- tt_mem_op(&cert->signed_key, ==, &kp2->pubkey, sizeof(ed25519_public_key_t));
+ tt_mem_op(&cert->signed_key, OP_EQ, &kp2->pubkey,
+ sizeof(ed25519_public_key_t));
tt_assert(! cert->signing_key_included);
- tt_int_op(cert->valid_until, >=, now);
- tt_int_op(cert->valid_until, <=, now+7200);
+ tt_int_op(cert->valid_until, OP_GE, now);
+ tt_int_op(cert->valid_until, OP_LE, now+7200);
/* Create a new key-including certificate signed by kp1 */
ed25519_keypair_free(kp2);
@@ -227,8 +228,10 @@ test_routerkeys_ed_key_create(void *arg)
tt_assert(kp2);
tt_assert(cert);
tt_assert(cert->signing_key_included);
- tt_mem_op(&cert->signed_key, ==, &kp2->pubkey, sizeof(ed25519_public_key_t));
- tt_mem_op(&cert->signing_key, ==, &kp1->pubkey,sizeof(ed25519_public_key_t));
+ tt_mem_op(&cert->signed_key, OP_EQ, &kp2->pubkey,
+ sizeof(ed25519_public_key_t));
+ tt_mem_op(&cert->signing_key, OP_EQ, &kp1->pubkey,
+ sizeof(ed25519_public_key_t));
done:
ed25519_keypair_free(kp1);
@@ -261,8 +264,8 @@ test_routerkeys_ed_key_init_basic(void *arg)
NULL, now, 0, 7, &cert);
tt_assert(kp1 != NULL);
tt_assert(cert == NULL);
- tt_int_op(stat(get_fname("test_ed_key_1_cert"), &st), <, 0);
- tt_int_op(stat(get_fname("test_ed_key_1_secret_key"), &st), ==, 0);
+ tt_int_op(stat(get_fname("test_ed_key_1_cert"), &st), OP_LT, 0);
+ tt_int_op(stat(get_fname("test_ed_key_1_secret_key"), &st), OP_EQ, 0);
/* Fail to load if we say we need a cert */
kp2 = ed_key_init_from_file(fname1, INIT_ED_KEY_NEEDCERT, LOG_INFO,
@@ -279,14 +282,14 @@ test_routerkeys_ed_key_init_basic(void *arg)
NULL, now, 0, 7, &cert);
tt_assert(kp2 != NULL);
tt_assert(cert == NULL);
- tt_mem_op(kp1, ==, kp2, sizeof(*kp1));
+ tt_mem_op(kp1, OP_EQ, kp2, sizeof(*kp1));
ed25519_keypair_free(kp2); kp2 = NULL;
kp2 = ed_key_init_from_file(fname1, 0, LOG_INFO,
NULL, now, 0, 7, &cert);
tt_assert(kp2 != NULL);
tt_assert(cert == NULL);
- tt_mem_op(kp1, ==, kp2, sizeof(*kp1));
+ tt_mem_op(kp1, OP_EQ, kp2, sizeof(*kp1));
ed25519_keypair_free(kp2); kp2 = NULL;
/* Now create a key with a cert. */
@@ -295,34 +298,34 @@ test_routerkeys_ed_key_init_basic(void *arg)
LOG_INFO, kp1, now, 7200, 7, &cert);
tt_assert(kp2 != NULL);
tt_assert(cert != NULL);
- tt_mem_op(kp1, !=, kp2, sizeof(*kp1));
- tt_int_op(stat(get_fname("test_ed_key_2_cert"), &st), ==, 0);
- tt_int_op(stat(get_fname("test_ed_key_2_secret_key"), &st), ==, 0);
+ tt_mem_op(kp1, OP_NE, kp2, sizeof(*kp1));
+ tt_int_op(stat(get_fname("test_ed_key_2_cert"), &st), OP_EQ, 0);
+ tt_int_op(stat(get_fname("test_ed_key_2_secret_key"), &st), OP_EQ, 0);
tt_assert(cert->cert_valid == 1);
- tt_mem_op(&cert->signed_key, ==, &kp2->pubkey, 32);
+ tt_mem_op(&cert->signed_key, OP_EQ, &kp2->pubkey, 32);
/* Now verify we can load the cert... */
kp3 = ed_key_init_from_file(fname2, (INIT_ED_KEY_CREATE|
INIT_ED_KEY_NEEDCERT),
LOG_INFO, kp1, now, 7200, 7, &cert2);
- tt_mem_op(kp2, ==, kp3, sizeof(*kp2));
- tt_mem_op(cert2->encoded, ==, cert->encoded, cert->encoded_len);
+ tt_mem_op(kp2, OP_EQ, kp3, sizeof(*kp2));
+ tt_mem_op(cert2->encoded, OP_EQ, cert->encoded, cert->encoded_len);
ed25519_keypair_free(kp3); kp3 = NULL;
tor_cert_free(cert2); cert2 = NULL;
/* ... even without create... */
kp3 = ed_key_init_from_file(fname2, INIT_ED_KEY_NEEDCERT,
LOG_INFO, kp1, now, 7200, 7, &cert2);
- tt_mem_op(kp2, ==, kp3, sizeof(*kp2));
- tt_mem_op(cert2->encoded, ==, cert->encoded, cert->encoded_len);
+ tt_mem_op(kp2, OP_EQ, kp3, sizeof(*kp2));
+ tt_mem_op(cert2->encoded, OP_EQ, cert->encoded, cert->encoded_len);
ed25519_keypair_free(kp3); kp3 = NULL;
tor_cert_free(cert2); cert2 = NULL;
/* ... but that we don't crash or anything if we say we don't want it. */
kp3 = ed_key_init_from_file(fname2, INIT_ED_KEY_NEEDCERT,
LOG_INFO, kp1, now, 7200, 7, NULL);
- tt_mem_op(kp2, ==, kp3, sizeof(*kp2));
+ tt_mem_op(kp2, OP_EQ, kp3, sizeof(*kp2));
ed25519_keypair_free(kp3); kp3 = NULL;
/* Fail if we're told the wrong signing key */
@@ -367,16 +370,16 @@ test_routerkeys_ed_key_init_split(void *arg)
LOG_INFO, NULL, now, 0, 7, &cert);
tt_assert(kp1 != NULL);
tt_assert(cert == NULL);
- tt_int_op(stat(get_fname("test_ed_key_3_cert"), &st), <, 0);
- tt_int_op(stat(get_fname("test_ed_key_3_secret_key"), &st), ==, 0);
- tt_int_op(stat(get_fname("test_ed_key_3_public_key"), &st), ==, 0);
+ tt_int_op(stat(get_fname("test_ed_key_3_cert"), &st), OP_LT, 0);
+ tt_int_op(stat(get_fname("test_ed_key_3_secret_key"), &st), OP_EQ, 0);
+ tt_int_op(stat(get_fname("test_ed_key_3_public_key"), &st), OP_EQ, 0);
/* Load it. */
kp2 = ed_key_init_from_file(fname1, flags|INIT_ED_KEY_CREATE,
LOG_INFO, NULL, now, 0, 7, &cert);
tt_assert(kp2 != NULL);
tt_assert(cert == NULL);
- tt_mem_op(kp1, ==, kp2, sizeof(*kp2));
+ tt_mem_op(kp1, OP_EQ, kp2, sizeof(*kp2));
ed25519_keypair_free(kp2); kp2 = NULL;
/* Okay, try killing the secret key and loading it. */
@@ -385,7 +388,7 @@ test_routerkeys_ed_key_init_split(void *arg)
LOG_INFO, NULL, now, 0, 7, &cert);
tt_assert(kp2 != NULL);
tt_assert(cert == NULL);
- tt_mem_op(&kp1->pubkey, ==, &kp2->pubkey, sizeof(kp2->pubkey));
+ tt_mem_op(&kp1->pubkey, OP_EQ, &kp2->pubkey, sizeof(kp2->pubkey));
tt_assert(tor_mem_is_zero((char*)kp2->seckey.seckey,
sizeof(kp2->seckey.seckey)));
ed25519_keypair_free(kp2); kp2 = NULL;
@@ -395,7 +398,7 @@ test_routerkeys_ed_key_init_split(void *arg)
LOG_INFO, NULL, now, 0, 7, &cert);
tt_assert(kp2 != NULL);
tt_assert(cert == NULL);
- tt_mem_op(&kp1->pubkey, ==, &kp2->pubkey, sizeof(kp2->pubkey));
+ tt_mem_op(&kp1->pubkey, OP_EQ, &kp2->pubkey, sizeof(kp2->pubkey));
tt_assert(tor_mem_is_zero((char*)kp2->seckey.seckey,
sizeof(kp2->seckey.seckey)));
ed25519_keypair_free(kp2); kp2 = NULL;
@@ -446,12 +449,12 @@ test_routerkeys_ed_keys_init_all(void *arg)
#else
mkdir(dir, 0700);
mkdir(get_fname("test_ed_keys_init_all/keys"), 0700);
-#endif
+#endif /* defined(_WIN32) */
options->DataDirectory = dir;
- tt_int_op(0, ==, load_ed_keys(options, now));
- tt_int_op(0, ==, generate_ed_link_cert(options, now));
+ tt_int_op(1, OP_EQ, load_ed_keys(options, now));
+ tt_int_op(0, OP_EQ, generate_ed_link_cert(options, now, 0));
tt_assert(get_master_identity_key());
tt_assert(get_master_identity_key());
tt_assert(get_master_signing_keypair());
@@ -465,21 +468,21 @@ test_routerkeys_ed_keys_init_all(void *arg)
link_cert = tor_cert_dup(get_current_link_cert_cert());
/* Call load_ed_keys again, but nothing has changed. */
- tt_int_op(0, ==, load_ed_keys(options, now));
- tt_int_op(0, ==, generate_ed_link_cert(options, now));
- tt_mem_op(&id, ==, get_master_identity_key(), sizeof(id));
- tt_mem_op(&sign, ==, get_master_signing_keypair(), sizeof(sign));
- tt_mem_op(&auth, ==, get_current_auth_keypair(), sizeof(auth));
+ tt_int_op(0, OP_EQ, load_ed_keys(options, now));
+ tt_int_op(0, OP_EQ, generate_ed_link_cert(options, now, 0));
+ tt_mem_op(&id, OP_EQ, get_master_identity_key(), sizeof(id));
+ tt_mem_op(&sign, OP_EQ, get_master_signing_keypair(), sizeof(sign));
+ tt_mem_op(&auth, OP_EQ, get_current_auth_keypair(), sizeof(auth));
tt_assert(tor_cert_eq(link_cert, get_current_link_cert_cert()));
/* Force a reload: we make new link/auth keys. */
routerkeys_free_all();
- tt_int_op(0, ==, load_ed_keys(options, now));
- tt_int_op(0, ==, generate_ed_link_cert(options, now));
- tt_mem_op(&id, ==, get_master_identity_key(), sizeof(id));
- tt_mem_op(&sign, ==, get_master_signing_keypair(), sizeof(sign));
+ tt_int_op(1, OP_EQ, load_ed_keys(options, now));
+ tt_int_op(0, OP_EQ, generate_ed_link_cert(options, now, 0));
+ tt_mem_op(&id, OP_EQ, get_master_identity_key(), sizeof(id));
+ tt_mem_op(&sign, OP_EQ, get_master_signing_keypair(), sizeof(sign));
tt_assert(tor_cert_eq(link_cert, get_current_link_cert_cert()));
- tt_mem_op(&auth, !=, get_current_auth_keypair(), sizeof(auth));
+ tt_mem_op(&auth, OP_NE, get_current_auth_keypair(), sizeof(auth));
tt_assert(get_master_signing_key_cert());
tt_assert(get_current_link_cert_cert());
tt_assert(get_current_auth_key_cert());
@@ -488,12 +491,12 @@ test_routerkeys_ed_keys_init_all(void *arg)
memcpy(&auth, get_current_auth_keypair(), sizeof(auth));
/* Force a link/auth-key regeneration by advancing time. */
- tt_int_op(0, ==, load_ed_keys(options, now+3*86400));
- tt_int_op(0, ==, generate_ed_link_cert(options, now+3*86400));
- tt_mem_op(&id, ==, get_master_identity_key(), sizeof(id));
- tt_mem_op(&sign, ==, get_master_signing_keypair(), sizeof(sign));
+ tt_int_op(0, OP_EQ, load_ed_keys(options, now+3*86400));
+ tt_int_op(0, OP_EQ, generate_ed_link_cert(options, now+3*86400, 0));
+ tt_mem_op(&id, OP_EQ, get_master_identity_key(), sizeof(id));
+ tt_mem_op(&sign, OP_EQ, get_master_signing_keypair(), sizeof(sign));
tt_assert(! tor_cert_eq(link_cert, get_current_link_cert_cert()));
- tt_mem_op(&auth, !=, get_current_auth_keypair(), sizeof(auth));
+ tt_mem_op(&auth, OP_NE, get_current_auth_keypair(), sizeof(auth));
tt_assert(get_master_signing_key_cert());
tt_assert(get_current_link_cert_cert());
tt_assert(get_current_auth_key_cert());
@@ -502,12 +505,12 @@ test_routerkeys_ed_keys_init_all(void *arg)
memcpy(&auth, get_current_auth_keypair(), sizeof(auth));
/* Force a signing-key regeneration by advancing time. */
- tt_int_op(0, ==, load_ed_keys(options, now+100*86400));
- tt_int_op(0, ==, generate_ed_link_cert(options, now+100*86400));
- tt_mem_op(&id, ==, get_master_identity_key(), sizeof(id));
- tt_mem_op(&sign, !=, get_master_signing_keypair(), sizeof(sign));
+ tt_int_op(1, OP_EQ, load_ed_keys(options, now+100*86400));
+ tt_int_op(0, OP_EQ, generate_ed_link_cert(options, now+100*86400, 0));
+ tt_mem_op(&id, OP_EQ, get_master_identity_key(), sizeof(id));
+ tt_mem_op(&sign, OP_NE, get_master_signing_keypair(), sizeof(sign));
tt_assert(! tor_cert_eq(link_cert, get_current_link_cert_cert()));
- tt_mem_op(&auth, !=, get_current_auth_keypair(), sizeof(auth));
+ tt_mem_op(&auth, OP_NE, get_current_auth_keypair(), sizeof(auth));
tt_assert(get_master_signing_key_cert());
tt_assert(get_current_link_cert_cert());
tt_assert(get_current_auth_key_cert());
@@ -520,12 +523,12 @@ test_routerkeys_ed_keys_init_all(void *arg)
routerkeys_free_all();
unlink(get_fname("test_ed_keys_init_all/keys/"
"ed25519_master_id_secret_key"));
- tt_int_op(0, ==, load_ed_keys(options, now));
- tt_int_op(0, ==, generate_ed_link_cert(options, now));
- tt_mem_op(&id, ==, get_master_identity_key(), sizeof(id));
- tt_mem_op(&sign, ==, get_master_signing_keypair(), sizeof(sign));
+ tt_int_op(1, OP_EQ, load_ed_keys(options, now));
+ tt_int_op(0, OP_EQ, generate_ed_link_cert(options, now, 0));
+ tt_mem_op(&id, OP_EQ, get_master_identity_key(), sizeof(id));
+ tt_mem_op(&sign, OP_EQ, get_master_signing_keypair(), sizeof(sign));
tt_assert(! tor_cert_eq(link_cert, get_current_link_cert_cert()));
- tt_mem_op(&auth, !=, get_current_auth_keypair(), sizeof(auth));
+ tt_mem_op(&auth, OP_NE, get_current_auth_keypair(), sizeof(auth));
tt_assert(get_master_signing_key_cert());
tt_assert(get_current_link_cert_cert());
tt_assert(get_current_auth_key_cert());
@@ -535,7 +538,7 @@ test_routerkeys_ed_keys_init_all(void *arg)
log_global_min_severity_ = LOG_ERR; /* Suppress warnings.
* XXX (better way to do this)? */
routerkeys_free_all();
- tt_int_op(-1, ==, load_ed_keys(options, now+200*86400));
+ tt_int_op(-1, OP_EQ, load_ed_keys(options, now+200*86400));
done:
tor_free(dir);
@@ -556,20 +559,20 @@ test_routerkeys_cross_certify_ntor(void *args)
time_t now = time(NULL);
int sign;
- tt_int_op(0, ==, ed25519_public_from_base64(&master_key,
+ tt_int_op(0, OP_EQ, ed25519_public_from_base64(&master_key,
"IamwritingthesetestsOnARainyAfternoonin2014"));
- tt_int_op(0, ==, curve25519_keypair_generate(&onion_keys, 0));
+ tt_int_op(0, OP_EQ, curve25519_keypair_generate(&onion_keys, 0));
cert = make_ntor_onion_key_crosscert(&onion_keys,
&master_key,
now, 10000,
&sign);
tt_assert(cert);
tt_assert(sign == 0 || sign == 1);
- tt_int_op(cert->cert_type, ==, CERT_TYPE_ONION_ID);
- tt_int_op(1, ==, ed25519_pubkey_eq(&cert->signed_key, &master_key));
- tt_int_op(0, ==, ed25519_public_key_from_curve25519_public_key(
+ tt_int_op(cert->cert_type, OP_EQ, CERT_TYPE_ONION_ID);
+ tt_int_op(1, OP_EQ, ed25519_pubkey_eq(&cert->signed_key, &master_key));
+ tt_int_op(0, OP_EQ, ed25519_public_key_from_curve25519_public_key(
&onion_check_key, &onion_keys.pubkey, sign));
- tt_int_op(0, ==, tor_cert_checksig(cert, &onion_check_key, now));
+ tt_int_op(0, OP_EQ, tor_cert_checksig(cert, &onion_check_key, now));
done:
tor_cert_free(cert);
@@ -587,7 +590,7 @@ test_routerkeys_cross_certify_tap(void *args)
char buf[128];
int n;
- tt_int_op(0, ==, ed25519_public_from_base64(&master_key,
+ tt_int_op(0, OP_EQ, ed25519_public_from_base64(&master_key,
"IAlreadyWroteTestsForRouterdescsUsingTheseX"));
cc = make_tap_onion_key_crosscert(onion_key,
@@ -598,14 +601,14 @@ test_routerkeys_cross_certify_tap(void *args)
n = crypto_pk_public_checksig(onion_key, buf, sizeof(buf),
(char*)cc, cc_len);
- tt_int_op(n,>,0);
- tt_int_op(n,==,52);
+ tt_int_op(n,OP_GT,0);
+ tt_int_op(n,OP_EQ,52);
crypto_pk_get_digest(id_key, digest);
- tt_mem_op(buf,==,digest,20);
- tt_mem_op(buf+20,==,master_key.pubkey,32);
+ tt_mem_op(buf,OP_EQ,digest,20);
+ tt_mem_op(buf+20,OP_EQ,master_key.pubkey,32);
- tt_int_op(0, ==, check_tap_onion_key_crosscert(cc, cc_len,
+ tt_int_op(0, OP_EQ, check_tap_onion_key_crosscert(cc, cc_len,
onion_key, &master_key, (uint8_t*)digest));
done:
@@ -614,6 +617,66 @@ test_routerkeys_cross_certify_tap(void *args)
crypto_pk_free(onion_key);
}
+static void
+test_routerkeys_rsa_ed_crosscert(void *arg)
+{
+ (void)arg;
+ ed25519_public_key_t ed;
+ crypto_pk_t *rsa = pk_generate(2);
+
+ uint8_t *cc = NULL;
+ ssize_t cc_len;
+ time_t expires_in = 1470846177;
+
+ tt_int_op(0, OP_EQ, ed25519_public_from_base64(&ed,
+ "ThisStringCanContainAnythingSoNoKeyHereNowX"));
+ cc_len = tor_make_rsa_ed25519_crosscert(&ed, rsa, expires_in, &cc);
+
+ tt_int_op(cc_len, OP_GT, 0);
+ tt_int_op(cc_len, OP_GT, 37); /* key, expires, siglen */
+ tt_mem_op(cc, OP_EQ, ed.pubkey, 32);
+ time_t expires_out = 3600 * ntohl(get_uint32(cc+32));
+ tt_int_op(expires_out, OP_GE, expires_in);
+ tt_int_op(expires_out, OP_LE, expires_in + 3600);
+
+ tt_int_op(cc_len, OP_EQ, 37 + get_uint8(cc+36));
+
+ tt_int_op(0, OP_EQ, rsa_ed25519_crosscert_check(cc, cc_len, rsa, &ed,
+ expires_in - 10));
+
+ /* Now try after it has expired */
+ tt_int_op(-4, OP_EQ, rsa_ed25519_crosscert_check(cc, cc_len, rsa, &ed,
+ expires_out + 1));
+
+ /* Truncated object */
+ tt_int_op(-2, OP_EQ, rsa_ed25519_crosscert_check(cc, cc_len - 2, rsa, &ed,
+ expires_in - 10));
+
+ /* Key not as expected */
+ cc[0] ^= 3;
+ tt_int_op(-3, OP_EQ, rsa_ed25519_crosscert_check(cc, cc_len, rsa, &ed,
+ expires_in - 10));
+ cc[0] ^= 3;
+
+ /* Bad signature */
+ cc[40] ^= 3;
+ tt_int_op(-5, OP_EQ, rsa_ed25519_crosscert_check(cc, cc_len, rsa, &ed,
+ expires_in - 10));
+ cc[40] ^= 3;
+
+ /* Signature of wrong data */
+ cc[0] ^= 3;
+ ed.pubkey[0] ^= 3;
+ tt_int_op(-6, OP_EQ, rsa_ed25519_crosscert_check(cc, cc_len, rsa, &ed,
+ expires_in - 10));
+ cc[0] ^= 3;
+ ed.pubkey[0] ^= 3;
+
+ done:
+ crypto_pk_free(rsa);
+ tor_free(cc);
+}
+
#define TEST(name, flags) \
{ #name , test_routerkeys_ ## name, (flags), NULL, NULL }
@@ -626,6 +689,7 @@ struct testcase_t routerkeys_tests[] = {
TEST(ed_keys_init_all, TT_FORK),
TEST(cross_certify_ntor, 0),
TEST(cross_certify_tap, 0),
+ TEST(rsa_ed_crosscert, 0),
END_OF_TESTCASES
};
diff --git a/src/test/test_routerlist.c b/src/test/test_routerlist.c
index 088bd257c3..3b0e943ce5 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"
@@ -15,6 +15,7 @@
#include "container.h"
#include "directory.h"
#include "dirvote.h"
+#include "entrynodes.h"
#include "microdesc.h"
#include "networkstatus.h"
#include "nodelist.h"
@@ -116,7 +117,7 @@ test_routerlist_launch_descriptor_downloads(void *arg)
MOCK(initiate_descriptor_downloads, mock_initiate_descriptor_downloads);
launch_descriptor_downloads(DIR_PURPOSE_FETCH_MICRODESC, downloadable,
NULL, now);
- tt_int_op(3, ==, count);
+ tt_int_op(3, OP_EQ, count);
UNMOCK(initiate_descriptor_downloads);
done:
@@ -147,24 +148,24 @@ construct_consensus(char **consensus_text_md)
&v1, &n_vrs, now, 1);
networkstatus_vote_free(vote);
tt_assert(v1);
- tt_int_op(n_vrs, ==, 4);
- tt_int_op(smartlist_len(v1->routerstatus_list), ==, 4);
+ tt_int_op(n_vrs, OP_EQ, 4);
+ tt_int_op(smartlist_len(v1->routerstatus_list), OP_EQ, 4);
dir_common_construct_vote_2(&vote, cert2, sign_skey_2,
&dir_common_gen_routerstatus_for_v3ns,
&v2, &n_vrs, now, 1);
networkstatus_vote_free(vote);
tt_assert(v2);
- tt_int_op(n_vrs, ==, 4);
- tt_int_op(smartlist_len(v2->routerstatus_list), ==, 4);
+ tt_int_op(n_vrs, OP_EQ, 4);
+ tt_int_op(smartlist_len(v2->routerstatus_list), OP_EQ, 4);
dir_common_construct_vote_3(&vote, cert3, sign_skey_3,
&dir_common_gen_routerstatus_for_v3ns,
&v3, &n_vrs, now, 1);
tt_assert(v3);
- tt_int_op(n_vrs, ==, 4);
- tt_int_op(smartlist_len(v3->routerstatus_list), ==, 4);
+ tt_int_op(n_vrs, OP_EQ, 4);
+ tt_int_op(smartlist_len(v3->routerstatus_list), OP_EQ, 4);
networkstatus_vote_free(vote);
votes = smartlist_new();
smartlist_add(votes, v1);
@@ -246,16 +247,16 @@ test_router_pick_directory_server_impl(void *arg)
/* No consensus available, fail early */
rs = router_pick_directory_server_impl(V3_DIRINFO, (const int) 0, NULL);
- tt_assert(rs == NULL);
+ tt_ptr_op(rs, OP_EQ, NULL);
construct_consensus(&consensus_text_md);
tt_assert(consensus_text_md);
con_md = networkstatus_parse_vote_from_string(consensus_text_md, NULL,
NS_TYPE_CONSENSUS);
tt_assert(con_md);
- tt_int_op(con_md->flavor,==, FLAV_MICRODESC);
+ tt_int_op(con_md->flavor,OP_EQ, FLAV_MICRODESC);
tt_assert(con_md->routerstatus_list);
- tt_int_op(smartlist_len(con_md->routerstatus_list), ==, 3);
+ tt_int_op(smartlist_len(con_md->routerstatus_list), OP_EQ, 3);
tt_assert(!networkstatus_set_current_consensus_from_ns(con_md,
"microdesc"));
@@ -286,7 +287,7 @@ test_router_pick_directory_server_impl(void *arg)
rs = router_pick_directory_server_impl(V3_DIRINFO, flags, NULL);
/* We should not fail now we have a consensus and routerstatus_list
* and nodelist are populated. */
- tt_assert(rs != NULL);
+ tt_ptr_op(rs, OP_NE, NULL);
/* Manipulate the nodes so we get the dir server we expect */
router1_id = tor_malloc(DIGEST_LEN);
@@ -305,7 +306,7 @@ test_router_pick_directory_server_impl(void *arg)
node_router1->is_running = 0;
node_router3->is_running = 0;
rs = router_pick_directory_server_impl(V3_DIRINFO, flags, NULL);
- tt_assert(rs != NULL);
+ tt_ptr_op(rs, OP_NE, NULL);
tt_assert(tor_memeq(rs->identity_digest, router2_id, DIGEST_LEN));
rs = NULL;
node_router1->is_running = 1;
@@ -318,7 +319,7 @@ test_router_pick_directory_server_impl(void *arg)
node_router1->rs->dir_port = 0;
node_router3->rs->dir_port = 0;
rs = router_pick_directory_server_impl(V3_DIRINFO, flags, NULL);
- tt_assert(rs != NULL);
+ tt_ptr_op(rs, OP_NE, NULL);
tt_assert(tor_memeq(rs->identity_digest, router2_id, DIGEST_LEN));
rs = NULL;
node_router1->rs->is_v2_dir = 1;
@@ -329,42 +330,18 @@ test_router_pick_directory_server_impl(void *arg)
node_router1->is_valid = 0;
node_router3->is_valid = 0;
rs = router_pick_directory_server_impl(V3_DIRINFO, flags, NULL);
- tt_assert(rs != NULL);
+ tt_ptr_op(rs, OP_NE, NULL);
tt_assert(tor_memeq(rs->identity_digest, router2_id, DIGEST_LEN));
rs = NULL;
node_router1->is_valid = 1;
node_router3->is_valid = 1;
- flags |= PDS_FOR_GUARD;
- node_router1->using_as_guard = 1;
- node_router2->using_as_guard = 1;
- node_router3->using_as_guard = 1;
- rs = router_pick_directory_server_impl(V3_DIRINFO, flags, NULL);
- tt_assert(rs == NULL);
- node_router1->using_as_guard = 0;
- rs = router_pick_directory_server_impl(V3_DIRINFO, flags, NULL);
- tt_assert(rs != NULL);
- tt_assert(tor_memeq(rs->identity_digest, router1_id, DIGEST_LEN));
- rs = NULL;
- node_router2->using_as_guard = 0;
- node_router3->using_as_guard = 0;
-
- /* One not valid, one guard. This should leave one remaining */
- node_router1->is_valid = 0;
- node_router2->using_as_guard = 1;
- rs = router_pick_directory_server_impl(V3_DIRINFO, flags, NULL);
- tt_assert(rs != NULL);
- tt_assert(tor_memeq(rs->identity_digest, router3_id, DIGEST_LEN));
- rs = NULL;
- node_router1->is_valid = 1;
- node_router2->using_as_guard = 0;
-
/* Manipulate overloaded */
node_router2->rs->last_dir_503_at = now;
node_router3->rs->last_dir_503_at = now;
rs = router_pick_directory_server_impl(V3_DIRINFO, flags, NULL);
- tt_assert(rs != NULL);
+ tt_ptr_op(rs, OP_NE, NULL);
tt_assert(tor_memeq(rs->identity_digest, router1_id, DIGEST_LEN));
node_router2->rs->last_dir_503_at = 0;
node_router3->rs->last_dir_503_at = 0;
@@ -381,13 +358,13 @@ test_router_pick_directory_server_impl(void *arg)
node_router2->rs->or_port = 443;
node_router3->rs->or_port = 442;
rs = router_pick_directory_server_impl(V3_DIRINFO, flags, NULL);
- tt_assert(rs != NULL);
+ tt_ptr_op(rs, OP_NE, NULL);
tt_assert(tor_memeq(rs->identity_digest, router3_id, DIGEST_LEN));
node_router1->rs->or_port = 442;
node_router2->rs->or_port = 443;
node_router3->rs->or_port = 444;
rs = router_pick_directory_server_impl(V3_DIRINFO, flags, NULL);
- tt_assert(rs != NULL);
+ tt_ptr_op(rs, OP_NE, NULL);
tt_assert(tor_memeq(rs->identity_digest, router1_id, DIGEST_LEN));
/* Fascist firewall and overloaded */
@@ -396,7 +373,7 @@ test_router_pick_directory_server_impl(void *arg)
node_router3->rs->or_port = 442;
node_router3->rs->last_dir_503_at = now;
rs = router_pick_directory_server_impl(V3_DIRINFO, flags, NULL);
- tt_assert(rs != NULL);
+ tt_ptr_op(rs, OP_NE, NULL);
tt_assert(tor_memeq(rs->identity_digest, router1_id, DIGEST_LEN));
node_router3->rs->last_dir_503_at = 0;
@@ -414,12 +391,13 @@ test_router_pick_directory_server_impl(void *arg)
node_router3->rs->dir_port = 81;
node_router1->rs->last_dir_503_at = now;
rs = router_pick_directory_server_impl(V3_DIRINFO, flags, NULL);
- tt_assert(rs != NULL);
+ tt_ptr_op(rs, OP_NE, NULL);
tt_assert(tor_memeq(rs->identity_digest, router1_id, DIGEST_LEN));
node_router1->rs->last_dir_503_at = 0;
done:
UNMOCK(usable_consensus_flavor);
+
if (router1_id)
tor_free(router1_id);
if (router2_id)
@@ -471,27 +449,27 @@ test_routerlist_router_is_already_dir_fetching(void *arg)
/* Test that we never get 1 from a NULL connection */
mocked_connection = NULL;
- tt_assert(router_is_already_dir_fetching(&test_ap, 1, 1) == 0);
- tt_assert(router_is_already_dir_fetching(&test_ap, 1, 0) == 0);
- tt_assert(router_is_already_dir_fetching(&test_ap, 0, 1) == 0);
+ tt_int_op(router_is_already_dir_fetching(&test_ap, 1, 1), OP_EQ, 0);
+ tt_int_op(router_is_already_dir_fetching(&test_ap, 1, 0), OP_EQ, 0);
+ tt_int_op(router_is_already_dir_fetching(&test_ap, 0, 1), OP_EQ, 0);
/* We always expect 0 in these cases */
- tt_assert(router_is_already_dir_fetching(&test_ap, 0, 0) == 0);
- tt_assert(router_is_already_dir_fetching(NULL, 1, 1) == 0);
- tt_assert(router_is_already_dir_fetching(&null_addr_ap, 1, 1) == 0);
- tt_assert(router_is_already_dir_fetching(&zero_port_ap, 1, 1) == 0);
+ tt_int_op(router_is_already_dir_fetching(&test_ap, 0, 0), OP_EQ, 0);
+ tt_int_op(router_is_already_dir_fetching(NULL, 1, 1), OP_EQ, 0);
+ tt_int_op(router_is_already_dir_fetching(&null_addr_ap, 1, 1), OP_EQ, 0);
+ tt_int_op(router_is_already_dir_fetching(&zero_port_ap, 1, 1), OP_EQ, 0);
/* Test that we get 1 with a connection in the appropriate circumstances */
mocked_connection = connection_new(CONN_TYPE_DIR, AF_INET);
- tt_assert(router_is_already_dir_fetching(&test_ap, 1, 1) == 1);
- tt_assert(router_is_already_dir_fetching(&test_ap, 1, 0) == 1);
- tt_assert(router_is_already_dir_fetching(&test_ap, 0, 1) == 1);
+ tt_int_op(router_is_already_dir_fetching(&test_ap, 1, 1), OP_EQ, 1);
+ tt_int_op(router_is_already_dir_fetching(&test_ap, 1, 0), OP_EQ, 1);
+ tt_int_op(router_is_already_dir_fetching(&test_ap, 0, 1), OP_EQ, 1);
/* Test that we get 0 even with a connection in the appropriate
* circumstances */
- tt_assert(router_is_already_dir_fetching(&test_ap, 0, 0) == 0);
- tt_assert(router_is_already_dir_fetching(NULL, 1, 1) == 0);
- tt_assert(router_is_already_dir_fetching(&null_addr_ap, 1, 1) == 0);
- tt_assert(router_is_already_dir_fetching(&zero_port_ap, 1, 1) == 0);
+ tt_int_op(router_is_already_dir_fetching(&test_ap, 0, 0), OP_EQ, 0);
+ tt_int_op(router_is_already_dir_fetching(NULL, 1, 1), OP_EQ, 0);
+ tt_int_op(router_is_already_dir_fetching(&null_addr_ap, 1, 1), OP_EQ, 0);
+ tt_int_op(router_is_already_dir_fetching(&zero_port_ap, 1, 1), OP_EQ, 0);
done:
/* If a connection is never set up, connection_free chokes on it. */
diff --git a/src/test/test_routerset.c b/src/test/test_routerset.c
index 1b526d430b..c9c69911da 100644
--- a/src/test/test_routerset.c
+++ b/src/test/test_routerset.c
@@ -623,7 +623,7 @@ NS(test_main)(void *arg)
(void)arg;
tgt = routerset_new();
- smartlist_add(src->list, tor_strdup("{xx}"));
+ smartlist_add_strdup(src->list, "{xx}");
routerset_union(tgt, src);
tt_int_op(smartlist_len(tgt->list), OP_NE, 0);
@@ -745,7 +745,7 @@ NS(test_main)(void *arg)
tt_int_op(is_empty, OP_NE, 0);
set = routerset_new();
- smartlist_add(set->list, tor_strdup("{xx}"));
+ smartlist_add_strdup(set->list, "{xx}");
is_empty = routerset_is_empty(set);
routerset_free(set);
set = NULL;
@@ -1602,7 +1602,7 @@ NS(test_main)(void *arg)
*/
NS_DECL(const node_t *, node_get_by_nickname,
- (const char *nickname, int warn_if_unused));
+ (const char *nickname, unsigned flags));
static const char *NS(mock_nickname);
static void
@@ -1616,7 +1616,7 @@ NS(test_main)(void *arg)
NS_MOCK(node_get_by_nickname);
NS(mock_nickname) = "foo";
- smartlist_add(set->list, tor_strdup(NS(mock_nickname)));
+ smartlist_add_strdup(set->list, NS(mock_nickname));
routerset_get_all_nodes(out, set, NULL, 0);
out_len = smartlist_len(out);
@@ -1632,11 +1632,11 @@ NS(test_main)(void *arg)
}
const node_t *
-NS(node_get_by_nickname)(const char *nickname, int warn_if_unused)
+NS(node_get_by_nickname)(const char *nickname, unsigned flags)
{
CALLED(node_get_by_nickname)++;
tt_str_op(nickname, OP_EQ, NS(mock_nickname));
- tt_int_op(warn_if_unused, OP_EQ, 1);
+ tt_uint_op(flags, OP_EQ, 0);
done:
return NULL;
@@ -1651,7 +1651,7 @@ NS(node_get_by_nickname)(const char *nickname, int warn_if_unused)
*/
NS_DECL(const node_t *, node_get_by_nickname,
- (const char *nickname, int warn_if_unused));
+ (const char *nickname, unsigned flags));
static const char *NS(mock_nickname);
static node_t NS(mock_node);
@@ -1667,7 +1667,7 @@ NS(test_main)(void *arg)
NS(mock_node).is_running = 0;
NS(mock_nickname) = "foo";
- smartlist_add(set->list, tor_strdup(NS(mock_nickname)));
+ smartlist_add_strdup(set->list, NS(mock_nickname));
routerset_get_all_nodes(out, set, NULL, 1);
out_len = smartlist_len(out);
@@ -1683,11 +1683,11 @@ NS(test_main)(void *arg)
}
const node_t *
-NS(node_get_by_nickname)(const char *nickname, int warn_if_unused)
+NS(node_get_by_nickname)(const char *nickname, unsigned flags)
{
CALLED(node_get_by_nickname)++;
tt_str_op(nickname, OP_EQ, NS(mock_nickname));
- tt_int_op(warn_if_unused, OP_EQ, 1);
+ tt_int_op(flags, OP_EQ, 0);
done:
return &NS(mock_node);
@@ -1701,7 +1701,7 @@ NS(node_get_by_nickname)(const char *nickname, int warn_if_unused)
*/
NS_DECL(const node_t *, node_get_by_nickname,
- (const char *nickname, int warn_if_unused));
+ (const char *nickname, unsigned flags));
static char *NS(mock_nickname);
static node_t NS(mock_node);
@@ -1735,11 +1735,11 @@ NS(test_main)(void *arg)
}
const node_t *
-NS(node_get_by_nickname)(const char *nickname, int warn_if_unused)
+NS(node_get_by_nickname)(const char *nickname, unsigned flags)
{
CALLED(node_get_by_nickname)++;
tt_str_op(nickname, OP_EQ, NS(mock_nickname));
- tt_int_op(warn_if_unused, OP_EQ, 1);
+ tt_int_op(flags, OP_EQ, 0);
done:
return &NS(mock_node);
@@ -1766,7 +1766,7 @@ NS(test_main)(void *arg)
NS_MOCK(nodelist_get_list);
- smartlist_add(set->country_names, tor_strdup("{xx}"));
+ smartlist_add_strdup(set->country_names, "{xx}");
NS(mock_smartlist) = smartlist_new();
routerset_get_all_nodes(out, set, NULL, 1);
@@ -1813,7 +1813,7 @@ NS(test_main)(void *arg)
NS_MOCK(nodelist_get_list);
- smartlist_add(set->country_names, tor_strdup("{xx}"));
+ smartlist_add_strdup(set->country_names, "{xx}");
NS(mock_smartlist) = smartlist_new();
NS(mock_node).is_running = 0;
smartlist_add(NS(mock_smartlist), (void *)&NS(mock_node));
@@ -1985,7 +1985,7 @@ NS(test_main)(void *arg)
int r;
(void)arg;
- smartlist_add(b->list, tor_strdup("{xx}"));
+ smartlist_add_strdup(b->list, "{xx}");
r = routerset_equal(a, b);
routerset_free(a);
routerset_free(b);
@@ -2010,9 +2010,9 @@ NS(test_main)(void *arg)
int r;
(void)arg;
- smartlist_add(a->list, tor_strdup("{aa}"));
- smartlist_add(b->list, tor_strdup("{b1}"));
- smartlist_add(b->list, tor_strdup("{b2}"));
+ smartlist_add_strdup(a->list, "{aa}");
+ smartlist_add_strdup(b->list, "{b1}");
+ smartlist_add_strdup(b->list, "{b2}");
r = routerset_equal(a, b);
routerset_free(a);
routerset_free(b);
@@ -2037,8 +2037,8 @@ NS(test_main)(void *arg)
int r;
(void)arg;
- smartlist_add(a->list, tor_strdup("foo"));
- smartlist_add(b->list, tor_strdup("bar"));
+ smartlist_add_strdup(a->list, "foo");
+ smartlist_add_strdup(b->list, "bar");
r = routerset_equal(a, b);
routerset_free(a);
routerset_free(b);
@@ -2063,8 +2063,8 @@ NS(test_main)(void *arg)
int r;
(void)arg;
- smartlist_add(a->list, tor_strdup("foo"));
- smartlist_add(b->list, tor_strdup("foo"));
+ smartlist_add_strdup(a->list, "foo");
+ smartlist_add_strdup(b->list, "foo");
r = routerset_equal(a, b);
routerset_free(a);
routerset_free(b);
diff --git a/src/test/test_rust.c b/src/test/test_rust.c
new file mode 100644
index 0000000000..6ad57d6fcb
--- /dev/null
+++ b/src/test/test_rust.c
@@ -0,0 +1,31 @@
+/* Copyright (c) 2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+#include "compat_rust.h"
+#include "test.h"
+#include "util.h"
+
+static void
+test_welcome_string(void *arg)
+{
+ (void)arg;
+ rust_str_t s = rust_welcome_string();
+ const char *c_str = rust_str_get(s);
+ tt_assert(c_str);
+ size_t len = strlen(c_str);
+#ifdef HAVE_RUST
+ tt_assert(len > 0);
+#else
+ tt_assert(len == 0);
+#endif
+
+ done:
+ rust_str_free(s);
+}
+
+struct testcase_t rust_tests[] = {
+ { "welcome_string", test_welcome_string, 0, NULL, NULL },
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_rust.sh b/src/test/test_rust.sh
new file mode 100755
index 0000000000..2761b612b5
--- /dev/null
+++ b/src/test/test_rust.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+# Test all Rust crates
+
+set -e
+
+export LSAN_OPTIONS=suppressions=${abs_top_srcdir:-../../..}/src/test/rust_supp.txt
+
+for cargo_toml_dir in "${abs_top_srcdir:-../../..}"/src/rust/*; do
+ if [ -e "${cargo_toml_dir}/Cargo.toml" ]; then
+ cd "${cargo_toml_dir}" && \
+ CARGO_TARGET_DIR="${abs_top_builddir:-../../..}/src/rust/target" \
+ "${CARGO:-cargo}" test ${CARGO_ONLINE-"--frozen"} \
+ ${EXTRA_CARGO_OPTIONS} \
+ --manifest-path "${cargo_toml_dir}/Cargo.toml" || exitcode=1
+ fi
+done
+
+exit $exitcode
diff --git a/src/test/test_scheduler.c b/src/test/test_scheduler.c
index 05ea8e86e8..724a6b56b2 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"
@@ -6,11 +6,16 @@
#include <math.h>
#include <event2/event.h>
+#define SCHEDULER_KIST_PRIVATE
#define TOR_CHANNEL_INTERNAL_
#define CHANNEL_PRIVATE_
#include "or.h"
+#include "config.h"
#include "compat_libevent.h"
#include "channel.h"
+#include "channeltls.h"
+#include "connection.h"
+#include "networkstatus.h"
#define SCHEDULER_PRIVATE_
#include "scheduler.h"
@@ -18,64 +23,100 @@
#include "test.h"
#include "fakechans.h"
-/* Event base for scheduelr tests */
-static struct event_base *mock_event_base = NULL;
-
-/* Statics controlling mocks */
-static circuitmux_t *mock_ccm_tgt_1 = NULL;
-static circuitmux_t *mock_ccm_tgt_2 = NULL;
+/* Shamelessly stolen from compat_libevent.c */
+#define V(major, minor, patch) \
+ (((major) << 24) | ((minor) << 16) | ((patch) << 8))
-static circuitmux_t *mock_cgp_tgt_1 = NULL;
-static circuitmux_policy_t *mock_cgp_val_1 = NULL;
-static circuitmux_t *mock_cgp_tgt_2 = NULL;
-static circuitmux_policy_t *mock_cgp_val_2 = NULL;
+/******************************************************************************
+ * Statistical info
+ *****************************************************************************/
static int scheduler_compare_channels_mock_ctr = 0;
static int scheduler_run_mock_ctr = 0;
-static void channel_flush_some_cells_mock_free_all(void);
-static void channel_flush_some_cells_mock_set(channel_t *chan,
- ssize_t num_cells);
+/******************************************************************************
+ * Utility functions and things we need to mock
+ *****************************************************************************/
+static or_options_t mocked_options;
+static const or_options_t *
+mock_get_options(void)
+{
+ return &mocked_options;
+}
-/* Setup for mock event stuff */
-static void mock_event_free_all(void);
-static void mock_event_init(void);
+static void
+cleanup_scheduler_options(void)
+{
+ if (mocked_options.SchedulerTypes_) {
+ SMARTLIST_FOREACH(mocked_options.SchedulerTypes_, int *, i, tor_free(i));
+ smartlist_free(mocked_options.SchedulerTypes_);
+ mocked_options.SchedulerTypes_ = NULL;
+ }
+}
+
+static void
+set_scheduler_options(int val)
+{
+ int *type;
-/* Mocks used by scheduler tests */
-static ssize_t channel_flush_some_cells_mock(channel_t *chan,
- ssize_t num_cells);
-static int circuitmux_compare_muxes_mock(circuitmux_t *cmux_1,
- circuitmux_t *cmux_2);
-static const circuitmux_policy_t * circuitmux_get_policy_mock(
- circuitmux_t *cmux);
-static int scheduler_compare_channels_mock(const void *c1_v,
- const void *c2_v);
-static void scheduler_run_noop_mock(void);
-static struct event_base * tor_libevent_get_base_mock(void);
-
-/* Scheduler test cases */
-static void test_scheduler_channel_states(void *arg);
-static void test_scheduler_compare_channels(void *arg);
-static void test_scheduler_initfree(void *arg);
-static void test_scheduler_loop(void *arg);
-static void test_scheduler_queue_heuristic(void *arg);
-
-/* Mock event init/free */
+ if (mocked_options.SchedulerTypes_ == NULL) {
+ mocked_options.SchedulerTypes_ = smartlist_new();
+ }
+ type = tor_malloc_zero(sizeof(int));
+ *type = val;
+ smartlist_add(mocked_options.SchedulerTypes_, type);
+}
-/* Shamelessly stolen from compat_libevent.c */
-#define V(major, minor, patch) \
- (((major) << 24) | ((minor) << 16) | ((patch) << 8))
+static void
+clear_options(void)
+{
+ cleanup_scheduler_options();
+ memset(&mocked_options, 0, sizeof(mocked_options));
+}
+
+static int32_t
+mock_vanilla_networkstatus_get_param(
+ const networkstatus_t *ns, const char *param_name, int32_t default_val,
+ int32_t min_val, int32_t max_val)
+{
+ (void)ns;
+ (void)default_val;
+ (void)min_val;
+ (void)max_val;
+ // only support KISTSchedRunInterval right now
+ tor_assert(strcmp(param_name, "KISTSchedRunInterval")==0);
+ return 0;
+}
+
+static int32_t
+mock_kist_networkstatus_get_param(
+ const networkstatus_t *ns, const char *param_name, int32_t default_val,
+ int32_t min_val, int32_t max_val)
+{
+ (void)ns;
+ (void)default_val;
+ (void)min_val;
+ (void)max_val;
+ // only support KISTSchedRunInterval right now
+ tor_assert(strcmp(param_name, "KISTSchedRunInterval")==0);
+ return 12;
+}
+/* Event base for scheduelr tests */
+static struct event_base *mock_event_base = NULL;
+/* Setup for mock event stuff */
+static void mock_event_free_all(void);
+static void mock_event_init(void);
static void
mock_event_free_all(void)
{
- tt_assert(mock_event_base != NULL);
+ tt_ptr_op(mock_event_base, OP_NE, NULL);
if (mock_event_base) {
event_base_free(mock_event_base);
mock_event_base = NULL;
}
- tt_ptr_op(mock_event_base, ==, NULL);
+ tt_ptr_op(mock_event_base, OP_EQ, NULL);
done:
return;
@@ -86,7 +127,7 @@ mock_event_init(void)
{
struct event_config *cfg = NULL;
- tt_ptr_op(mock_event_base, ==, NULL);
+ tt_ptr_op(mock_event_base, OP_EQ, NULL);
/*
* Really cut down from tor_libevent_initialize of
@@ -104,13 +145,90 @@ mock_event_init(void)
event_config_free(cfg);
}
- tt_assert(mock_event_base != NULL);
+ tt_ptr_op(mock_event_base, OP_NE, NULL);
done:
return;
}
-/* Mocks */
+static struct event_base *
+tor_libevent_get_base_mock(void)
+{
+ return mock_event_base;
+}
+
+static int
+scheduler_compare_channels_mock(const void *c1_v,
+ const void *c2_v)
+{
+ uintptr_t p1, p2;
+
+ p1 = (uintptr_t)(c1_v);
+ p2 = (uintptr_t)(c2_v);
+
+ ++scheduler_compare_channels_mock_ctr;
+
+ if (p1 == p2) return 0;
+ else if (p1 < p2) return 1;
+ else return -1;
+}
+
+static void
+scheduler_run_noop_mock(void)
+{
+ ++scheduler_run_mock_ctr;
+}
+
+static circuitmux_t *mock_ccm_tgt_1 = NULL;
+static circuitmux_t *mock_ccm_tgt_2 = NULL;
+static circuitmux_t *mock_cgp_tgt_1 = NULL;
+static circuitmux_policy_t *mock_cgp_val_1 = NULL;
+static circuitmux_t *mock_cgp_tgt_2 = NULL;
+static circuitmux_policy_t *mock_cgp_val_2 = NULL;
+
+static const circuitmux_policy_t *
+circuitmux_get_policy_mock(circuitmux_t *cmux)
+{
+ const circuitmux_policy_t *result = NULL;
+
+ tt_assert(cmux != NULL);
+ if (cmux) {
+ if (cmux == mock_cgp_tgt_1) result = mock_cgp_val_1;
+ else if (cmux == mock_cgp_tgt_2) result = mock_cgp_val_2;
+ else result = circuitmux_get_policy__real(cmux);
+ }
+
+ done:
+ return result;
+}
+
+static int
+circuitmux_compare_muxes_mock(circuitmux_t *cmux_1,
+ circuitmux_t *cmux_2)
+{
+ int result = 0;
+
+ tt_assert(cmux_1 != NULL);
+ tt_assert(cmux_2 != NULL);
+
+ if (cmux_1 != cmux_2) {
+ if (cmux_1 == mock_ccm_tgt_1 && cmux_2 == mock_ccm_tgt_2) result = -1;
+ else if (cmux_1 == mock_ccm_tgt_2 && cmux_2 == mock_ccm_tgt_1) {
+ result = 1;
+ } else {
+ if (cmux_1 == mock_ccm_tgt_1 || cmux_1 == mock_ccm_tgt_2) result = -1;
+ else if (cmux_2 == mock_ccm_tgt_1 || cmux_2 == mock_ccm_tgt_2) {
+ result = 1;
+ } else {
+ result = circuitmux_compare_muxes__real(cmux_1, cmux_2);
+ }
+ }
+ }
+ /* else result = 0 always */
+
+ done:
+ return result;
+}
typedef struct {
const channel_t *chan;
@@ -174,6 +292,67 @@ channel_flush_some_cells_mock_set(channel_t *chan, ssize_t num_cells)
}
}
+static int
+channel_more_to_flush_mock(channel_t *chan)
+{
+ tor_assert(chan);
+
+ flush_mock_channel_t *found_mock_ch = NULL;
+
+ /* Check if we have any queued */
+ if (! TOR_SIMPLEQ_EMPTY(&chan->incoming_queue))
+ return 1;
+
+ SMARTLIST_FOREACH_BEGIN(chans_for_flush_mock,
+ flush_mock_channel_t *,
+ flush_mock_ch) {
+ if (flush_mock_ch != NULL && flush_mock_ch->chan != NULL) {
+ if (flush_mock_ch->chan == chan) {
+ /* Found it */
+ found_mock_ch = flush_mock_ch;
+ break;
+ }
+ } else {
+ /* That shouldn't be there... */
+ SMARTLIST_DEL_CURRENT(chans_for_flush_mock, flush_mock_ch);
+ tor_free(flush_mock_ch);
+ }
+ } SMARTLIST_FOREACH_END(flush_mock_ch);
+
+ tor_assert(found_mock_ch);
+
+ /* Check if any circuits would like to queue some */
+ /* special for the mock: return the number of cells (instead of 1), or zero
+ * if nothing to flush */
+ return (found_mock_ch->cells > 0 ? (int)found_mock_ch->cells : 0 );
+}
+
+static void
+channel_write_to_kernel_mock(channel_t *chan)
+{
+ (void)chan;
+ //log_debug(LD_SCHED, "chan=%d writing to kernel",
+ // (int)chan->global_identifier);
+}
+
+static int
+channel_should_write_to_kernel_mock(outbuf_table_t *ot, channel_t *chan)
+{
+ (void)ot;
+ (void)chan;
+ return 1;
+ /* We could make this more complicated if we wanted. But I don't think doing
+ * so tests much of anything */
+ //static int called_counter = 0;
+ //if (++called_counter >= 3) {
+ // called_counter -= 3;
+ // log_debug(LD_SCHED, "chan=%d should write to kernel",
+ // (int)chan->global_identifier);
+ // return 1;
+ //}
+ //return 0;
+}
+
static ssize_t
channel_flush_some_cells_mock(channel_t *chan, ssize_t num_cells)
{
@@ -181,7 +360,7 @@ channel_flush_some_cells_mock(channel_t *chan, ssize_t num_cells)
char unlimited = 0;
flush_mock_channel_t *found = NULL;
- tt_assert(chan != NULL);
+ tt_ptr_op(chan, OP_NE, NULL);
if (chan) {
if (num_cells < 0) {
num_cells = 0;
@@ -215,11 +394,6 @@ channel_flush_some_cells_mock(channel_t *chan, ssize_t num_cells)
flushed += max;
found->cells -= max;
-
- if (found->cells <= 0) {
- smartlist_remove(chans_for_flush_mock, found);
- tor_free(found);
- }
}
}
}
@@ -228,90 +402,26 @@ channel_flush_some_cells_mock(channel_t *chan, ssize_t num_cells)
return flushed;
}
-static int
-circuitmux_compare_muxes_mock(circuitmux_t *cmux_1,
- circuitmux_t *cmux_2)
-{
- int result = 0;
-
- tt_assert(cmux_1 != NULL);
- tt_assert(cmux_2 != NULL);
-
- if (cmux_1 != cmux_2) {
- if (cmux_1 == mock_ccm_tgt_1 && cmux_2 == mock_ccm_tgt_2) result = -1;
- else if (cmux_1 == mock_ccm_tgt_2 && cmux_2 == mock_ccm_tgt_1) {
- result = 1;
- } else {
- if (cmux_1 == mock_ccm_tgt_1 || cmux_1 == mock_ccm_tgt_2) result = -1;
- else if (cmux_2 == mock_ccm_tgt_1 || cmux_2 == mock_ccm_tgt_2) {
- result = 1;
- } else {
- result = circuitmux_compare_muxes__real(cmux_1, cmux_2);
- }
- }
- }
- /* else result = 0 always */
-
- done:
- return result;
-}
-
-static const circuitmux_policy_t *
-circuitmux_get_policy_mock(circuitmux_t *cmux)
-{
- const circuitmux_policy_t *result = NULL;
-
- tt_assert(cmux != NULL);
- if (cmux) {
- if (cmux == mock_cgp_tgt_1) result = mock_cgp_val_1;
- else if (cmux == mock_cgp_tgt_2) result = mock_cgp_val_2;
- else result = circuitmux_get_policy__real(cmux);
- }
-
- done:
- return result;
-}
-
-static int
-scheduler_compare_channels_mock(const void *c1_v,
- const void *c2_v)
-{
- uintptr_t p1, p2;
-
- p1 = (uintptr_t)(c1_v);
- p2 = (uintptr_t)(c2_v);
-
- ++scheduler_compare_channels_mock_ctr;
-
- if (p1 == p2) return 0;
- else if (p1 < p2) return 1;
- else return -1;
-}
-
static void
-scheduler_run_noop_mock(void)
+update_socket_info_impl_mock(socket_table_ent_t *ent)
{
- ++scheduler_run_mock_ctr;
+ ent->cwnd = ent->unacked = ent->mss = ent->notsent = 0;
+ ent->limit = INT_MAX;
}
-static struct event_base *
-tor_libevent_get_base_mock(void)
-{
- return mock_event_base;
-}
-
-/* Test cases */
-
static void
-test_scheduler_channel_states(void *arg)
+perform_channel_state_tests(int KISTSchedRunInterval, int sched_type)
{
channel_t *ch1 = NULL, *ch2 = NULL;
int old_count;
- (void)arg;
+ /* setup options so we're sure about what sched we are running */
+ MOCK(get_options, mock_get_options);
+ clear_options();
+ mocked_options.KISTSchedRunInterval = KISTSchedRunInterval;
+ set_scheduler_options(sched_type);
/* Set up libevent and scheduler */
-
mock_event_init();
MOCK(tor_libevent_get_base, tor_libevent_get_base_mock);
scheduler_init();
@@ -324,9 +434,9 @@ test_scheduler_channel_states(void *arg)
* Disable scheduler_run so we can just check the state transitions
* without having to make everything it might call work too.
*/
- MOCK(scheduler_run, scheduler_run_noop_mock);
+ ((scheduler_t *) the_scheduler)->run = scheduler_run_noop_mock;
- tt_int_op(smartlist_len(channels_pending), ==, 0);
+ tt_int_op(smartlist_len(channels_pending), OP_EQ, 0);
/* Set up a fake channel */
ch1 = new_fake_channel();
@@ -341,7 +451,7 @@ test_scheduler_channel_states(void *arg)
tt_assert(ch1->registered);
/* It should start off in SCHED_CHAN_IDLE */
- tt_int_op(ch1->scheduler_state, ==, SCHED_CHAN_IDLE);
+ tt_int_op(ch1->scheduler_state, OP_EQ, SCHED_CHAN_IDLE);
/* Now get another one */
ch2 = new_fake_channel();
@@ -351,57 +461,69 @@ test_scheduler_channel_states(void *arg)
channel_register(ch2);
tt_assert(ch2->registered);
- /* Send it to SCHED_CHAN_WAITING_TO_WRITE */
+ /* Send ch1 to SCHED_CHAN_WAITING_TO_WRITE */
scheduler_channel_has_waiting_cells(ch1);
- tt_int_op(ch1->scheduler_state, ==, SCHED_CHAN_WAITING_TO_WRITE);
+ tt_int_op(ch1->scheduler_state, OP_EQ, SCHED_CHAN_WAITING_TO_WRITE);
/* This should send it to SCHED_CHAN_PENDING */
scheduler_channel_wants_writes(ch1);
- tt_int_op(ch1->scheduler_state, ==, SCHED_CHAN_PENDING);
- tt_int_op(smartlist_len(channels_pending), ==, 1);
+ tt_int_op(ch1->scheduler_state, OP_EQ, SCHED_CHAN_PENDING);
+ tt_int_op(smartlist_len(channels_pending), OP_EQ, 1);
/* Now send ch2 to SCHED_CHAN_WAITING_FOR_CELLS */
scheduler_channel_wants_writes(ch2);
- tt_int_op(ch2->scheduler_state, ==, SCHED_CHAN_WAITING_FOR_CELLS);
+ tt_int_op(ch2->scheduler_state, OP_EQ, SCHED_CHAN_WAITING_FOR_CELLS);
/* Drop ch2 back to idle */
scheduler_channel_doesnt_want_writes(ch2);
- tt_int_op(ch2->scheduler_state, ==, SCHED_CHAN_IDLE);
+ tt_int_op(ch2->scheduler_state, OP_EQ, SCHED_CHAN_IDLE);
/* ...and back to SCHED_CHAN_WAITING_FOR_CELLS */
scheduler_channel_wants_writes(ch2);
- tt_int_op(ch2->scheduler_state, ==, SCHED_CHAN_WAITING_FOR_CELLS);
+ tt_int_op(ch2->scheduler_state, OP_EQ, SCHED_CHAN_WAITING_FOR_CELLS);
/* ...and this should kick ch2 into SCHED_CHAN_PENDING */
scheduler_channel_has_waiting_cells(ch2);
- tt_int_op(ch2->scheduler_state, ==, SCHED_CHAN_PENDING);
- tt_int_op(smartlist_len(channels_pending), ==, 2);
+ tt_int_op(ch2->scheduler_state, OP_EQ, SCHED_CHAN_PENDING);
+ tt_int_op(smartlist_len(channels_pending), OP_EQ, 2);
/* This should send ch2 to SCHED_CHAN_WAITING_TO_WRITE */
scheduler_channel_doesnt_want_writes(ch2);
- tt_int_op(ch2->scheduler_state, ==, SCHED_CHAN_WAITING_TO_WRITE);
- tt_int_op(smartlist_len(channels_pending), ==, 1);
+ tt_int_op(ch2->scheduler_state, OP_EQ, SCHED_CHAN_WAITING_TO_WRITE);
+ tt_int_op(smartlist_len(channels_pending), OP_EQ, 1);
/* ...and back to SCHED_CHAN_PENDING */
scheduler_channel_wants_writes(ch2);
- tt_int_op(ch2->scheduler_state, ==, SCHED_CHAN_PENDING);
- tt_int_op(smartlist_len(channels_pending), ==, 2);
+ tt_int_op(ch2->scheduler_state, OP_EQ, SCHED_CHAN_PENDING);
+ tt_int_op(smartlist_len(channels_pending), OP_EQ, 2);
/* Now we exercise scheduler_touch_channel */
old_count = scheduler_compare_channels_mock_ctr;
scheduler_touch_channel(ch1);
tt_assert(scheduler_compare_channels_mock_ctr > old_count);
+ /* Release the ch2 and then do it another time to make sure it doesn't blow
+ * up and we are still in a quiescent state. */
+ scheduler_release_channel(ch2);
+ tt_int_op(ch2->scheduler_state, OP_EQ, SCHED_CHAN_IDLE);
+ tt_int_op(smartlist_len(channels_pending), OP_EQ, 1);
+ /* Cheat a bit so make the release more confused but also will tells us if
+ * the release did put the channel in the right state. */
+ ch2->scheduler_state = SCHED_CHAN_PENDING;
+ scheduler_release_channel(ch2);
+ tt_int_op(ch2->scheduler_state, OP_EQ, SCHED_CHAN_IDLE);
+ tt_int_op(smartlist_len(channels_pending), OP_EQ, 1);
+
/* Close */
channel_mark_for_close(ch1);
- tt_int_op(ch1->state, ==, CHANNEL_STATE_CLOSING);
+ tt_int_op(ch1->state, OP_EQ, CHANNEL_STATE_CLOSING);
channel_mark_for_close(ch2);
- tt_int_op(ch2->state, ==, CHANNEL_STATE_CLOSING);
+ tt_int_op(ch2->state, OP_EQ, CHANNEL_STATE_CLOSING);
channel_closed(ch1);
- tt_int_op(ch1->state, ==, CHANNEL_STATE_CLOSED);
+ tt_int_op(ch1->state, OP_EQ, CHANNEL_STATE_CLOSED);
ch1 = NULL;
channel_closed(ch2);
- tt_int_op(ch2->state, ==, CHANNEL_STATE_CLOSED);
+ tt_int_op(ch2->state, OP_EQ, CHANNEL_STATE_CLOSED);
ch2 = NULL;
/* Shut things down */
@@ -415,8 +537,9 @@ test_scheduler_channel_states(void *arg)
tor_free(ch2);
UNMOCK(scheduler_compare_channels);
- UNMOCK(scheduler_run);
UNMOCK(tor_libevent_get_base);
+ UNMOCK(get_options);
+ cleanup_scheduler_options();
return;
}
@@ -464,21 +587,21 @@ test_scheduler_compare_channels(void *arg)
/* Equal-channel case */
result = scheduler_compare_channels(&c1, &c1);
- tt_int_op(result, ==, 0);
+ tt_int_op(result, OP_EQ, 0);
/* Distinct channels, distinct policies */
result = scheduler_compare_channels(&c1, &c2);
- tt_int_op(result, ==, -1);
+ tt_int_op(result, OP_EQ, -1);
result = scheduler_compare_channels(&c2, &c1);
- tt_int_op(result, ==, 1);
+ tt_int_op(result, OP_EQ, 1);
/* Distinct channels, same policy */
tor_free(mock_cgp_val_2);
mock_cgp_val_2 = mock_cgp_val_1;
result = scheduler_compare_channels(&c1, &c2);
- tt_int_op(result, ==, -1);
+ tt_int_op(result, OP_EQ, -1);
result = scheduler_compare_channels(&c2, &c1);
- tt_int_op(result, ==, 1);
+ tt_int_op(result, OP_EQ, 1);
done:
@@ -502,40 +625,22 @@ test_scheduler_compare_channels(void *arg)
return;
}
-static void
-test_scheduler_initfree(void *arg)
-{
- (void)arg;
-
- tt_ptr_op(channels_pending, ==, NULL);
- tt_ptr_op(run_sched_ev, ==, NULL);
-
- mock_event_init();
- MOCK(tor_libevent_get_base, tor_libevent_get_base_mock);
-
- scheduler_init();
-
- tt_assert(channels_pending != NULL);
- tt_assert(run_sched_ev != NULL);
-
- scheduler_free_all();
-
- UNMOCK(tor_libevent_get_base);
- mock_event_free_all();
-
- tt_ptr_op(channels_pending, ==, NULL);
- tt_ptr_op(run_sched_ev, ==, NULL);
-
- done:
- return;
-}
+/******************************************************************************
+ * The actual tests!
+ *****************************************************************************/
static void
-test_scheduler_loop(void *arg)
+test_scheduler_loop_vanilla(void *arg)
{
+ (void)arg;
channel_t *ch1 = NULL, *ch2 = NULL;
+ void (*run_func_ptr)(void);
- (void)arg;
+ /* setup options so we're sure about what sched we are running */
+ MOCK(get_options, mock_get_options);
+ clear_options();
+ set_scheduler_options(SCHEDULER_VANILLA);
+ mocked_options.KISTSchedRunInterval = 0;
/* Set up libevent and scheduler */
@@ -551,12 +656,14 @@ test_scheduler_loop(void *arg)
* Disable scheduler_run so we can just check the state transitions
* without having to make everything it might call work too.
*/
- MOCK(scheduler_run, scheduler_run_noop_mock);
+ run_func_ptr = the_scheduler->run;
+ ((scheduler_t *) the_scheduler)->run = scheduler_run_noop_mock;
- tt_int_op(smartlist_len(channels_pending), ==, 0);
+ tt_int_op(smartlist_len(channels_pending), OP_EQ, 0);
/* Set up a fake channel */
ch1 = new_fake_channel();
+ ch1->magic = TLS_CHAN_MAGIC;
tt_assert(ch1);
/* Start it off in OPENING */
@@ -567,13 +674,14 @@ test_scheduler_loop(void *arg)
channel_register(ch1);
tt_assert(ch1->registered);
/* Finish opening it */
- channel_change_state(ch1, CHANNEL_STATE_OPEN);
+ channel_change_state_open(ch1);
/* It should start off in SCHED_CHAN_IDLE */
- tt_int_op(ch1->scheduler_state, ==, SCHED_CHAN_IDLE);
+ tt_int_op(ch1->scheduler_state, OP_EQ, SCHED_CHAN_IDLE);
/* Now get another one */
ch2 = new_fake_channel();
+ ch2->magic = TLS_CHAN_MAGIC;
tt_assert(ch2);
ch2->state = CHANNEL_STATE_OPENING;
ch2->cmux = circuitmux_alloc();
@@ -584,68 +692,62 @@ test_scheduler_loop(void *arg)
* zero and we'll get coverage of that exception case in scheduler_run()
*/
- tt_int_op(ch1->state, ==, CHANNEL_STATE_OPEN);
- tt_int_op(ch2->state, ==, CHANNEL_STATE_OPENING);
+ tt_int_op(ch1->state, OP_EQ, CHANNEL_STATE_OPEN);
+ tt_int_op(ch2->state, OP_EQ, CHANNEL_STATE_OPENING);
/* Send it to SCHED_CHAN_WAITING_TO_WRITE */
scheduler_channel_has_waiting_cells(ch1);
- tt_int_op(ch1->scheduler_state, ==, SCHED_CHAN_WAITING_TO_WRITE);
+ tt_int_op(ch1->scheduler_state, OP_EQ, SCHED_CHAN_WAITING_TO_WRITE);
/* This should send it to SCHED_CHAN_PENDING */
scheduler_channel_wants_writes(ch1);
- tt_int_op(ch1->scheduler_state, ==, SCHED_CHAN_PENDING);
- tt_int_op(smartlist_len(channels_pending), ==, 1);
+ tt_int_op(ch1->scheduler_state, OP_EQ, SCHED_CHAN_PENDING);
+ tt_int_op(smartlist_len(channels_pending), OP_EQ, 1);
/* Now send ch2 to SCHED_CHAN_WAITING_FOR_CELLS */
scheduler_channel_wants_writes(ch2);
- tt_int_op(ch2->scheduler_state, ==, SCHED_CHAN_WAITING_FOR_CELLS);
+ tt_int_op(ch2->scheduler_state, OP_EQ, SCHED_CHAN_WAITING_FOR_CELLS);
/* Drop ch2 back to idle */
scheduler_channel_doesnt_want_writes(ch2);
- tt_int_op(ch2->scheduler_state, ==, SCHED_CHAN_IDLE);
+ tt_int_op(ch2->scheduler_state, OP_EQ, SCHED_CHAN_IDLE);
/* ...and back to SCHED_CHAN_WAITING_FOR_CELLS */
scheduler_channel_wants_writes(ch2);
- tt_int_op(ch2->scheduler_state, ==, SCHED_CHAN_WAITING_FOR_CELLS);
+ tt_int_op(ch2->scheduler_state, OP_EQ, SCHED_CHAN_WAITING_FOR_CELLS);
/* ...and this should kick ch2 into SCHED_CHAN_PENDING */
scheduler_channel_has_waiting_cells(ch2);
- tt_int_op(ch2->scheduler_state, ==, SCHED_CHAN_PENDING);
- tt_int_op(smartlist_len(channels_pending), ==, 2);
+ tt_int_op(ch2->scheduler_state, OP_EQ, SCHED_CHAN_PENDING);
+ tt_int_op(smartlist_len(channels_pending), OP_EQ, 2);
/*
* Now we've got two pending channels and need to fire off
- * scheduler_run(); first, unmock it.
+ * the scheduler run() that we kept.
*/
-
- UNMOCK(scheduler_run);
-
- scheduler_run();
-
- /* Now re-mock it */
- MOCK(scheduler_run, scheduler_run_noop_mock);
+ run_func_ptr();
/*
* Assert that they're still in the states we left and aren't still
* pending
*/
- tt_int_op(ch1->state, ==, CHANNEL_STATE_OPEN);
- tt_int_op(ch2->state, ==, CHANNEL_STATE_OPENING);
+ tt_int_op(ch1->state, OP_EQ, CHANNEL_STATE_OPEN);
+ tt_int_op(ch2->state, OP_EQ, CHANNEL_STATE_OPENING);
tt_assert(ch1->scheduler_state != SCHED_CHAN_PENDING);
tt_assert(ch2->scheduler_state != SCHED_CHAN_PENDING);
- tt_int_op(smartlist_len(channels_pending), ==, 0);
+ tt_int_op(smartlist_len(channels_pending), OP_EQ, 0);
/* Now, finish opening ch2, and get both back to pending */
- channel_change_state(ch2, CHANNEL_STATE_OPEN);
+ channel_change_state_open(ch2);
scheduler_channel_wants_writes(ch1);
scheduler_channel_wants_writes(ch2);
scheduler_channel_has_waiting_cells(ch1);
scheduler_channel_has_waiting_cells(ch2);
- tt_int_op(ch1->state, ==, CHANNEL_STATE_OPEN);
- tt_int_op(ch2->state, ==, CHANNEL_STATE_OPEN);
- tt_int_op(ch1->scheduler_state, ==, SCHED_CHAN_PENDING);
- tt_int_op(ch2->scheduler_state, ==, SCHED_CHAN_PENDING);
- tt_int_op(smartlist_len(channels_pending), ==, 2);
+ tt_int_op(ch1->state, OP_EQ, CHANNEL_STATE_OPEN);
+ tt_int_op(ch2->state, OP_EQ, CHANNEL_STATE_OPEN);
+ tt_int_op(ch1->scheduler_state, OP_EQ, SCHED_CHAN_PENDING);
+ tt_int_op(ch2->scheduler_state, OP_EQ, SCHED_CHAN_PENDING);
+ tt_int_op(smartlist_len(channels_pending), OP_EQ, 2);
/* Now, set up the channel_flush_some_cells() mock */
MOCK(channel_flush_some_cells, channel_flush_some_cells_mock);
@@ -661,38 +763,33 @@ test_scheduler_loop(void *arg)
channel_flush_some_cells_mock_set(ch2, 48);
/*
- * And re-run the scheduler_run() loop with non-zero returns from
+ * And re-run the scheduler run() loop with non-zero returns from
* channel_flush_some_cells() this time.
*/
- UNMOCK(scheduler_run);
-
- scheduler_run();
-
- /* Now re-mock it */
- MOCK(scheduler_run, scheduler_run_noop_mock);
+ run_func_ptr();
/*
* ch1 should have gone to SCHED_CHAN_WAITING_FOR_CELLS, with 16 flushed
* and 32 writeable.
*/
- tt_int_op(ch1->scheduler_state, ==, SCHED_CHAN_WAITING_FOR_CELLS);
+ tt_int_op(ch1->scheduler_state, OP_EQ, SCHED_CHAN_WAITING_FOR_CELLS);
/*
* ...ch2 should also have gone to SCHED_CHAN_WAITING_FOR_CELLS, with
* channel_more_to_flush() returning false and channel_num_cells_writeable()
* > 0/
*/
- tt_int_op(ch2->scheduler_state, ==, SCHED_CHAN_WAITING_FOR_CELLS);
+ tt_int_op(ch2->scheduler_state, OP_EQ, SCHED_CHAN_WAITING_FOR_CELLS);
/* Close */
channel_mark_for_close(ch1);
- tt_int_op(ch1->state, ==, CHANNEL_STATE_CLOSING);
+ tt_int_op(ch1->state, OP_EQ, CHANNEL_STATE_CLOSING);
channel_mark_for_close(ch2);
- tt_int_op(ch2->state, ==, CHANNEL_STATE_CLOSING);
+ tt_int_op(ch2->state, OP_EQ, CHANNEL_STATE_CLOSING);
channel_closed(ch1);
- tt_int_op(ch1->state, ==, CHANNEL_STATE_CLOSED);
+ tt_int_op(ch1->state, OP_EQ, CHANNEL_STATE_CLOSED);
ch1 = NULL;
channel_closed(ch2);
- tt_int_op(ch2->state, ==, CHANNEL_STATE_CLOSED);
+ tt_int_op(ch2->state, OP_EQ, CHANNEL_STATE_CLOSED);
ch2 = NULL;
/* Shut things down */
@@ -704,55 +801,297 @@ test_scheduler_loop(void *arg)
done:
tor_free(ch1);
tor_free(ch2);
+ cleanup_scheduler_options();
UNMOCK(channel_flush_some_cells);
UNMOCK(scheduler_compare_channels);
- UNMOCK(scheduler_run);
UNMOCK(tor_libevent_get_base);
+ UNMOCK(get_options);
+}
+
+static void
+test_scheduler_loop_kist(void *arg)
+{
+ (void) arg;
+
+#ifndef HAVE_KIST_SUPPORT
+ return;
+#endif
+
+ channel_t *ch1 = new_fake_channel(), *ch2 = new_fake_channel();
+ channel_t *ch3 = new_fake_channel();
+
+ /* setup options so we're sure about what sched we are running */
+ MOCK(get_options, mock_get_options);
+ MOCK(channel_flush_some_cells, channel_flush_some_cells_mock);
+ MOCK(channel_more_to_flush, channel_more_to_flush_mock);
+ MOCK(channel_write_to_kernel, channel_write_to_kernel_mock);
+ MOCK(channel_should_write_to_kernel, channel_should_write_to_kernel_mock);
+ MOCK(update_socket_info_impl, update_socket_info_impl_mock);
+ clear_options();
+ mocked_options.KISTSchedRunInterval = 11;
+ set_scheduler_options(SCHEDULER_KIST);
+ scheduler_init();
+
+ tt_assert(ch1);
+ ch1->magic = TLS_CHAN_MAGIC;
+ ch1->state = CHANNEL_STATE_OPENING;
+ ch1->cmux = circuitmux_alloc();
+ channel_register(ch1);
+ tt_assert(ch1->registered);
+ channel_change_state_open(ch1);
+ scheduler_channel_has_waiting_cells(ch1);
+ scheduler_channel_wants_writes(ch1);
+ channel_flush_some_cells_mock_set(ch1, 5);
+
+ tt_assert(ch2);
+ ch2->magic = TLS_CHAN_MAGIC;
+ ch2->state = CHANNEL_STATE_OPENING;
+ ch2->cmux = circuitmux_alloc();
+ channel_register(ch2);
+ tt_assert(ch2->registered);
+ channel_change_state_open(ch2);
+ scheduler_channel_has_waiting_cells(ch2);
+ scheduler_channel_wants_writes(ch2);
+ channel_flush_some_cells_mock_set(ch2, 5);
+
+ the_scheduler->run();
+
+ scheduler_channel_has_waiting_cells(ch1);
+ channel_flush_some_cells_mock_set(ch1, 5);
+
+ the_scheduler->run();
+
+ scheduler_channel_has_waiting_cells(ch1);
+ channel_flush_some_cells_mock_set(ch1, 5);
+ scheduler_channel_has_waiting_cells(ch2);
+ channel_flush_some_cells_mock_set(ch2, 5);
+
+ the_scheduler->run();
+
+ channel_flush_some_cells_mock_free_all();
+
+ /* We'll try to run this closed channel threw the scheduler loop and make
+ * sure it ends up in the right state. */
+ tt_assert(ch3);
+ ch3->magic = TLS_CHAN_MAGIC;
+ ch3->state = CHANNEL_STATE_OPEN;
+ circuitmux_free(ch3->cmux);
+ ch3->cmux = circuitmux_alloc();
+ channel_register(ch3);
+ tt_assert(ch3->registered);
+
+ ch3->scheduler_state = SCHED_CHAN_WAITING_FOR_CELLS;
+ scheduler_channel_has_waiting_cells(ch3);
+ /* Should be in the pending list now waiting to be handled. */
+ tt_int_op(ch3->scheduler_state, OP_EQ, SCHED_CHAN_PENDING);
+ tt_int_op(smartlist_len(get_channels_pending()), OP_EQ, 1);
+ /* By running the scheduler on a closed channel, it should end up in the
+ * IDLE state and not in the pending channel list. */
+ ch3->state = CHANNEL_STATE_CLOSED;
+ the_scheduler->run();
+ tt_int_op(ch3->scheduler_state, OP_EQ, SCHED_CHAN_IDLE);
+ tt_int_op(smartlist_len(get_channels_pending()), OP_EQ, 0);
+
+ done:
+ /* Prep the channel so the free() function doesn't explode. */
+ ch1->state = ch2->state = ch3->state = CHANNEL_STATE_CLOSED;
+ ch1->registered = ch2->registered = ch3->registered = 0;
+ channel_free(ch1);
+ channel_free(ch2);
+ channel_free(ch3);
+ UNMOCK(update_socket_info_impl);
+ UNMOCK(channel_should_write_to_kernel);
+ UNMOCK(channel_write_to_kernel);
+ UNMOCK(channel_more_to_flush);
+ UNMOCK(channel_flush_some_cells);
+ UNMOCK(get_options);
+ scheduler_free_all();
+ return;
}
static void
-test_scheduler_queue_heuristic(void *arg)
+test_scheduler_channel_states(void *arg)
{
- time_t now = approx_time();
- uint64_t qh;
+ (void)arg;
+ perform_channel_state_tests(-1, SCHEDULER_VANILLA);
+ perform_channel_state_tests(11, SCHEDULER_KIST_LITE);
+#ifdef HAVE_KIST_SUPPORT
+ perform_channel_state_tests(11, SCHEDULER_KIST);
+#endif
+}
+static void
+test_scheduler_initfree(void *arg)
+{
(void)arg;
- queue_heuristic = 0;
- queue_heuristic_timestamp = 0;
+ tt_ptr_op(channels_pending, ==, NULL);
+ tt_ptr_op(run_sched_ev, ==, NULL);
- /* Not yet inited case */
- scheduler_update_queue_heuristic(now - 180);
- tt_u64_op(queue_heuristic, ==, 0);
- tt_int_op(queue_heuristic_timestamp, ==, now - 180);
+ mock_event_init();
+ MOCK(tor_libevent_get_base, tor_libevent_get_base_mock);
+ MOCK(get_options, mock_get_options);
+ set_scheduler_options(SCHEDULER_KIST);
+ set_scheduler_options(SCHEDULER_KIST_LITE);
+ set_scheduler_options(SCHEDULER_VANILLA);
+
+ scheduler_init();
- queue_heuristic = 1000000000L;
- queue_heuristic_timestamp = now - 120;
+ tt_ptr_op(channels_pending, !=, NULL);
+ tt_ptr_op(run_sched_ev, !=, NULL);
+ /* We have specified nothing in the torrc and there's no consensus so the
+ * KIST scheduler is what should be in use */
+ tt_ptr_op(the_scheduler, ==, get_kist_scheduler());
+ tt_int_op(sched_run_interval, ==, 10);
- scheduler_update_queue_heuristic(now - 119);
- tt_u64_op(queue_heuristic, ==, 500000000L);
- tt_int_op(queue_heuristic_timestamp, ==, now - 119);
+ scheduler_free_all();
- scheduler_update_queue_heuristic(now - 116);
- tt_u64_op(queue_heuristic, ==, 62500000L);
- tt_int_op(queue_heuristic_timestamp, ==, now - 116);
+ UNMOCK(tor_libevent_get_base);
+ mock_event_free_all();
- qh = scheduler_get_queue_heuristic();
- tt_u64_op(qh, ==, 0);
+ tt_ptr_op(channels_pending, ==, NULL);
+ tt_ptr_op(run_sched_ev, ==, NULL);
done:
+ UNMOCK(get_options);
+ cleanup_scheduler_options();
+ return;
+}
+
+static void
+test_scheduler_can_use_kist(void *arg)
+{
+ (void)arg;
+
+ int res_should, res_freq;
+ MOCK(get_options, mock_get_options);
+
+ /* Test force enabling of KIST */
+ clear_options();
+ mocked_options.KISTSchedRunInterval = 1234;
+ res_should = scheduler_can_use_kist();
+ res_freq = kist_scheduler_run_interval();
+#ifdef HAVE_KIST_SUPPORT
+ tt_int_op(res_should, ==, 1);
+#else /* HAVE_KIST_SUPPORT */
+ tt_int_op(res_should, ==, 0);
+#endif /* HAVE_KIST_SUPPORT */
+ tt_int_op(res_freq, ==, 1234);
+
+ /* Test defer to consensus, but no consensus available */
+ clear_options();
+ mocked_options.KISTSchedRunInterval = 0;
+ res_should = scheduler_can_use_kist();
+ res_freq = kist_scheduler_run_interval();
+#ifdef HAVE_KIST_SUPPORT
+ tt_int_op(res_should, ==, 1);
+#else /* HAVE_KIST_SUPPORT */
+ tt_int_op(res_should, ==, 0);
+#endif /* HAVE_KIST_SUPPORT */
+ tt_int_op(res_freq, ==, 10);
+
+ /* Test defer to consensus, and kist consensus available */
+ MOCK(networkstatus_get_param, mock_kist_networkstatus_get_param);
+ clear_options();
+ mocked_options.KISTSchedRunInterval = 0;
+ res_should = scheduler_can_use_kist();
+ res_freq = kist_scheduler_run_interval();
+#ifdef HAVE_KIST_SUPPORT
+ tt_int_op(res_should, ==, 1);
+#else /* HAVE_KIST_SUPPORT */
+ tt_int_op(res_should, ==, 0);
+#endif /* HAVE_KIST_SUPPORT */
+ tt_int_op(res_freq, ==, 12);
+ UNMOCK(networkstatus_get_param);
+
+ /* Test defer to consensus, and vanilla consensus available */
+ MOCK(networkstatus_get_param, mock_vanilla_networkstatus_get_param);
+ clear_options();
+ mocked_options.KISTSchedRunInterval = 0;
+ res_should = scheduler_can_use_kist();
+ res_freq = kist_scheduler_run_interval();
+ tt_int_op(res_should, ==, 0);
+ tt_int_op(res_freq, ==, 0);
+ UNMOCK(networkstatus_get_param);
+
+ done:
+ UNMOCK(get_options);
+ return;
+}
+
+static void
+test_scheduler_ns_changed(void *arg)
+{
+ (void) arg;
+
+ /*
+ * Currently no scheduler implementations use the old/new consensuses passed
+ * in scheduler_notify_networkstatus_changed, so it is okay to pass NULL.
+ *
+ * "But then what does test actually exercise???" It tests that
+ * scheduler_notify_networkstatus_changed fetches the correct value from the
+ * consensus, and then switches the scheduler if necessasry.
+ */
+
+ MOCK(get_options, mock_get_options);
+ clear_options();
+ set_scheduler_options(SCHEDULER_KIST);
+ set_scheduler_options(SCHEDULER_VANILLA);
+
+ tt_ptr_op(the_scheduler, ==, NULL);
+
+ /* Change from vanilla to kist via consensus */
+ the_scheduler = get_vanilla_scheduler();
+ MOCK(networkstatus_get_param, mock_kist_networkstatus_get_param);
+ scheduler_notify_networkstatus_changed();
+ UNMOCK(networkstatus_get_param);
+#ifdef HAVE_KIST_SUPPORT
+ tt_ptr_op(the_scheduler, ==, get_kist_scheduler());
+#else
+ tt_ptr_op(the_scheduler, ==, get_vanilla_scheduler());
+#endif
+
+ /* Change from kist to vanilla via consensus */
+ the_scheduler = get_kist_scheduler();
+ MOCK(networkstatus_get_param, mock_vanilla_networkstatus_get_param);
+ scheduler_notify_networkstatus_changed();
+ UNMOCK(networkstatus_get_param);
+ tt_ptr_op(the_scheduler, ==, get_vanilla_scheduler());
+
+ /* Doesn't change when using KIST */
+ the_scheduler = get_kist_scheduler();
+ MOCK(networkstatus_get_param, mock_kist_networkstatus_get_param);
+ scheduler_notify_networkstatus_changed();
+ UNMOCK(networkstatus_get_param);
+#ifdef HAVE_KIST_SUPPORT
+ tt_ptr_op(the_scheduler, ==, get_kist_scheduler());
+#else
+ tt_ptr_op(the_scheduler, ==, get_vanilla_scheduler());
+#endif
+
+ /* Doesn't change when using vanilla */
+ the_scheduler = get_vanilla_scheduler();
+ MOCK(networkstatus_get_param, mock_vanilla_networkstatus_get_param);
+ scheduler_notify_networkstatus_changed();
+ UNMOCK(networkstatus_get_param);
+ tt_ptr_op(the_scheduler, ==, get_vanilla_scheduler());
+
+ done:
+ UNMOCK(get_options);
+ cleanup_scheduler_options();
return;
}
struct testcase_t scheduler_tests[] = {
- { "channel_states", test_scheduler_channel_states, TT_FORK, NULL, NULL },
{ "compare_channels", test_scheduler_compare_channels,
TT_FORK, NULL, NULL },
+ { "channel_states", test_scheduler_channel_states, TT_FORK, NULL, NULL },
{ "initfree", test_scheduler_initfree, TT_FORK, NULL, NULL },
- { "loop", test_scheduler_loop, TT_FORK, NULL, NULL },
- { "queue_heuristic", test_scheduler_queue_heuristic,
- TT_FORK, NULL, NULL },
+ { "loop_vanilla", test_scheduler_loop_vanilla, TT_FORK, NULL, NULL },
+ { "loop_kist", test_scheduler_loop_kist, TT_FORK, NULL, NULL },
+ { "ns_changed", test_scheduler_ns_changed, TT_FORK, NULL, NULL},
+ { "should_use_kist", test_scheduler_can_use_kist, TT_FORK, NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_shared_random.c b/src/test/test_shared_random.c
index 6a8c1abaff..b7cd33715f 100644
--- a/src/test/test_shared_random.c
+++ b/src/test/test_shared_random.c
@@ -48,7 +48,7 @@ init_authority_state(void)
mock_cert = authority_cert_parse_from_string(AUTHORITY_CERT_1, NULL);
tt_assert(mock_cert);
options->AuthoritativeDir = 1;
- tt_int_op(0, ==, load_ed_keys(options, time(NULL)));
+ tt_int_op(load_ed_keys(options, time(NULL)), OP_GE, 0);
sr_state_init(0, 0);
/* It's possible a commit has been generated in our state depending on
* the phase we are currently in which uses "now" as the starting
@@ -73,65 +73,73 @@ test_get_sr_protocol_phase(void *arg)
{
retval = parse_rfc1123_time("Wed, 20 Apr 2015 23:59:00 UTC", &the_time);
- tt_int_op(retval, ==, 0);
+ tt_int_op(retval, OP_EQ, 0);
phase = get_sr_protocol_phase(the_time);
- tt_int_op(phase, ==, SR_PHASE_REVEAL);
+ tt_int_op(phase, OP_EQ, SR_PHASE_REVEAL);
}
{
retval = parse_rfc1123_time("Wed, 20 Apr 2015 00:00:00 UTC", &the_time);
- tt_int_op(retval, ==, 0);
+ tt_int_op(retval, OP_EQ, 0);
phase = get_sr_protocol_phase(the_time);
- tt_int_op(phase, ==, SR_PHASE_COMMIT);
+ tt_int_op(phase, OP_EQ, SR_PHASE_COMMIT);
}
{
retval = parse_rfc1123_time("Wed, 20 Apr 2015 00:00:01 UTC", &the_time);
- tt_int_op(retval, ==, 0);
+ tt_int_op(retval, OP_EQ, 0);
phase = get_sr_protocol_phase(the_time);
- tt_int_op(phase, ==, SR_PHASE_COMMIT);
+ tt_int_op(phase, OP_EQ, SR_PHASE_COMMIT);
}
{
retval = parse_rfc1123_time("Wed, 20 Apr 2015 11:59:00 UTC", &the_time);
- tt_int_op(retval, ==, 0);
+ tt_int_op(retval, OP_EQ, 0);
phase = get_sr_protocol_phase(the_time);
- tt_int_op(phase, ==, SR_PHASE_COMMIT);
+ tt_int_op(phase, OP_EQ, SR_PHASE_COMMIT);
}
{
retval = parse_rfc1123_time("Wed, 20 Apr 2015 12:00:00 UTC", &the_time);
- tt_int_op(retval, ==, 0);
+ tt_int_op(retval, OP_EQ, 0);
phase = get_sr_protocol_phase(the_time);
- tt_int_op(phase, ==, SR_PHASE_REVEAL);
+ tt_int_op(phase, OP_EQ, SR_PHASE_REVEAL);
}
{
retval = parse_rfc1123_time("Wed, 20 Apr 2015 12:00:01 UTC", &the_time);
- tt_int_op(retval, ==, 0);
+ tt_int_op(retval, OP_EQ, 0);
phase = get_sr_protocol_phase(the_time);
- tt_int_op(phase, ==, SR_PHASE_REVEAL);
+ tt_int_op(phase, OP_EQ, SR_PHASE_REVEAL);
}
{
retval = parse_rfc1123_time("Wed, 20 Apr 2015 13:00:00 UTC", &the_time);
- tt_int_op(retval, ==, 0);
+ tt_int_op(retval, OP_EQ, 0);
phase = get_sr_protocol_phase(the_time);
- tt_int_op(phase, ==, SR_PHASE_REVEAL);
+ tt_int_op(phase, OP_EQ, SR_PHASE_REVEAL);
}
done:
;
}
-static networkstatus_t *mock_consensus = NULL;
+static networkstatus_t mock_consensus;
+
+/* Mock function to immediately return our local 'mock_consensus'. */
+static networkstatus_t *
+mock_networkstatus_get_live_consensus(time_t now)
+{
+ (void) now;
+ return &mock_consensus;
+}
static void
test_get_state_valid_until_time(void *arg)
@@ -143,11 +151,23 @@ test_get_state_valid_until_time(void *arg)
(void) arg;
+ MOCK(networkstatus_get_live_consensus,
+ mock_networkstatus_get_live_consensus);
+
+ retval = parse_rfc1123_time("Mon, 20 Apr 2015 01:00:00 UTC",
+ &mock_consensus.fresh_until);
+ tt_int_op(retval, OP_EQ, 0);
+
+ retval = parse_rfc1123_time("Mon, 20 Apr 2015 00:00:00 UTC",
+ &mock_consensus.valid_after);
+ tt_int_op(retval, OP_EQ, 0);
+
{
/* Get the valid until time if called at 00:00:01 */
retval = parse_rfc1123_time("Mon, 20 Apr 2015 00:00:01 UTC",
&current_time);
- tt_int_op(retval, ==, 0);
+ tt_int_op(retval, OP_EQ, 0);
+ dirvote_recalculate_timing(get_options(), current_time);
valid_until_time = get_state_valid_until_time(current_time);
/* Compare it with the correct result */
@@ -158,7 +178,8 @@ test_get_state_valid_until_time(void *arg)
{
retval = parse_rfc1123_time("Mon, 20 Apr 2015 19:22:00 UTC",
&current_time);
- tt_int_op(retval, ==, 0);
+ tt_int_op(retval, OP_EQ, 0);
+ dirvote_recalculate_timing(get_options(), current_time);
valid_until_time = get_state_valid_until_time(current_time);
format_iso_time(tbuf, valid_until_time);
@@ -168,7 +189,8 @@ test_get_state_valid_until_time(void *arg)
{
retval = parse_rfc1123_time("Mon, 20 Apr 2015 23:59:00 UTC",
&current_time);
- tt_int_op(retval, ==, 0);
+ tt_int_op(retval, OP_EQ, 0);
+ dirvote_recalculate_timing(get_options(), current_time);
valid_until_time = get_state_valid_until_time(current_time);
format_iso_time(tbuf, valid_until_time);
@@ -178,7 +200,8 @@ test_get_state_valid_until_time(void *arg)
{
retval = parse_rfc1123_time("Mon, 20 Apr 2015 00:00:00 UTC",
&current_time);
- tt_int_op(retval, ==, 0);
+ tt_int_op(retval, OP_EQ, 0);
+ dirvote_recalculate_timing(get_options(), current_time);
valid_until_time = get_state_valid_until_time(current_time);
format_iso_time(tbuf, valid_until_time);
@@ -186,82 +209,148 @@ test_get_state_valid_until_time(void *arg)
}
done:
- ;
-}
-
-/* Mock function to immediately return our local 'mock_consensus'. */
-static networkstatus_t *
-mock_networkstatus_get_live_consensus(time_t now)
-{
- (void) now;
- return mock_consensus;
+ UNMOCK(networkstatus_get_live_consensus);
}
-/** Test the get_next_valid_after_time() function. */
+/** Test the function that calculates the start time of the current SRV
+ * protocol run. */
static void
-test_get_next_valid_after_time(void *arg)
+test_get_start_time_of_current_run(void *arg)
{
- time_t current_time;
- time_t valid_after_time;
- char tbuf[ISO_TIME_LEN + 1];
int retval;
+ char tbuf[ISO_TIME_LEN + 1];
+ time_t current_time, run_start_time;
(void) arg;
- {
- /* Setup a fake consensus just to get the times out of it, since
- get_next_valid_after_time() needs them. */
- mock_consensus = tor_malloc_zero(sizeof(networkstatus_t));
+ MOCK(networkstatus_get_live_consensus,
+ mock_networkstatus_get_live_consensus);
- retval = parse_rfc1123_time("Mon, 13 Jan 2016 16:00:00 UTC",
- &mock_consensus->fresh_until);
- tt_int_op(retval, ==, 0);
+ retval = parse_rfc1123_time("Mon, 20 Apr 2015 01:00:00 UTC",
+ &mock_consensus.fresh_until);
+ tt_int_op(retval, OP_EQ, 0);
- retval = parse_rfc1123_time("Mon, 13 Jan 2016 15:00:00 UTC",
- &mock_consensus->valid_after);
- tt_int_op(retval, ==, 0);
+ retval = parse_rfc1123_time("Mon, 20 Apr 2015 00:00:00 UTC",
+ &mock_consensus.valid_after);
+ tt_int_op(retval, OP_EQ, 0);
+
+ {
+ /* Get start time if called at 00:00:01 */
+ retval = parse_rfc1123_time("Mon, 20 Apr 2015 00:00:01 UTC",
+ &current_time);
+ tt_int_op(retval, OP_EQ, 0);
+ dirvote_recalculate_timing(get_options(), current_time);
+ run_start_time =
+ sr_state_get_start_time_of_current_protocol_run(current_time);
- MOCK(networkstatus_get_live_consensus,
- mock_networkstatus_get_live_consensus);
+ /* Compare it with the correct result */
+ format_iso_time(tbuf, run_start_time);
+ tt_str_op("2015-04-20 00:00:00", OP_EQ, tbuf);
}
{
- /* Get the valid after time if called at 00:00:00 */
- retval = parse_rfc1123_time("Mon, 20 Apr 2015 00:00:00 UTC",
+ retval = parse_rfc1123_time("Mon, 20 Apr 2015 23:59:59 UTC",
&current_time);
- tt_int_op(retval, ==, 0);
- valid_after_time = get_next_valid_after_time(current_time);
+ tt_int_op(retval, OP_EQ, 0);
+ dirvote_recalculate_timing(get_options(), current_time);
+ run_start_time =
+ sr_state_get_start_time_of_current_protocol_run(current_time);
/* Compare it with the correct result */
- format_iso_time(tbuf, valid_after_time);
- tt_str_op("2015-04-20 01:00:00", OP_EQ, tbuf);
+ format_iso_time(tbuf, run_start_time);
+ tt_str_op("2015-04-20 00:00:00", OP_EQ, tbuf);
}
{
- /* Get the valid until time if called at 00:00:01 */
- retval = parse_rfc1123_time("Mon, 20 Apr 2015 00:00:01 UTC",
+ retval = parse_rfc1123_time("Mon, 20 Apr 2015 00:00:00 UTC",
&current_time);
- tt_int_op(retval, ==, 0);
- valid_after_time = get_next_valid_after_time(current_time);
+ tt_int_op(retval, OP_EQ, 0);
+ dirvote_recalculate_timing(get_options(), current_time);
+ run_start_time =
+ sr_state_get_start_time_of_current_protocol_run(current_time);
/* Compare it with the correct result */
- format_iso_time(tbuf, valid_after_time);
- tt_str_op("2015-04-20 01:00:00", OP_EQ, tbuf);
- }
+ format_iso_time(tbuf, run_start_time);
+ tt_str_op("2015-04-20 00:00:00", OP_EQ, tbuf);
+ }
+
+ /* Next test is testing it without a consensus to use the testing voting
+ * interval . */
+ UNMOCK(networkstatus_get_live_consensus);
+ /* Now let's alter the voting schedule and check the correctness of the
+ * function. Voting interval of 10 seconds, means that an SRV protocol run
+ * takes 10 seconds * 24 rounds = 4 mins */
{
- retval = parse_rfc1123_time("Mon, 20 Apr 2015 23:30:01 UTC",
+ or_options_t *options = get_options_mutable();
+ options->V3AuthVotingInterval = 10;
+ options->TestingV3AuthInitialVotingInterval = 10;
+ retval = parse_rfc1123_time("Mon, 20 Apr 2015 00:15:32 UTC",
&current_time);
- tt_int_op(retval, ==, 0);
- valid_after_time = get_next_valid_after_time(current_time);
+ tt_int_op(retval, OP_EQ, 0);
+ dirvote_recalculate_timing(get_options(), current_time);
+ run_start_time =
+ sr_state_get_start_time_of_current_protocol_run(current_time);
/* Compare it with the correct result */
- format_iso_time(tbuf, valid_after_time);
- tt_str_op("2015-04-21 00:00:00", OP_EQ, tbuf);
- }
+ format_iso_time(tbuf, run_start_time);
+ tt_str_op("2015-04-20 00:12:00", OP_EQ, tbuf);
+ }
+
+ done:
+ ;
+}
+
+/** Do some rudimentary consistency checks between the functions that
+ * understand the shared random protocol schedule */
+static void
+test_get_start_time_functions(void *arg)
+{
+ (void) arg;
+ int retval;
+
+ MOCK(networkstatus_get_live_consensus,
+ mock_networkstatus_get_live_consensus);
+
+ retval = parse_rfc1123_time("Mon, 20 Apr 2015 01:00:00 UTC",
+ &mock_consensus.fresh_until);
+ tt_int_op(retval, OP_EQ, 0);
+
+ retval = parse_rfc1123_time("Mon, 20 Apr 2015 00:00:00 UTC",
+ &mock_consensus.valid_after);
+ tt_int_op(retval, OP_EQ, 0);
+ time_t now = mock_consensus.valid_after;
+
+ dirvote_recalculate_timing(get_options(), now);
+ time_t start_time_of_protocol_run =
+ sr_state_get_start_time_of_current_protocol_run(now);
+ tt_assert(start_time_of_protocol_run);
+
+ /* Check that the round start time of the beginning of the run, is itself */
+ tt_int_op(get_start_time_of_current_round(), OP_EQ,
+ start_time_of_protocol_run);
done:
- networkstatus_vote_free(mock_consensus);
+ UNMOCK(networkstatus_get_live_consensus);
+}
+
+static void
+test_get_sr_protocol_duration(void *arg)
+{
+ (void) arg;
+
+ /* Check that by default an SR phase is 12 hours */
+ tt_int_op(sr_state_get_phase_duration(), OP_EQ, 12*60*60);
+ tt_int_op(sr_state_get_protocol_run_duration(), OP_EQ, 24*60*60);
+
+ /* Now alter the voting interval and check that the SR phase is 2 mins long
+ * if voting happens every 10 seconds (10*12 seconds = 2 mins) */
+ or_options_t *options = get_options_mutable();
+ options->V3AuthVotingInterval = 10;
+ tt_int_op(sr_state_get_phase_duration(), OP_EQ, 2*60);
+ tt_int_op(sr_state_get_protocol_run_duration(), OP_EQ, 4*60);
+
+ done: ;
}
/* In this test we are going to generate a sr_commit_t object and validate
@@ -286,7 +375,7 @@ test_sr_commit(void *arg)
tt_assert(auth_cert);
options->AuthoritativeDir = 1;
- tt_int_op(0, ==, load_ed_keys(options, now));
+ tt_int_op(load_ed_keys(options, time(NULL)), OP_GE, 0);
}
/* Generate our commit object and validate it has the appropriate field
@@ -304,18 +393,18 @@ test_sr_commit(void *arg)
tt_assert(!tor_mem_is_zero((char *) our_commit->random_number,
sizeof(our_commit->random_number)));
/* Commit and reveal timestamp should be the same. */
- tt_u64_op(our_commit->commit_ts, ==, our_commit->reveal_ts);
+ tt_u64_op(our_commit->commit_ts, OP_EQ, our_commit->reveal_ts);
/* We should have a hashed reveal. */
tt_assert(!tor_mem_is_zero(our_commit->hashed_reveal,
sizeof(our_commit->hashed_reveal)));
/* Do we have a valid encoded commit and reveal. Note the following only
* tests if the generated values are correct. Their could be a bug in
* the decode function but we test them seperately. */
- tt_int_op(0, ==, reveal_decode(our_commit->encoded_reveal,
+ tt_int_op(0, OP_EQ, reveal_decode(our_commit->encoded_reveal,
&test_commit));
- tt_int_op(0, ==, commit_decode(our_commit->encoded_commit,
+ tt_int_op(0, OP_EQ, commit_decode(our_commit->encoded_commit,
&test_commit));
- tt_int_op(0, ==, verify_commit_and_reveal(our_commit));
+ tt_int_op(0, OP_EQ, verify_commit_and_reveal(our_commit));
}
/* Let's make sure our verify commit and reveal function works. We'll
@@ -328,32 +417,32 @@ test_sr_commit(void *arg)
/* Timestamp MUST match. */
test_commit.commit_ts = test_commit.reveal_ts - 42;
setup_full_capture_of_logs(LOG_WARN);
- tt_int_op(-1, ==, verify_commit_and_reveal(&test_commit));
+ tt_int_op(-1, OP_EQ, verify_commit_and_reveal(&test_commit));
expect_log_msg_containing("doesn't match reveal timestamp");
teardown_capture_of_logs();
memcpy(&test_commit, our_commit, sizeof(test_commit));
- tt_int_op(0, ==, verify_commit_and_reveal(&test_commit));
+ tt_int_op(0, OP_EQ, verify_commit_and_reveal(&test_commit));
/* Hashed reveal must match the H(encoded_reveal). */
memset(test_commit.hashed_reveal, 'X',
sizeof(test_commit.hashed_reveal));
setup_full_capture_of_logs(LOG_WARN);
- tt_int_op(-1, ==, verify_commit_and_reveal(&test_commit));
+ tt_int_op(-1, OP_EQ, verify_commit_and_reveal(&test_commit));
expect_single_log_msg_containing("doesn't match the commit value");
teardown_capture_of_logs();
memcpy(&test_commit, our_commit, sizeof(test_commit));
- tt_int_op(0, ==, verify_commit_and_reveal(&test_commit));
+ tt_int_op(0, OP_EQ, verify_commit_and_reveal(&test_commit));
}
/* We'll build a list of values from our commit that our parsing function
* takes from a vote line and see if we can parse it correctly. */
{
- smartlist_add(args, tor_strdup("1"));
- smartlist_add(args,
- tor_strdup(crypto_digest_algorithm_get_name(our_commit->alg)));
- smartlist_add(args, tor_strdup(sr_commit_get_rsa_fpr(our_commit)));
- smartlist_add(args, tor_strdup(our_commit->encoded_commit));
- smartlist_add(args, tor_strdup(our_commit->encoded_reveal));
+ smartlist_add_strdup(args, "1");
+ smartlist_add_strdup(args,
+ crypto_digest_algorithm_get_name(our_commit->alg));
+ smartlist_add_strdup(args, sr_commit_get_rsa_fpr(our_commit));
+ smartlist_add_strdup(args, our_commit->encoded_commit);
+ smartlist_add_strdup(args, our_commit->encoded_reveal);
parsed_commit = sr_parse_commit(args);
tt_assert(parsed_commit);
/* That parsed commit should be _EXACTLY_ like our original commit (we
@@ -396,26 +485,26 @@ test_encoding(void *arg)
/* Hash random number because we don't expose bytes of the RNG. */
ret = crypto_digest256(hashed_rand, raw_rand,
sizeof(raw_rand), SR_DIGEST_ALG);
- tt_int_op(0, ==, ret);
+ tt_int_op(0, OP_EQ, ret);
/* Hash reveal value. */
- tt_int_op(SR_REVEAL_BASE64_LEN, ==, strlen(encoded_reveal));
+ tt_int_op(SR_REVEAL_BASE64_LEN, OP_EQ, strlen(encoded_reveal));
ret = crypto_digest256(hashed_reveal, encoded_reveal,
strlen(encoded_reveal), SR_DIGEST_ALG);
- tt_int_op(0, ==, ret);
- tt_int_op(SR_COMMIT_BASE64_LEN, ==, strlen(encoded_commit));
+ tt_int_op(0, OP_EQ, ret);
+ tt_int_op(SR_COMMIT_BASE64_LEN, OP_EQ, strlen(encoded_commit));
/* Test our commit/reveal decode functions. */
{
/* Test the reveal encoded value. */
- tt_int_op(0, ==, reveal_decode(encoded_reveal, &parsed_commit));
- tt_u64_op(ts, ==, parsed_commit.reveal_ts);
+ tt_int_op(0, OP_EQ, reveal_decode(encoded_reveal, &parsed_commit));
+ tt_u64_op(ts, OP_EQ, parsed_commit.reveal_ts);
tt_mem_op(hashed_rand, OP_EQ, parsed_commit.random_number,
sizeof(hashed_rand));
/* Test the commit encoded value. */
memset(&parsed_commit, 0, sizeof(parsed_commit));
- tt_int_op(0, ==, commit_decode(encoded_commit, &parsed_commit));
- tt_u64_op(ts, ==, parsed_commit.commit_ts);
+ tt_int_op(0, OP_EQ, commit_decode(encoded_commit, &parsed_commit));
+ tt_u64_op(ts, OP_EQ, parsed_commit.commit_ts);
tt_mem_op(encoded_commit, OP_EQ, parsed_commit.encoded_commit,
sizeof(parsed_commit.encoded_commit));
tt_mem_op(hashed_reveal, OP_EQ, parsed_commit.hashed_reveal,
@@ -430,7 +519,7 @@ test_encoding(void *arg)
memcpy(parsed_commit.random_number, hashed_rand,
sizeof(parsed_commit.random_number));
ret = reveal_encode(&parsed_commit, encoded, sizeof(encoded));
- tt_int_op(SR_REVEAL_BASE64_LEN, ==, ret);
+ tt_int_op(SR_REVEAL_BASE64_LEN, OP_EQ, ret);
tt_mem_op(encoded_reveal, OP_EQ, encoded, strlen(encoded_reveal));
}
@@ -441,7 +530,7 @@ test_encoding(void *arg)
memcpy(parsed_commit.hashed_reveal, hashed_reveal,
sizeof(parsed_commit.hashed_reveal));
ret = commit_encode(&parsed_commit, encoded, sizeof(encoded));
- tt_int_op(SR_COMMIT_BASE64_LEN, ==, ret);
+ tt_int_op(SR_COMMIT_BASE64_LEN, OP_EQ, ret);
tt_mem_op(encoded_commit, OP_EQ, encoded, strlen(encoded_commit));
}
@@ -518,7 +607,7 @@ test_vote(void *arg)
tt_assert(lines);
/* Split the lines. We expect 2 here. */
ret = smartlist_split_string(chunks, lines, "\n", SPLIT_IGNORE_BLANK, 0);
- tt_int_op(ret, ==, 4);
+ tt_int_op(ret, OP_EQ, 4);
tt_str_op(smartlist_get(chunks, 0), OP_EQ, "shared-rand-participate");
/* Get our commitment line and will validate it agains our commit. The
* format is as follow:
@@ -528,7 +617,7 @@ test_vote(void *arg)
char *commit_line = smartlist_get(chunks, 1);
tt_assert(commit_line);
ret = smartlist_split_string(tokens, commit_line, " ", 0, 0);
- tt_int_op(ret, ==, 6);
+ tt_int_op(ret, OP_EQ, 6);
tt_str_op(smartlist_get(tokens, 0), OP_EQ, "shared-rand-commit");
tt_str_op(smartlist_get(tokens, 1), OP_EQ, "1");
tt_str_op(smartlist_get(tokens, 2), OP_EQ,
@@ -536,7 +625,7 @@ test_vote(void *arg)
char digest[DIGEST_LEN];
base16_decode(digest, sizeof(digest), smartlist_get(tokens, 3),
HEX_DIGEST_LEN);
- tt_mem_op(digest, ==, our_commit->rsa_identity, sizeof(digest));
+ tt_mem_op(digest, OP_EQ, our_commit->rsa_identity, sizeof(digest));
tt_str_op(smartlist_get(tokens, 4), OP_EQ, our_commit->encoded_commit);
tt_str_op(smartlist_get(tokens, 5), OP_EQ, our_commit->encoded_reveal)
;
@@ -552,7 +641,7 @@ test_vote(void *arg)
/* Set valid flag explicitly here to compare since it's not set by
* simply parsing the commit. */
parsed_commit->valid = 1;
- tt_mem_op(parsed_commit, ==, our_commit, sizeof(*our_commit));
+ tt_mem_op(parsed_commit, OP_EQ, our_commit, sizeof(*our_commit));
/* minor cleanup */
SMARTLIST_FOREACH(tokens, char *, s, tor_free(s));
@@ -562,7 +651,7 @@ test_vote(void *arg)
char *prev_srv_line = smartlist_get(chunks, 2);
tt_assert(prev_srv_line);
ret = smartlist_split_string(tokens, prev_srv_line, " ", 0, 0);
- tt_int_op(ret, ==, 3);
+ tt_int_op(ret, OP_EQ, 3);
tt_str_op(smartlist_get(tokens, 0), OP_EQ, "shared-rand-previous-value");
tt_str_op(smartlist_get(tokens, 1), OP_EQ, "42");
tt_str_op(smartlist_get(tokens, 2), OP_EQ,
@@ -576,7 +665,7 @@ test_vote(void *arg)
char *current_srv_line = smartlist_get(chunks, 3);
tt_assert(current_srv_line);
ret = smartlist_split_string(tokens, current_srv_line, " ", 0, 0);
- tt_int_op(ret, ==, 3);
+ tt_int_op(ret, OP_EQ, 3);
tt_str_op(smartlist_get(tokens, 0), OP_EQ, "shared-rand-current-value");
tt_str_op(smartlist_get(tokens, 1), OP_EQ, "128");
tt_str_op(smartlist_get(tokens, 2), OP_EQ,
@@ -629,7 +718,7 @@ test_state_load_from_disk(void *arg)
/* First try with a nonexistent path. */
ret = disk_state_load_from_disk_impl("NONEXISTENTNONEXISTENT");
- tt_assert(ret == -ENOENT);
+ tt_int_op(ret, OP_EQ, -ENOENT);
/* Now create a mock state directory and state file */
#ifdef _WIN32
@@ -637,9 +726,9 @@ test_state_load_from_disk(void *arg)
#else
ret = mkdir(dir, 0700);
#endif
- tt_assert(ret == 0);
+ tt_int_op(ret, OP_EQ, 0);
ret = write_str_to_file(sr_state_path, sr_state_str, 0);
- tt_assert(ret == 0);
+ tt_int_op(ret, OP_EQ, 0);
/* Try to load the directory itself. Should fail. */
ret = disk_state_load_from_disk_impl(dir);
@@ -647,11 +736,11 @@ test_state_load_from_disk(void *arg)
/* State should be non-existent at this point. */
the_sr_state = get_sr_state();
- tt_assert(!the_sr_state);
+ tt_ptr_op(the_sr_state, OP_EQ, NULL);
/* Now try to load the correct file! */
ret = disk_state_load_from_disk_impl(sr_state_path);
- tt_assert(ret == 0);
+ tt_int_op(ret, OP_EQ, 0);
/* Check the content of the state */
/* XXX check more deeply!!! */
@@ -689,7 +778,7 @@ test_sr_setup_commits(void)
tt_assert(auth_cert);
options->AuthoritativeDir = 1;
- tt_int_op(0, ==, load_ed_keys(options, now));
+ tt_int_op(0, OP_EQ, load_ed_keys(options, now));
}
/* Generate three dummy commits according to sr_srv_calc_ref.py . Then
@@ -775,7 +864,7 @@ test_sr_setup_commits(void)
save_commit_to_state(commit_b);
save_commit_to_state(commit_c);
save_commit_to_state(commit_d);
- tt_int_op(digestmap_size(get_sr_state()->commits), ==, 4);
+ tt_int_op(digestmap_size(get_sr_state()->commits), OP_EQ, 4);
/* Now during REVEAL phase save commit D by restoring its reveal. */
set_sr_phase(SR_PHASE_REVEAL);
@@ -822,9 +911,9 @@ test_sr_compute_srv(void *arg)
/* Check the result against the test vector */
current_srv = sr_state_get_current_srv();
tt_assert(current_srv);
- tt_u64_op(current_srv->num_reveals, ==, 3);
+ tt_u64_op(current_srv->num_reveals, OP_EQ, 3);
tt_str_op(hex_str((char*)current_srv->value, 32),
- ==,
+ OP_EQ,
SRV_TEST_VECTOR);
done:
@@ -880,7 +969,7 @@ test_sr_get_majority_srv_from_votes(void *arg)
/* Since it's only one vote with an SRV, it should not achieve majority and
hence no SRV will be returned. */
chosen_srv = get_majority_srv_from_votes(votes, 1);
- tt_assert(!chosen_srv);
+ tt_ptr_op(chosen_srv, OP_EQ, NULL);
{ /* Now put in 8 more votes. Let SRV_1 have majority. */
int i;
@@ -899,21 +988,21 @@ test_sr_get_majority_srv_from_votes(void *arg)
smartlist_add(votes, vote);
}
- tt_int_op(smartlist_len(votes), ==, 9);
+ tt_int_op(smartlist_len(votes), OP_EQ, 9);
}
/* Now we achieve majority for SRV_1, but not the AuthDirNumSRVAgreements
requirement. So still not picking an SRV. */
set_num_srv_agreements(8);
chosen_srv = get_majority_srv_from_votes(votes, 1);
- tt_assert(!chosen_srv);
+ tt_ptr_op(chosen_srv, OP_EQ, NULL);
/* We will now lower the AuthDirNumSRVAgreements requirement by tweaking the
* consensus parameter and we will try again. This time it should work. */
set_num_srv_agreements(7);
chosen_srv = get_majority_srv_from_votes(votes, 1);
tt_assert(chosen_srv);
- tt_u64_op(chosen_srv->num_reveals, ==, 42);
+ tt_u64_op(chosen_srv->num_reveals, OP_EQ, 42);
tt_mem_op(chosen_srv->value, OP_EQ, SRV_1, sizeof(chosen_srv->value));
done:
@@ -937,7 +1026,7 @@ test_utils(void *arg)
memcpy(srv->value, srv_value, sizeof(srv->value));
dup_srv = srv_dup(srv);
tt_assert(dup_srv);
- tt_u64_op(dup_srv->num_reveals, ==, srv->num_reveals);
+ tt_u64_op(dup_srv->num_reveals, OP_EQ, srv->num_reveals);
tt_mem_op(dup_srv->value, OP_EQ, srv->value, sizeof(srv->value));
tor_free(srv);
tor_free(dup_srv);
@@ -957,10 +1046,10 @@ test_utils(void *arg)
sr_commit_t commit1, commit2;
memcpy(commit1.encoded_commit, payload, sizeof(commit1.encoded_commit));
memcpy(commit2.encoded_commit, payload, sizeof(commit2.encoded_commit));
- tt_int_op(commitments_are_the_same(&commit1, &commit2), ==, 1);
+ tt_int_op(commitments_are_the_same(&commit1, &commit2), OP_EQ, 1);
/* Let's corrupt one of them. */
memset(commit1.encoded_commit, 'A', sizeof(commit1.encoded_commit));
- tt_int_op(commitments_are_the_same(&commit1, &commit2), ==, 0);
+ tt_int_op(commitments_are_the_same(&commit1, &commit2), OP_EQ, 0);
}
/* Testing commit_is_authoritative(). */
@@ -971,32 +1060,32 @@ test_utils(void *arg)
tt_assert(!crypto_pk_generate_key(k));
- tt_int_op(0, ==, crypto_pk_get_digest(k, digest));
+ tt_int_op(0, OP_EQ, crypto_pk_get_digest(k, digest));
memcpy(commit.rsa_identity, digest, sizeof(commit.rsa_identity));
- tt_int_op(commit_is_authoritative(&commit, digest), ==, 1);
+ tt_int_op(commit_is_authoritative(&commit, digest), OP_EQ, 1);
/* Change the pubkey. */
memset(commit.rsa_identity, 0, sizeof(commit.rsa_identity));
- tt_int_op(commit_is_authoritative(&commit, digest), ==, 0);
+ tt_int_op(commit_is_authoritative(&commit, digest), OP_EQ, 0);
crypto_pk_free(k);
}
/* Testing get_phase_str(). */
{
- tt_str_op(get_phase_str(SR_PHASE_REVEAL), ==, "reveal");
- tt_str_op(get_phase_str(SR_PHASE_COMMIT), ==, "commit");
+ tt_str_op(get_phase_str(SR_PHASE_REVEAL), OP_EQ, "reveal");
+ tt_str_op(get_phase_str(SR_PHASE_COMMIT), OP_EQ, "commit");
}
/* Testing phase transition */
{
init_authority_state();
set_sr_phase(SR_PHASE_COMMIT);
- tt_int_op(is_phase_transition(SR_PHASE_REVEAL), ==, 1);
- tt_int_op(is_phase_transition(SR_PHASE_COMMIT), ==, 0);
+ tt_int_op(is_phase_transition(SR_PHASE_REVEAL), OP_EQ, 1);
+ tt_int_op(is_phase_transition(SR_PHASE_COMMIT), OP_EQ, 0);
set_sr_phase(SR_PHASE_REVEAL);
- tt_int_op(is_phase_transition(SR_PHASE_REVEAL), ==, 0);
- tt_int_op(is_phase_transition(SR_PHASE_COMMIT), ==, 1);
+ tt_int_op(is_phase_transition(SR_PHASE_REVEAL), OP_EQ, 0);
+ tt_int_op(is_phase_transition(SR_PHASE_COMMIT), OP_EQ, 1);
/* Junk. */
- tt_int_op(is_phase_transition(42), ==, 1);
+ tt_int_op(is_phase_transition(42), OP_EQ, 1);
}
done:
@@ -1024,24 +1113,24 @@ test_state_transition(void *arg)
sr_commit_t *commit = sr_generate_our_commit(now, mock_cert);
tt_assert(commit);
sr_state_add_commit(commit);
- tt_int_op(digestmap_size(state->commits), ==, 1);
+ tt_int_op(digestmap_size(state->commits), OP_EQ, 1);
/* Let's test our delete feature. */
sr_state_delete_commits();
- tt_int_op(digestmap_size(state->commits), ==, 0);
+ tt_int_op(digestmap_size(state->commits), OP_EQ, 0);
/* Add it back so we can continue the rest of the test because after
* deletiong our commit will be freed so generate a new one. */
commit = sr_generate_our_commit(now, mock_cert);
tt_assert(commit);
sr_state_add_commit(commit);
- tt_int_op(digestmap_size(state->commits), ==, 1);
+ tt_int_op(digestmap_size(state->commits), OP_EQ, 1);
state->n_reveal_rounds = 42;
state->n_commit_rounds = 43;
state->n_protocol_runs = 44;
reset_state_for_new_protocol_run(now);
- tt_int_op(state->n_reveal_rounds, ==, 0);
- tt_int_op(state->n_commit_rounds, ==, 0);
- tt_u64_op(state->n_protocol_runs, ==, 45);
- tt_int_op(digestmap_size(state->commits), ==, 0);
+ tt_int_op(state->n_reveal_rounds, OP_EQ, 0);
+ tt_int_op(state->n_commit_rounds, OP_EQ, 0);
+ tt_u64_op(state->n_protocol_runs, OP_EQ, 45);
+ tt_int_op(digestmap_size(state->commits), OP_EQ, 0);
}
/* Test SRV rotation in our state. */
@@ -1054,7 +1143,7 @@ test_state_transition(void *arg)
state_rotate_srv();
prev = sr_state_get_previous_srv();
tt_assert(prev == cur);
- tt_assert(!sr_state_get_current_srv());
+ tt_ptr_op(sr_state_get_current_srv(), OP_EQ, NULL);
sr_state_clean_srvs();
}
@@ -1079,18 +1168,18 @@ test_state_transition(void *arg)
/* Also, make sure we did change the current. */
tt_assert(sr_state_get_current_srv() != cur);
/* We should have our commitment alone. */
- tt_int_op(digestmap_size(state->commits), ==, 1);
- tt_int_op(state->n_reveal_rounds, ==, 0);
- tt_int_op(state->n_commit_rounds, ==, 0);
+ tt_int_op(digestmap_size(state->commits), OP_EQ, 1);
+ tt_int_op(state->n_reveal_rounds, OP_EQ, 0);
+ tt_int_op(state->n_commit_rounds, OP_EQ, 0);
/* 46 here since we were at 45 just before. */
- tt_u64_op(state->n_protocol_runs, ==, 46);
+ tt_u64_op(state->n_protocol_runs, OP_EQ, 46);
}
/* Cleanup of SRVs. */
{
sr_state_clean_srvs();
- tt_assert(!sr_state_get_current_srv());
- tt_assert(!sr_state_get_previous_srv());
+ tt_ptr_op(sr_state_get_current_srv(), OP_EQ, NULL);
+ tt_ptr_op(sr_state_get_previous_srv(), OP_EQ, NULL);
}
done:
@@ -1119,6 +1208,8 @@ test_keep_commit(void *arg)
state = get_sr_state();
}
+ crypto_rand((char*)fp, sizeof(fp));
+
/* Test this very important function that tells us if we should keep a
* commit or not in our state. Most of it depends on the phase and what's
* in the commit so we'll change the commit as we go. */
@@ -1127,21 +1218,21 @@ test_keep_commit(void *arg)
/* Set us in COMMIT phase for starter. */
set_sr_phase(SR_PHASE_COMMIT);
/* We should never keep a commit from a non authoritative authority. */
- tt_int_op(should_keep_commit(commit, fp, SR_PHASE_COMMIT), ==, 0);
+ tt_int_op(should_keep_commit(commit, fp, SR_PHASE_COMMIT), OP_EQ, 0);
/* This should NOT be kept because it has a reveal value in it. */
tt_assert(commit_has_reveal_value(commit));
tt_int_op(should_keep_commit(commit, commit->rsa_identity,
- SR_PHASE_COMMIT), ==, 0);
+ SR_PHASE_COMMIT), OP_EQ, 0);
/* Add it to the state which should return to not keep it. */
sr_state_add_commit(commit);
tt_int_op(should_keep_commit(commit, commit->rsa_identity,
- SR_PHASE_COMMIT), ==, 0);
+ SR_PHASE_COMMIT), OP_EQ, 0);
/* Remove it from state so we can continue our testing. */
digestmap_remove(state->commits, commit->rsa_identity);
/* Let's remove our reveal value which should make it OK to keep it. */
memset(commit->encoded_reveal, 0, sizeof(commit->encoded_reveal));
tt_int_op(should_keep_commit(commit, commit->rsa_identity,
- SR_PHASE_COMMIT), ==, 1);
+ SR_PHASE_COMMIT), OP_EQ, 1);
/* Let's reset our commit and go into REVEAL phase. */
sr_commit_free(commit);
@@ -1153,17 +1244,17 @@ test_keep_commit(void *arg)
memset(dup_commit->encoded_reveal, 0, sizeof(dup_commit->encoded_reveal));
set_sr_phase(SR_PHASE_REVEAL);
/* We should never keep a commit from a non authoritative authority. */
- tt_int_op(should_keep_commit(commit, fp, SR_PHASE_REVEAL), ==, 0);
+ tt_int_op(should_keep_commit(commit, fp, SR_PHASE_REVEAL), OP_EQ, 0);
/* We shouldn't accept a commit that is not in our state. */
tt_int_op(should_keep_commit(commit, commit->rsa_identity,
- SR_PHASE_REVEAL), ==, 0);
+ SR_PHASE_REVEAL), OP_EQ, 0);
/* Important to add the commit _without_ the reveal here. */
sr_state_add_commit(dup_commit);
- tt_int_op(digestmap_size(state->commits), ==, 1);
+ tt_int_op(digestmap_size(state->commits), OP_EQ, 1);
/* Our commit should be valid that is authoritative, contains a reveal, be
* in the state and commitment and reveal values match. */
tt_int_op(should_keep_commit(commit, commit->rsa_identity,
- SR_PHASE_REVEAL), ==, 1);
+ SR_PHASE_REVEAL), OP_EQ, 1);
/* The commit shouldn't be kept if it's not verified that is no matchin
* hashed reveal. */
{
@@ -1174,7 +1265,7 @@ test_keep_commit(void *arg)
memset(commit->hashed_reveal, 0, sizeof(commit->hashed_reveal));
setup_full_capture_of_logs(LOG_WARN);
tt_int_op(should_keep_commit(commit, commit->rsa_identity,
- SR_PHASE_REVEAL), ==, 0);
+ SR_PHASE_REVEAL), OP_EQ, 0);
expect_log_msg_containing("doesn't match the commit value.");
expect_log_msg_containing("has an invalid reveal value.");
assert_log_predicate(mock_saved_log_n_entries() == 2,
@@ -1185,11 +1276,11 @@ test_keep_commit(void *arg)
}
/* We shouldn't keep a commit that has no reveal. */
tt_int_op(should_keep_commit(dup_commit, dup_commit->rsa_identity,
- SR_PHASE_REVEAL), ==, 0);
+ SR_PHASE_REVEAL), OP_EQ, 0);
/* We must not keep a commit that is not the same from the commit phase. */
memset(commit->encoded_commit, 0, sizeof(commit->encoded_commit));
tt_int_op(should_keep_commit(commit, commit->rsa_identity,
- SR_PHASE_REVEAL), ==, 0);
+ SR_PHASE_REVEAL), OP_EQ, 0);
done:
teardown_capture_of_logs();
@@ -1227,35 +1318,35 @@ test_state_update(void *arg)
/* We are in COMMIT phase here and we'll trigger a state update but no
* transition. */
sr_state_update(commit_phase_time);
- tt_int_op(state->valid_after, ==, commit_phase_time);
- tt_int_op(state->n_commit_rounds, ==, 1);
- tt_int_op(state->phase, ==, SR_PHASE_COMMIT);
- tt_int_op(digestmap_size(state->commits), ==, 1);
+ tt_int_op(state->valid_after, OP_EQ, commit_phase_time);
+ tt_int_op(state->n_commit_rounds, OP_EQ, 1);
+ tt_int_op(state->phase, OP_EQ, SR_PHASE_COMMIT);
+ tt_int_op(digestmap_size(state->commits), OP_EQ, 1);
/* We are still in the COMMIT phase here but we'll trigger a state
* transition to the REVEAL phase. */
sr_state_update(reveal_phase_time);
- tt_int_op(state->phase, ==, SR_PHASE_REVEAL);
- tt_int_op(state->valid_after, ==, reveal_phase_time);
+ tt_int_op(state->phase, OP_EQ, SR_PHASE_REVEAL);
+ tt_int_op(state->valid_after, OP_EQ, reveal_phase_time);
/* Only our commit should be in there. */
- tt_int_op(digestmap_size(state->commits), ==, 1);
- tt_int_op(state->n_reveal_rounds, ==, 1);
+ tt_int_op(digestmap_size(state->commits), OP_EQ, 1);
+ tt_int_op(state->n_reveal_rounds, OP_EQ, 1);
/* We can't update a state with a valid after _lower_ than the creation
* time so here it is. */
sr_state_update(commit_phase_time);
- tt_int_op(state->valid_after, ==, reveal_phase_time);
+ tt_int_op(state->valid_after, OP_EQ, reveal_phase_time);
/* Finally, let's go back in COMMIT phase so we can test the state update
* of a new protocol run. */
state->valid_after = 0;
sr_state_update(commit_phase_time);
- tt_int_op(state->valid_after, ==, commit_phase_time);
- tt_int_op(state->n_commit_rounds, ==, 1);
- tt_int_op(state->n_reveal_rounds, ==, 0);
- tt_u64_op(state->n_protocol_runs, ==, 1);
- tt_int_op(state->phase, ==, SR_PHASE_COMMIT);
- tt_int_op(digestmap_size(state->commits), ==, 1);
+ tt_int_op(state->valid_after, OP_EQ, commit_phase_time);
+ tt_int_op(state->n_commit_rounds, OP_EQ, 1);
+ tt_int_op(state->n_reveal_rounds, OP_EQ, 0);
+ tt_u64_op(state->n_protocol_runs, OP_EQ, 1);
+ tt_int_op(state->phase, OP_EQ, SR_PHASE_COMMIT);
+ tt_int_op(digestmap_size(state->commits), OP_EQ, 1);
tt_assert(state->current_srv);
done:
@@ -1272,7 +1363,11 @@ struct testcase_t sr_tests[] = {
NULL, NULL },
{ "encoding", test_encoding, TT_FORK,
NULL, NULL },
- { "get_next_valid_after_time", test_get_next_valid_after_time, TT_FORK,
+ { "get_start_time_of_current_run", test_get_start_time_of_current_run,
+ TT_FORK, NULL, NULL },
+ { "get_start_time_functions", test_get_start_time_functions,
+ TT_FORK, NULL, NULL },
+ { "get_sr_protocol_duration", test_get_sr_protocol_duration, TT_FORK,
NULL, NULL },
{ "get_state_valid_until_time", test_get_state_valid_until_time, TT_FORK,
NULL, NULL },
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..9ae7530e22 100644
--- a/src/test/test_socks.c
+++ b/src/test/test_socks.c
@@ -1,12 +1,14 @@
/* 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"
#include "buffers.h"
#include "config.h"
+#include "proto_socks.h"
#include "test.h"
+#include "log_test_helpers.h"
typedef struct socks_test_data_t {
socks_request_t *req;
@@ -43,7 +45,7 @@ static const struct testcase_setup_t socks_setup = {
buf_t *buf = testdata->buf; \
socks_request_t *socks = testdata->req;
#define ADD_DATA(buf, s) \
- write_to_buf(s, sizeof(s)-1, buf)
+ buf_add(buf, s, sizeof(s)-1)
static void
socks_request_clear(socks_request_t *socks)
@@ -61,8 +63,9 @@ test_socks_4_unsupported_commands(void *ptr)
/* SOCKS 4 Send BIND [02] to IP address 2.2.2.2:4369 */
ADD_DATA(buf, "\x04\x02\x11\x11\x02\x02\x02\x02\x00");
- tt_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
- get_options()->SafeSocks) == -1);
+ tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks),
+ OP_EQ, -1);
tt_int_op(4,OP_EQ, socks->socks_version);
tt_int_op(0,OP_EQ, socks->replylen); /* XXX: shouldn't tor reply? */
@@ -80,8 +83,9 @@ test_socks_4_supported_commands(void *ptr)
/* SOCKS 4 Send CONNECT [01] to IP address 2.2.2.2:4370 */
ADD_DATA(buf, "\x04\x01\x11\x12\x02\x02\x02\x03\x00");
- tt_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
- get_options()->SafeSocks) == 1);
+ tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks),
+ OP_EQ, 1);
tt_int_op(4,OP_EQ, socks->socks_version);
tt_int_op(0,OP_EQ, socks->replylen); /* XXX: shouldn't tor reply? */
tt_int_op(SOCKS_COMMAND_CONNECT,OP_EQ, socks->command);
@@ -95,8 +99,8 @@ test_socks_4_supported_commands(void *ptr)
/* SOCKS 4 Send CONNECT [01] to IP address 2.2.2.2:4369 with userid*/
ADD_DATA(buf, "\x04\x01\x11\x12\x02\x02\x02\x04me\x00");
- tt_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
- get_options()->SafeSocks) == 1);
+ tt_int_op(fetch_from_buf_socks(buf, socks, 1, 0),
+ OP_EQ, 1);
tt_int_op(4,OP_EQ, socks->socks_version);
tt_int_op(0,OP_EQ, socks->replylen); /* XXX: shouldn't tor reply? */
tt_int_op(SOCKS_COMMAND_CONNECT,OP_EQ, socks->command);
@@ -112,8 +116,9 @@ test_socks_4_supported_commands(void *ptr)
/* SOCKS 4a Send RESOLVE [F0] request for torproject.org */
ADD_DATA(buf, "\x04\xF0\x01\x01\x00\x00\x00\x02me\x00torproject.org\x00");
- tt_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
- get_options()->SafeSocks) == 1);
+ tt_int_op(fetch_from_buf_socks(buf, socks, 1,
+ get_options()->SafeSocks),
+ OP_EQ, 1);
tt_int_op(4,OP_EQ, socks->socks_version);
tt_int_op(0,OP_EQ, socks->replylen); /* XXX: shouldn't tor reply? */
tt_str_op("torproject.org",OP_EQ, socks->address);
@@ -124,6 +129,83 @@ test_socks_4_supported_commands(void *ptr)
;
}
+static void
+test_socks_4_bad_arguments(void *ptr)
+{
+ SOCKS_TEST_INIT();
+ setup_capture_of_logs(LOG_DEBUG);
+
+ /* Try with 0 IPv4 address */
+ ADD_DATA(buf, "\x04\x01\x00\x50\x00\x00\x00\x00\x00");
+ tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks),
+ OP_EQ, -1);
+ buf_clear(buf);
+ expect_log_msg_containing("Port or DestIP is zero.");
+ mock_clean_saved_logs();
+
+ /* Try with 0 port */
+ ADD_DATA(buf, "\x04\x01\x00\x00\x01\x02\x03\x04\x00");
+ tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks),
+ OP_EQ, -1);
+ buf_clear(buf);
+ expect_log_msg_containing("Port or DestIP is zero.");
+ mock_clean_saved_logs();
+
+ /* Try with 2000-byte username (!) */
+ ADD_DATA(buf, "\x04\x01\x00\x50\x01\x02\x03\x04");
+ int i;
+ for (i = 0; i < 200; ++i) {
+ ADD_DATA(buf, "1234567890");
+ }
+ ADD_DATA(buf, "\x00");
+ tt_int_op(fetch_from_buf_socks(buf, socks, 1, 0),
+ OP_EQ, -1);
+ buf_clear(buf);
+ expect_log_msg_containing("user name too long; rejecting.");
+ mock_clean_saved_logs();
+
+ /* Try with 2000-byte hostname */
+ ADD_DATA(buf, "\x04\x01\x00\x50\x00\x00\x00\x01\x00");
+ for (i = 0; i < 200; ++i) {
+ ADD_DATA(buf, "1234567890");
+ }
+ ADD_DATA(buf, "\x00");
+ {
+ const char *p;
+ size_t s;
+ buf_pullup(buf, 9999, &p, &s);
+ }
+ tt_int_op(fetch_from_buf_socks(buf, socks, 1, 0),
+ OP_EQ, -1);
+ buf_clear(buf);
+ expect_log_msg_containing("Destaddr too long. Rejecting.");
+ mock_clean_saved_logs();
+
+ /* Try with 2000-byte hostname, not terminated. */
+ ADD_DATA(buf, "\x04\x01\x00\x50\x00\x00\x00\x01\x00");
+ for (i = 0; i < 200; ++i) {
+ ADD_DATA(buf, "1234567890");
+ }
+ tt_int_op(fetch_from_buf_socks(buf, socks, 1, 0),
+ OP_EQ, -1);
+ buf_clear(buf);
+ expect_log_msg_containing("Destaddr too long.");
+ mock_clean_saved_logs();
+
+ /* Socks4, bogus hostname */
+ ADD_DATA(buf, "\x04\x01\x00\x50\x00\x00\x00\x01\x00" "---\x00" );
+ tt_int_op(fetch_from_buf_socks(buf, socks, 1, 0), OP_EQ, -1);
+ buf_clear(buf);
+ expect_log_msg_containing("Your application (using socks4 to port 80) "
+ "gave Tor a malformed hostname: ");
+ mock_clean_saved_logs();
+
+ done:
+ teardown_capture_of_logs();
+}
+
/** Perform unsupported SOCKS 5 commands */
static void
test_socks_5_unsupported_commands(void *ptr)
@@ -199,10 +281,28 @@ test_socks_5_supported_commands(void *ptr)
tt_int_op(0,OP_EQ, buf_datalen(buf));
socks_request_clear(socks);
+ /* SOCKS 5 Send CONNECT [01] to one of the ipv6 addresses for
+ torproject.org:80 */
+ ADD_DATA(buf, "\x05\x01\x00");
+ ADD_DATA(buf, "\x05\x01\x00\x04"
+ "\x20\x02\x41\xb8\x02\x02\x0d\xeb\x02\x13\x21\xff\xfe\x20\x14\x26"
+ "\x00\x50");
+ tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks),OP_EQ, 1);
+ tt_int_op(5,OP_EQ, socks->socks_version);
+ tt_int_op(2,OP_EQ, socks->replylen);
+ tt_int_op(5,OP_EQ, socks->reply[0]);
+ tt_int_op(0,OP_EQ, socks->reply[1]);
+ tt_str_op("[2002:41b8:202:deb:213:21ff:fe20:1426]",OP_EQ, socks->address);
+ tt_int_op(80,OP_EQ, socks->port);
+
+ tt_int_op(0,OP_EQ, buf_datalen(buf));
+ socks_request_clear(socks);
+
/* SOCKS 5 Send CONNECT [01] to FQDN torproject.org:4369 */
ADD_DATA(buf, "\x05\x01\x00");
ADD_DATA(buf, "\x05\x01\x00\x03\x0Etorproject.org\x11\x11");
- tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ tt_int_op(fetch_from_buf_socks(buf, socks, 1,
get_options()->SafeSocks),OP_EQ, 1);
tt_int_op(5,OP_EQ, socks->socks_version);
@@ -218,8 +318,9 @@ test_socks_5_supported_commands(void *ptr)
/* SOCKS 5 Send RESOLVE [F0] request for torproject.org:4369 */
ADD_DATA(buf, "\x05\x01\x00");
ADD_DATA(buf, "\x05\xF0\x00\x03\x0Etorproject.org\x01\x02");
- tt_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
- get_options()->SafeSocks) == 1);
+ tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks),
+ OP_EQ, 1);
tt_int_op(5,OP_EQ, socks->socks_version);
tt_int_op(2,OP_EQ, socks->replylen);
tt_int_op(5,OP_EQ, socks->reply[0]);
@@ -229,47 +330,46 @@ test_socks_5_supported_commands(void *ptr)
tt_int_op(0,OP_EQ, buf_datalen(buf));
socks_request_clear(socks);
- /* SOCKS 5 Should reject RESOLVE [F0] request for IPv4 address
+ /* SOCKS 5 Should NOT reject RESOLVE [F0] request for IPv4 address
* string if SafeSocks is enabled. */
ADD_DATA(buf, "\x05\x01\x00");
ADD_DATA(buf, "\x05\xF0\x00\x03\x07");
ADD_DATA(buf, "8.8.8.8");
- ADD_DATA(buf, "\x01\x02");
- tt_assert(fetch_from_buf_socks(buf,socks,get_options()->TestSocks,1)
- == -1);
+ ADD_DATA(buf, "\x11\x11");
+ tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks, 1),
+ OP_EQ, 1);
- tt_int_op(5,OP_EQ,socks->socks_version);
- tt_int_op(10,OP_EQ,socks->replylen);
- tt_int_op(5,OP_EQ,socks->reply[0]);
- tt_int_op(SOCKS5_NOT_ALLOWED,OP_EQ,socks->reply[1]);
- tt_int_op(1,OP_EQ,socks->reply[3]);
+ tt_str_op("8.8.8.8", OP_EQ, socks->address);
+ tt_int_op(4369, OP_EQ, socks->port);
+
+ tt_int_op(0, OP_EQ, buf_datalen(buf));
socks_request_clear(socks);
- /* SOCKS 5 should reject RESOLVE [F0] reject for IPv6 address
+ /* SOCKS 5 should NOT reject RESOLVE [F0] reject for IPv6 address
* string if SafeSocks is enabled. */
ADD_DATA(buf, "\x05\x01\x00");
ADD_DATA(buf, "\x05\xF0\x00\x03\x27");
ADD_DATA(buf, "2001:0db8:85a3:0000:0000:8a2e:0370:7334");
ADD_DATA(buf, "\x01\x02");
- tt_assert(fetch_from_buf_socks(buf,socks,get_options()->TestSocks,1)
- == -1);
+ tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks, 1),
+ OP_EQ, -1);
- tt_int_op(5,OP_EQ,socks->socks_version);
- tt_int_op(10,OP_EQ,socks->replylen);
- tt_int_op(5,OP_EQ,socks->reply[0]);
- tt_int_op(SOCKS5_NOT_ALLOWED,OP_EQ,socks->reply[1]);
- tt_int_op(1,OP_EQ,socks->reply[3]);
+ tt_str_op("2001:0db8:85a3:0000:0000:8a2e:0370:7334", OP_EQ, socks->address);
+ tt_int_op(258, OP_EQ, socks->port);
+
+ tt_int_op(0, OP_EQ, buf_datalen(buf));
socks_request_clear(socks);
/* SOCKS 5 Send RESOLVE_PTR [F1] for IP address 2.2.2.5 */
ADD_DATA(buf, "\x05\x01\x00");
ADD_DATA(buf, "\x05\xF1\x00\x01\x02\x02\x02\x05\x01\x03");
- tt_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
- get_options()->SafeSocks) == 1);
+ tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks),
+ OP_EQ, 1);
tt_int_op(5,OP_EQ, socks->socks_version);
tt_int_op(2,OP_EQ, socks->replylen);
tt_int_op(5,OP_EQ, socks->reply[0]);
@@ -380,9 +480,9 @@ test_socks_5_authenticate_with_data(void *ptr)
/* SOCKS 5 Send username/password */
/* SOCKS 5 Send CONNECT [01] to IP address 2.2.2.2:4369 */
ADD_DATA(buf, "\x01\x02me\x03you\x05\x01\x00\x01\x02\x02\x02\x02\x11\x11");
- tt_assert(fetch_from_buf_socks(buf, socks,
- get_options()->TestSocks,
- get_options()->SafeSocks) == 1);
+ tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks),
+ OP_EQ, 1);
tt_int_op(5,OP_EQ, socks->socks_version);
tt_int_op(2,OP_EQ, socks->replylen);
tt_int_op(1,OP_EQ, socks->reply[0]);
@@ -400,6 +500,48 @@ test_socks_5_authenticate_with_data(void *ptr)
;
}
+/** Try to negotiate an unsupported authentication type */
+static void
+test_socks_5_auth_unsupported_type(void *ptr)
+{
+ SOCKS_TEST_INIT();
+
+ /* None of these authentication types are recognized. */
+ ADD_DATA(buf, "\x05\x03\x99\x21\x10");
+ tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks),
+ OP_EQ, -1);
+ tt_int_op(0,OP_EQ, socks->socks_version);
+ tt_int_op(2,OP_EQ, socks->replylen);
+ tt_int_op(5,OP_EQ, socks->reply[0]);
+ tt_int_op(0xff,OP_EQ, socks->reply[1]);
+
+ done:
+ ;
+}
+
+/** Try to negotiate an unsupported version of username/password auth. */
+static void
+test_socks_5_auth_unsupported_version(void *ptr)
+{
+ SOCKS_TEST_INIT();
+
+ /* Negotiate username/password */
+ ADD_DATA(buf, "\x05\x01\x02");
+ tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks),
+ OP_EQ, 0);
+ tt_int_op(0,OP_EQ, buf_datalen(buf)); /* buf should be drained */
+ /* Now, suggest an unrecognized username/password version */
+ ADD_DATA(buf, "\x02\x05" "hello" "\x05" "world");
+ tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks),
+ OP_EQ, -1);
+
+ done:
+ ;
+}
+
/** Perform SOCKS 5 authentication before method negotiated */
static void
test_socks_5_auth_before_negotiation(void *ptr)
@@ -408,9 +550,9 @@ test_socks_5_auth_before_negotiation(void *ptr)
/* SOCKS 5 Send username/password */
ADD_DATA(buf, "\x01\x02me\x02me");
- tt_assert(fetch_from_buf_socks(buf, socks,
- get_options()->TestSocks,
- get_options()->SafeSocks) == -1);
+ tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks),
+ OP_EQ, -1);
tt_int_op(0,OP_EQ, socks->socks_version);
tt_int_op(0,OP_EQ, socks->replylen);
tt_int_op(0,OP_EQ, socks->reply[0]);
@@ -492,20 +634,397 @@ test_socks_5_malformed_commands(void *ptr)
;
}
+static void
+test_socks_5_bad_arguments(void *ptr)
+{
+ SOCKS_TEST_INIT();
+ setup_capture_of_logs(LOG_DEBUG);
+
+ /* Socks5, bogus hostname */
+ ADD_DATA(buf, "\x05\x01\x00" "\x05\x01\x00\x03\x03" "---" "\x00\x50" );
+ tt_int_op(fetch_from_buf_socks(buf, socks, 1, 0), OP_EQ, -1);
+ buf_clear(buf);
+ expect_log_msg_containing("Your application (using socks5 to port 80) "
+ "gave Tor a malformed hostname: ");
+ mock_clean_saved_logs();
+ socks_request_clear(socks);
+
+ done:
+ teardown_capture_of_logs();
+}
+
+/** check for correct behavior when the socks command has not arrived. */
+static void
+test_socks_truncated(void *ptr)
+{
+ const struct {
+ enum { NONE, AUTH, ALL } setup;
+ const char *body;
+ size_t len;
+ } commands[] = {
+ /* SOCKS4 */
+ /* Connect, to an IP. */
+ { NONE, "\x04\x01\x05\x05\x01\x02\x03\x04\x00", 9},
+ /* Connect, to an IP, with authentication. */
+ { NONE, "\x04\x01\x05\x05\x01\x02\x03\x04hello\x00", 14},
+ /* SOCKS4A */
+ /* Connect, to a hostname */
+ { NONE, "\x04\x01\x09\x09\x00\x00\x00\x01\x00www.example.com\x00", 25},
+ /* Connect, to a hostname, with authentication */
+ { NONE, "\x04\x01\x09\x09\x00\x00\x00\x01hi\x00www.example.com\x00", 27},
+ /* SOCKS5 */
+ /* initial handshake */
+ { NONE, "\x05\x00", 2 },
+ /* no-auth handshake */
+ { NONE, "\x05\x03\x99\x21\x10", 5 },
+ /* SOCSK5, username-password, all empty. */
+ { AUTH, "\x01\x00\x00", 3 },
+ /* SOCSK5, username-password, 1 char each. */
+ { AUTH, "\x01\x01x\x01y", 5 },
+ /* SOCSK5, username-password, max length. */
+ { AUTH, "\x01\xff"
+ "Ogni tempo ha il suo fascismo: se ne notano i segni premonitori "
+ "dovunque la concentrazione di potere nega al cittadino la "
+ "possibilit\xc3\xa0 e la capacit\xc3\xa0 di esprimere ed attuare la "
+ "sua volont\xc3\xa0. A questo si arriva in molti modi, non "
+ "necessariamente col terror"
+ "\xff"
+ "e dell'intimidazione poliziesca, ma anche negando o distorcendo "
+ "l'informazione, inquinando la giustizia, paralizzando la scuola, "
+ "diffondendo in molti modi sottili la nostalgia per un mondo in cui "
+ "regnava sovrano l'ordine, ed in cui la sicurezza dei pochi "
+ /* privilegiati riposava sul lavoro forzato e sul silenzio forzato dei
+ molti. -- Primo Levi */ , 513 },
+ /* Socks5, IPv4 address */
+ { ALL, "\x05\x01\x00\x01\x01\x02\x03\x04\x20\x20", 10 },
+ /* Socks5, IPv6 address */
+ { ALL, "\x05\x01\x00\x04"
+ "\x49\x20\x48\x41\x5a\x20\x45\x41\x53\x54\x45\x52\x20\x45\x47\x47"
+ "\x20\x20", 22 },
+ /* Socks5, hostname, empty. */
+ { ALL, "\x05\x01\x00\x03" "\x00" "\x00\x50", 7 },
+ /* Socks5, hostname, moderate. */
+ { ALL, "\x05\x01\x00\x03" "\x11" "onion.example.com" "\x00\x50", 24 },
+ /* Socks5, hostname, maximum. */
+ { ALL, "\x05\x01\x00\x03" "\xff"
+ "whatsoever.I.shall.see.or.hear.in.the.course.of.my.profession.as.well."
+ "as.outside.my.profession.in.my.intercourse.with.men.if.it.be.what."
+ "should.not.be.published.abroad.I.will.never.divulge.holding.such."
+ "things.to.be.holy.secrets.x.hippocratic.oath.wikipedia"
+ "\x00\x50", 262 },
+ };
+ unsigned i, j;
+ SOCKS_TEST_INIT();
+ for (i = 0; i < ARRAY_LENGTH(commands); ++i) {
+ for (j = 0; j < commands[i].len; ++j) {
+ switch (commands[i].setup) {
+ default: /* Falls through */
+ case NONE:
+ /* This test calls for no setup on the socks state. */
+ break;
+ case AUTH:
+ /* This test calls for the socks state to be waiting for
+ * username/password authentication */
+ ADD_DATA(buf, "\x05\x01\x02");
+ tt_int_op(0, OP_EQ, fetch_from_buf_socks(buf, socks, 0, 0));
+ tt_int_op(0, OP_EQ, buf_datalen(buf));
+ break;
+ case ALL:
+ /* This test calls for the socks state to be waiting for
+ * the connection request */
+ ADD_DATA(buf, "\x05\x01\x00");
+ tt_int_op(0, OP_EQ, fetch_from_buf_socks(buf, socks, 0, 0));
+ tt_int_op(0, OP_EQ, buf_datalen(buf));
+ }
+
+ TT_BLATHER(("Checking command %u, length %u, omitting char %u", i, j,
+ (unsigned)commands[i].body[j]));
+ buf_add(buf, commands[i].body, j);
+ /* This should return 0 meaning "not done yet" */
+ tt_int_op(0, OP_EQ, fetch_from_buf_socks(buf, socks, 0, 0));
+ tt_uint_op(j, OP_EQ, buf_datalen(buf)); /* Nothing was drained */
+ buf_clear(buf);
+ socks_request_free(testdata->req);
+ socks = testdata->req = socks_request_new();
+ }
+ }
+ done:
+ ;
+}
+
+static void
+test_socks_wrong_protocol(void *ptr)
+{
+ SOCKS_TEST_INIT();
+ setup_capture_of_logs(LOG_DEBUG);
+
+ /* HTTP request. */
+ ADD_DATA(buf, "GET /index.html HTTP/1.0" );
+ tt_int_op(fetch_from_buf_socks(buf, socks, 1, 0), OP_EQ, -1);
+ buf_clear(buf);
+ expect_log_msg_containing("Socks version 71 not recognized. "
+ "(This port is not an HTTP proxy;");
+ mock_clean_saved_logs();
+ socks_request_clear(socks);
+
+ done:
+ teardown_capture_of_logs();
+}
+
+/* Check our client-side socks4 parsing (that is to say, our parsing of
+ * server responses).
+ */
+static void
+test_socks_client_v4(void *arg)
+{
+ (void)arg;
+ buf_t *buf = buf_new();
+ char *reason = NULL;
+
+ /* Legit socks4 response, success */
+ ADD_DATA(buf, "\x04\x5a\x20\x25\x01\x02\x03\x04");
+ tt_int_op(1, OP_EQ,
+ fetch_from_buf_socks_client(buf, PROXY_SOCKS4_WANT_CONNECT_OK,
+ &reason));
+ tt_ptr_op(reason, OP_EQ, NULL);
+ tt_int_op(buf_datalen(buf), OP_EQ, 0);
+
+ /* Legit socks4 response, failure. */
+ ADD_DATA(buf, "\x04\x5b\x20\x25\x01\x02\x03\x04");
+ tt_int_op(-1, OP_EQ,
+ fetch_from_buf_socks_client(buf, PROXY_SOCKS4_WANT_CONNECT_OK,
+ &reason));
+ tt_ptr_op(reason, OP_NE, NULL);
+ tt_str_op(reason, OP_EQ, "server rejected connection");
+
+ done:
+ buf_free(buf);
+ tor_free(reason);
+}
+
+/* Check our client-side socks5 authentication-negotiation parsing (that is to
+ * say, our parsing of server responses).
+ */
+static void
+test_socks_client_v5_auth(void *arg)
+{
+ (void)arg;
+ buf_t *buf = buf_new();
+ char *reason = NULL;
+
+ /* Legit socks5 responses, got a method we like. */
+ ADD_DATA(buf, "\x05\x00");
+ tt_int_op(1, OP_EQ,
+ fetch_from_buf_socks_client(buf,
+ PROXY_SOCKS5_WANT_AUTH_METHOD_NONE,
+ &reason));
+ tt_ptr_op(reason, OP_EQ, NULL);
+ tt_int_op(buf_datalen(buf), OP_EQ, 0);
+
+ /* Same, but we wanted something else. */
+ ADD_DATA(buf, "\x05\x00");
+ tt_int_op(1, OP_EQ,
+ fetch_from_buf_socks_client(buf,
+ PROXY_SOCKS5_WANT_AUTH_METHOD_RFC1929,
+ &reason));
+ tt_ptr_op(reason, OP_EQ, NULL);
+ tt_int_op(buf_datalen(buf), OP_EQ, 0);
+
+ /* Same, and they offered a password. */
+ ADD_DATA(buf, "\x05\x02");
+ tt_int_op(2, OP_EQ,
+ fetch_from_buf_socks_client(buf,
+ PROXY_SOCKS5_WANT_AUTH_METHOD_RFC1929,
+ &reason));
+ tt_ptr_op(reason, OP_EQ, NULL);
+ tt_int_op(buf_datalen(buf), OP_EQ, 0);
+
+ /* They rejected our method, or selected something we don't know. */
+ ADD_DATA(buf, "\x05\xff");
+ tt_int_op(-1, OP_EQ,
+ fetch_from_buf_socks_client(buf,
+ PROXY_SOCKS5_WANT_AUTH_METHOD_NONE,
+ &reason));
+ tt_str_op(reason, OP_EQ, "server doesn't support any of our available "
+ "authentication methods");
+ buf_clear(buf);
+ tor_free(reason);
+ ADD_DATA(buf, "\x05\xff");
+ tt_int_op(-1, OP_EQ,
+ fetch_from_buf_socks_client(buf,
+ PROXY_SOCKS5_WANT_AUTH_METHOD_RFC1929,
+ &reason));
+ tt_str_op(reason, OP_EQ, "server doesn't support any of our available "
+ "authentication methods");
+ tor_free(reason);
+ buf_clear(buf);
+
+ /* Now check for authentication responses: check success and failure. */
+ ADD_DATA(buf, "\x01\x00");
+ tt_int_op(1, OP_EQ,
+ fetch_from_buf_socks_client(buf,
+ PROXY_SOCKS5_WANT_AUTH_RFC1929_OK,
+ &reason));
+ tt_ptr_op(reason, OP_EQ, NULL);
+ tt_int_op(buf_datalen(buf), OP_EQ, 0);
+
+ ADD_DATA(buf, "\x01\xf0");
+ tt_int_op(-1, OP_EQ,
+ fetch_from_buf_socks_client(buf,
+ PROXY_SOCKS5_WANT_AUTH_RFC1929_OK,
+ &reason));
+ tt_ptr_op(reason, OP_NE, NULL);
+ tt_str_op(reason, OP_EQ, "authentication failed");
+
+ done:
+ buf_free(buf);
+ tor_free(reason);
+}
+
+/* Check our client-side socks5 connect parsing (that is to say, our parsing
+ * of server responses).
+ */
+static void
+test_socks_client_v5_connect(void *arg)
+{
+ (void)arg;
+ buf_t *buf = buf_new();
+ char *reason = NULL;
+
+ /* Legit socks5 responses, success, ipv4. */
+ ADD_DATA(buf, "\x05\x00\x00\x01\x01\x02\x03\x04\x00\x05");
+ tt_int_op(1, OP_EQ,
+ fetch_from_buf_socks_client(buf,
+ PROXY_SOCKS5_WANT_CONNECT_OK,
+ &reason));
+ tt_ptr_op(reason, OP_EQ, NULL);
+ tt_int_op(buf_datalen(buf), OP_EQ, 0);
+
+ /* Legit socks5 responses, success, ipv6. */
+ ADD_DATA(buf, "\x05\x00\x00\x04"
+ "abcdefghijklmnop"
+ "\x00\x05");
+ tt_int_op(1, OP_EQ,
+ fetch_from_buf_socks_client(buf,
+ PROXY_SOCKS5_WANT_CONNECT_OK,
+ &reason));
+ tt_ptr_op(reason, OP_EQ, NULL);
+ tt_int_op(buf_datalen(buf), OP_EQ, 0);
+
+ /* Legit socks5 responses, success, hostname. */
+ ADD_DATA(buf, "\x05\x00\x00\x03\x12"
+ "gopher.example.com"
+ "\x00\x05");
+ tt_int_op(1, OP_EQ,
+ fetch_from_buf_socks_client(buf,
+ PROXY_SOCKS5_WANT_CONNECT_OK,
+ &reason));
+ tt_ptr_op(reason, OP_EQ, NULL);
+ tt_int_op(buf_datalen(buf), OP_EQ, 0);
+
+ /* Legit socks5 responses, failure, hostname. */
+ ADD_DATA(buf, "\x05\x03\x00\x03\x12"
+ "gopher.example.com"
+ "\x00\x05");
+ tt_int_op(-1, OP_EQ,
+ fetch_from_buf_socks_client(buf,
+ PROXY_SOCKS5_WANT_CONNECT_OK,
+ &reason));
+ tt_ptr_op(reason, OP_NE, NULL);
+ tt_str_op(reason, OP_EQ, "Network unreachable");
+ tor_free(reason);
+ buf_clear(buf);
+
+ /* Bogus socks5 responses: what is address type 0x17? */
+ ADD_DATA(buf, "\x05\x03\x00\x17\x12 blah blah");
+ tt_int_op(-1, OP_EQ,
+ fetch_from_buf_socks_client(buf,
+ PROXY_SOCKS5_WANT_CONNECT_OK,
+ &reason));
+ tt_ptr_op(reason, OP_NE, NULL);
+ tt_str_op(reason, OP_EQ, "invalid response to connect request");
+ buf_clear(buf);
+
+ done:
+ buf_free(buf);
+ tor_free(reason);
+}
+
+static void
+test_socks_client_truncated(void *arg)
+{
+ (void)arg;
+ buf_t *buf = buf_new();
+ char *reason = NULL;
+
+#define S(str) str, (sizeof(str)-1)
+ const struct {
+ int state;
+ const char *body;
+ size_t len;
+ } replies[] = {
+ { PROXY_SOCKS4_WANT_CONNECT_OK, S("\x04\x5a\x20\x25\x01\x02\x03\x04") },
+ { PROXY_SOCKS4_WANT_CONNECT_OK, S("\x04\x5b\x20\x25\x01\x02\x03\x04") },
+ { PROXY_SOCKS5_WANT_AUTH_METHOD_NONE, S("\x05\x00") },
+ { PROXY_SOCKS5_WANT_AUTH_METHOD_RFC1929, S("\x05\x00") },
+ { PROXY_SOCKS5_WANT_AUTH_RFC1929_OK, S("\x01\x00") },
+ { PROXY_SOCKS5_WANT_CONNECT_OK,
+ S("\x05\x00\x00\x01\x01\x02\x03\x04\x00\x05") },
+ { PROXY_SOCKS5_WANT_CONNECT_OK,
+ S("\x05\x00\x00\x04" "abcdefghijklmnop" "\x00\x05") },
+ { PROXY_SOCKS5_WANT_CONNECT_OK,
+ S("\x05\x00\x00\x03\x12" "gopher.example.com" "\x00\x05") },
+ { PROXY_SOCKS5_WANT_CONNECT_OK,
+ S("\x05\x03\x00\x03\x12" "gopher.example.com""\x00\x05") },
+ { PROXY_SOCKS5_WANT_CONNECT_OK,
+ S("\x05\x03\x00\x17") },
+ };
+ unsigned i, j;
+ for (i = 0; i < ARRAY_LENGTH(replies); ++i) {
+ for (j = 0; j < replies[i].len; ++j) {
+ TT_BLATHER(("Checking command %u, length %u", i, j));
+ buf_add(buf, replies[i].body, j);
+ /* This should return 0 meaning "not done yet" */
+ tt_int_op(0, OP_EQ,
+ fetch_from_buf_socks_client(buf, replies[i].state, &reason));
+ tt_uint_op(j, OP_EQ, buf_datalen(buf)); /* Nothing was drained */
+ buf_clear(buf);
+ tt_ptr_op(reason, OP_EQ, NULL);
+ }
+ }
+
+ done:
+ tor_free(reason);
+ buf_free(buf);
+}
+
#define SOCKSENT(name) \
{ #name, test_socks_##name, TT_FORK, &socks_setup, NULL }
struct testcase_t socks_tests[] = {
SOCKSENT(4_unsupported_commands),
SOCKSENT(4_supported_commands),
+ SOCKSENT(4_bad_arguments),
SOCKSENT(5_unsupported_commands),
SOCKSENT(5_supported_commands),
SOCKSENT(5_no_authenticate),
+ SOCKSENT(5_auth_unsupported_type),
+ SOCKSENT(5_auth_unsupported_version),
SOCKSENT(5_auth_before_negotiation),
SOCKSENT(5_authenticate),
SOCKSENT(5_authenticate_with_data),
SOCKSENT(5_malformed_commands),
+ SOCKSENT(5_bad_arguments),
+
+ SOCKSENT(truncated),
+
+ SOCKSENT(wrong_protocol),
+
+ { "client/v4", test_socks_client_v4, TT_FORK, NULL, NULL },
+ { "client/v5_auth", test_socks_client_v5_auth, TT_FORK, NULL, NULL },
+ { "client/v5_connect", test_socks_client_v5_connect, TT_FORK, NULL, NULL },
+ { "client/truncated", test_socks_client_truncated, TT_FORK, NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_status.c b/src/test/test_status.c
index a3b1a2af87..f86f8e3b9e 100644
--- a/src/test/test_status.c
+++ b/src/test/test_status.c
@@ -889,8 +889,8 @@ NS(logv)(int severity, log_domain_mask_t domain, const char *funcname,
tt_str_op(format, OP_EQ,
"Average packaged cell fullness: %2.3f%%. "
"TLS write overhead: %.f%%");
- tt_double_op(fabs(va_arg(ap, double) - 50.0), <=, DBL_EPSILON);
- tt_double_op(fabs(va_arg(ap, double) - 0.0), <=, DBL_EPSILON);
+ tt_double_op(fabs(va_arg(ap, double) - 50.0), OP_LE, DBL_EPSILON);
+ tt_double_op(fabs(va_arg(ap, double) - 0.0), OP_LE, DBL_EPSILON);
break;
default:
tt_abort_msg("unexpected call to logv()"); // TODO: prettyprint args
@@ -1039,7 +1039,7 @@ NS(logv)(int severity, log_domain_mask_t domain,
"Average packaged cell fullness: %2.3f%%. "
"TLS write overhead: %.f%%");
tt_int_op(fabs(va_arg(ap, double) - 100.0) <= DBL_EPSILON, OP_EQ, 1);
- tt_double_op(fabs(va_arg(ap, double) - 100.0), <=, DBL_EPSILON);
+ tt_double_op(fabs(va_arg(ap, double) - 100.0), OP_LE, DBL_EPSILON);
break;
default:
tt_abort_msg("unexpected call to logv()"); // TODO: prettyprint args
diff --git a/src/test/test_storagedir.c b/src/test/test_storagedir.c
new file mode 100644
index 0000000000..a27074c21f
--- /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_ptr_op(labels->next->next->next, OP_EQ, 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 e12205bb2e..fe36d8c6e6 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"
@@ -71,7 +71,7 @@ check_can_bind_low_ports(void)
return -1;
}
-#endif
+#endif /* !defined(_WIN32) */
int
main(int argc, char **argv)
@@ -83,7 +83,7 @@ main(int argc, char **argv)
fprintf(stderr, "This test is not supported on your OS.\n");
return 77;
-#else
+#else /* !(defined(_WIN32)) */
const char *username;
const char *testname;
if (argc != 3) {
@@ -174,7 +174,7 @@ main(int argc, char **argv)
}
cap_free(caps);
}
-#endif
+#endif /* defined(HAVE_LINUX_CAPABILITIES) */
break;
default:
fprintf(stderr, "Unsupported test '%s'\n", testname);
@@ -187,6 +187,6 @@ main(int argc, char **argv)
}
return (okay ? 0 : 1);
-#endif
+#endif /* defined(_WIN32) */
}
diff --git a/src/test/test_threads.c b/src/test/test_threads.c
index ebbc95c7ca..ed6d8f04aa 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"
@@ -139,8 +139,8 @@ test_threads_basic(void *arg)
!strcmp(strmap_get(thread_test_strmap_, "thread 2"),
strmap_get(thread_test_strmap_, "last to run")));
- tt_int_op(thread_fns_failed, ==, 0);
- tt_int_op(thread_fn_tid1, !=, thread_fn_tid2);
+ tt_int_op(thread_fns_failed, OP_EQ, 0);
+ tt_int_op(thread_fn_tid1, OP_NE, thread_fn_tid2);
done:
tor_free(s1);
@@ -275,14 +275,14 @@ test_threads_conditionvar(void *arg)
SPIN();
tor_mutex_release(ti->mutex);
- tt_int_op(ti->value, ==, 1337);
+ tt_int_op(ti->value, OP_EQ, 1337);
if (!timeout) {
- tt_int_op(ti->n_shutdown, ==, 4);
+ tt_int_op(ti->n_shutdown, OP_EQ, 4);
} else {
tor_sleep_msec(200);
tor_mutex_acquire(ti->mutex);
- tt_int_op(ti->n_shutdown, ==, 2);
- tt_int_op(ti->n_timeouts, ==, 2);
+ tt_int_op(ti->n_shutdown, OP_EQ, 2);
+ tt_int_op(ti->n_timeouts, OP_EQ, 2);
tor_mutex_release(ti->mutex);
}
diff --git a/src/test/test_tortls.c b/src/test/test_tortls.c
index 4febd82ddc..9a6ebeb699 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"
@@ -62,7 +63,7 @@ fake_num_ciphers(void)
{
return 0;
}
-#endif
+#endif /* !defined(OPENSSL_OPAQUE) */
static void
test_tortls_errno_to_tls_error(void *data)
@@ -135,7 +136,7 @@ test_tortls_tor_tls_new(void *data)
SSL_CTX_free(client_tls_context->ctx);
client_tls_context->ctx = NULL;
tls = tor_tls_new(-1, 0);
- tt_assert(!tls);
+ tt_ptr_op(tls, OP_EQ, NULL);
#ifndef OPENSSL_OPAQUE
method = give_me_a_test_method();
@@ -143,8 +144,8 @@ test_tortls_tor_tls_new(void *data)
method->num_ciphers = fake_num_ciphers;
client_tls_context->ctx = ctx;
tls = tor_tls_new(-1, 0);
- tt_assert(!tls);
-#endif
+ tt_ptr_op(tls, OP_EQ, NULL);
+#endif /* !defined(OPENSSL_OPAQUE) */
done:
UNMOCK(tor_tls_cert_matches_key);
@@ -375,7 +376,7 @@ test_tortls_log_one_error(void *ignored)
tor_tls_log_one_error(tls, ERR_PACK(1, 2, SSL_R_RECORD_TOO_LARGE),
LOG_WARN, 0, NULL);
expect_log_severity(LOG_INFO);
-#endif
+#endif /* !defined(OPENSSL_1_1_API) */
mock_clean_saved_logs();
tor_tls_log_one_error(tls, ERR_PACK(1, 2, SSL_R_UNKNOWN_PROTOCOL),
@@ -489,7 +490,7 @@ test_tortls_get_error(void *ignored)
tor_free(tls);
SSL_CTX_free(ctx);
}
-#endif
+#endif /* !defined(OPENSSL_OPAQUE) */
static void
test_tortls_always_accept_verify_cb(void *ignored)
@@ -519,7 +520,7 @@ test_tortls_x509_cert_free(void *ignored)
cert->encoded = tor_malloc_zero(1);
tor_x509_cert_free(cert);
}
-#endif
+#endif /* !defined(OPENSSL_OPAQUE) */
static void
test_tortls_x509_cert_get_id_digests(void *ignored)
@@ -662,7 +663,7 @@ test_tortls_cert_get_key(void *ignored)
tor_free(cert);
crypto_pk_free(res);
}
-#endif
+#endif /* !defined(OPENSSL_OPAQUE) */
static void
test_tortls_get_my_client_auth_key(void *ignored)
@@ -744,7 +745,7 @@ get_cipher_by_name(const char *name)
return NULL;
}
-#endif
+#endif /* !defined(HAVE_SSL_GET_CLIENT_CIPHERS) */
#ifndef OPENSSL_OPAQUE
static void
@@ -879,7 +880,7 @@ test_tortls_classify_client_ciphers(void *ignored)
tor_free(tls);
SSL_CTX_free(ctx);
}
-#endif
+#endif /* !defined(OPENSSL_OPAQUE) */
static void
test_tortls_client_is_using_v2_ciphers(void *ignored)
@@ -921,7 +922,7 @@ test_tortls_client_is_using_v2_ciphers(void *ignored)
done:
SSL_free(ssl);
SSL_CTX_free(ctx);
-#endif
+#endif /* defined(HAVE_SSL_GET_CLIENT_CIPHERS) */
}
#ifndef OPENSSL_OPAQUE
@@ -937,7 +938,7 @@ fixed_try_to_extract_certs_from_tls(int severity, tor_tls_t *tls,
*cert_out = fixed_try_to_extract_certs_from_tls_cert_out_result;
*id_cert_out = fixed_try_to_extract_certs_from_tls_id_cert_out_result;
}
-#endif
+#endif /* !defined(OPENSSL_OPAQUE) */
#ifndef OPENSSL_OPAQUE
static const char* notCompletelyValidCertString =
@@ -956,7 +957,7 @@ static const char* notCompletelyValidCertString =
"jC9UeuErhaA/zzWi8ewMTFZW/WshOrm3fNvcMrMLKtH534JKvcdMg6qIdjTFINIr\n"
"evnAhf0cwULaebn+lMs8Pdl7y37+sfluVok=\n"
"-----END CERTIFICATE-----\n";
-#endif
+#endif /* !defined(OPENSSL_OPAQUE) */
static const char* validCertString = "-----BEGIN CERTIFICATE-----\n"
"MIIDpTCCAY0CAg3+MA0GCSqGSIb3DQEBBQUAMF4xCzAJBgNVBAYTAlVTMREwDwYD\n"
@@ -1079,7 +1080,7 @@ test_tortls_verify(void *ignored)
tor_free(tls);
tor_free(k);
}
-#endif
+#endif /* !defined(OPENSSL_OPAQUE) */
#ifndef OPENSSL_OPAQUE
static void
@@ -1092,13 +1093,13 @@ test_tortls_check_lifetime(void *ignored)
time_t now = time(NULL);
tls = tor_malloc_zero(sizeof(tor_tls_t));
- ret = tor_tls_check_lifetime(LOG_WARN, tls, 0, 0);
+ ret = tor_tls_check_lifetime(LOG_WARN, tls, time(NULL), 0, 0);
tt_int_op(ret, OP_EQ, -1);
tls->ssl = tor_malloc_zero(sizeof(SSL));
tls->ssl->session = tor_malloc_zero(sizeof(SSL_SESSION));
tls->ssl->session->peer = validCert;
- ret = tor_tls_check_lifetime(LOG_WARN, tls, 0, 0);
+ ret = tor_tls_check_lifetime(LOG_WARN, tls, time(NULL), 0, 0);
tt_int_op(ret, OP_EQ, 0);
ASN1_STRING_free(validCert->cert_info->validity->notBefore);
@@ -1106,10 +1107,10 @@ test_tortls_check_lifetime(void *ignored)
ASN1_STRING_free(validCert->cert_info->validity->notAfter);
validCert->cert_info->validity->notAfter = ASN1_TIME_set(NULL, now+60);
- ret = tor_tls_check_lifetime(LOG_WARN, tls, 0, -1000);
+ ret = tor_tls_check_lifetime(LOG_WARN, tls, time(NULL), 0, -1000);
tt_int_op(ret, OP_EQ, -1);
- ret = tor_tls_check_lifetime(LOG_WARN, tls, -1000, 0);
+ ret = tor_tls_check_lifetime(LOG_WARN, tls, time(NULL), -1000, 0);
tt_int_op(ret, OP_EQ, -1);
done:
@@ -1118,7 +1119,7 @@ test_tortls_check_lifetime(void *ignored)
tor_free(tls);
X509_free(validCert);
}
-#endif
+#endif /* !defined(OPENSSL_OPAQUE) */
#ifndef OPENSSL_OPAQUE
static int fixed_ssl_pending_result = 0;
@@ -1153,7 +1154,7 @@ test_tortls_get_pending_bytes(void *ignored)
tor_free(tls->ssl);
tor_free(tls);
}
-#endif
+#endif /* !defined(OPENSSL_OPAQUE) */
static void
test_tortls_get_forced_write_size(void *ignored)
@@ -1276,13 +1277,13 @@ test_tortls_SSL_SESSION_get_master_key(void *ignored)
tt_int_op(out[0], OP_EQ, 43);
done:
-#endif
+#endif /* !defined(HAVE_SSL_SESSION_GET_MASTER_KEY) */
tor_free(tls->ssl->session);
tor_free(tls->ssl);
tor_free(tls);
tor_free(out);
}
-#endif
+#endif /* !defined(OPENSSL_OPAQUE) */
#ifndef OPENSSL_OPAQUE
static void
@@ -1290,7 +1291,7 @@ test_tortls_get_tlssecrets(void *ignored)
{
(void)ignored;
int ret;
- uint8_t *secret_out = tor_malloc_zero(DIGEST256_LEN);;
+ uint8_t *secret_out = tor_malloc_zero(DIGEST256_LEN);
tor_tls_t *tls;
tls = tor_malloc_zero(sizeof(tor_tls_t));
tls->ssl = tor_malloc_zero(sizeof(SSL));
@@ -1308,7 +1309,7 @@ test_tortls_get_tlssecrets(void *ignored)
tor_free(tls->ssl);
tor_free(tls);
}
-#endif
+#endif /* !defined(OPENSSL_OPAQUE) */
#ifndef OPENSSL_OPAQUE
static void
@@ -1350,7 +1351,7 @@ test_tortls_get_buffer_sizes(void *ignored)
tt_int_op(rbuf_c, OP_EQ, 1);
tt_int_op(wbuf_c, OP_EQ, 2);
-#endif
+#endif /* OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) */
done:
tor_free(tls->ssl->s3->rbuf.buf);
@@ -1359,7 +1360,7 @@ test_tortls_get_buffer_sizes(void *ignored)
tor_free(tls->ssl);
tor_free(tls);
}
-#endif
+#endif /* !defined(OPENSSL_OPAQUE) */
static void
test_tortls_evaluate_ecgroup_for_tls(void *ignored)
@@ -1378,6 +1379,7 @@ test_tortls_evaluate_ecgroup_for_tls(void *ignored)
ret = evaluate_ecgroup_for_tls("P224");
// tt_int_op(ret, OP_EQ, 1); This varies between machines
+ tt_assert(ret == 0 || ret == 1);
done:
(void)0;
@@ -1450,7 +1452,7 @@ test_tortls_try_to_extract_certs_from_tls(void *ignored)
X509_free(c1);
X509_free(c2);
}
-#endif
+#endif /* !defined(OPENSSL_OPAQUE) */
#ifndef OPENSSL_OPAQUE
static void
@@ -1482,7 +1484,7 @@ test_tortls_get_peer_cert(void *ignored)
tor_free(tls);
X509_free(cert);
}
-#endif
+#endif /* !defined(OPENSSL_OPAQUE) */
#ifndef OPENSSL_OPAQUE
static void
@@ -1512,7 +1514,7 @@ test_tortls_peer_has_cert(void *ignored)
tor_free(tls);
X509_free(cert);
}
-#endif
+#endif /* !defined(OPENSSL_OPAQUE) */
static void
test_tortls_is_server(void *ignored)
@@ -1572,7 +1574,7 @@ test_tortls_session_secret_cb(void *ignored)
SSL_CTX_free(ctx);
tor_free(tls);
}
-#endif
+#endif /* !defined(OPENSSL_OPAQUE) */
#ifndef OPENSSL_OPAQUE
/* TODO: It seems block_renegotiation and unblock_renegotiation and
@@ -1623,7 +1625,7 @@ test_tortls_unblock_renegotiation(void *ignored)
tor_free(tls->ssl);
tor_free(tls);
}
-#endif
+#endif /* !defined(OPENSSL_OPAQUE) */
#ifndef OPENSSL_OPAQUE
static void
@@ -1642,7 +1644,7 @@ test_tortls_assert_renegotiation_unblocked(void *ignored)
tor_free(tls->ssl);
tor_free(tls);
}
-#endif
+#endif /* !defined(OPENSSL_OPAQUE) */
static void
test_tortls_set_logged_address(void *ignored)
@@ -1697,7 +1699,7 @@ test_tortls_set_renegotiate_callback(void *ignored)
tor_free(tls->ssl);
tor_free(tls);
}
-#endif
+#endif /* !defined(OPENSSL_OPAQUE) */
#ifndef OPENSSL_OPAQUE
static SSL_CIPHER *fixed_cipher1 = NULL;
@@ -1715,7 +1717,7 @@ fake_get_cipher(unsigned ncipher)
return NULL;
}
}
-#endif
+#endif /* !defined(OPENSSL_OPAQUE) */
#ifndef OPENSSL_OPAQUE
static void
@@ -1785,7 +1787,7 @@ test_tortls_find_cipher_by_id(void *ignored)
SSL_CTX_free(ctx);
tor_free(fixed_cipher1);
}
-#endif
+#endif /* !defined(OPENSSL_OPAQUE) */
#ifndef OPENSSL_OPAQUE
static void
@@ -1813,7 +1815,7 @@ test_tortls_debug_state_callback(void *ignored)
tor_free(buf);
tor_free(ssl);
}
-#endif
+#endif /* !defined(OPENSSL_OPAQUE) */
#ifndef OPENSSL_OPAQUE
static void
@@ -1877,7 +1879,7 @@ test_tortls_server_info_callback(void *ignored)
SSL_CTX_free(ctx);
tor_free(tls);
}
-#endif
+#endif /* !defined(OPENSSL_OPAQUE) */
#ifndef OPENSSL_OPAQUE
static int fixed_ssl_read_result_index;
@@ -1918,7 +1920,7 @@ setting_version_and_state_ssl_shutdown(SSL *s)
s->version = SSL2_VERSION;
return fixed_ssl_shutdown_result;
}
-#endif
+#endif /* !defined(LIBRESSL_VERSION_NUMBER) */
static int
dummy_handshake_func(SSL *s)
@@ -2014,7 +2016,7 @@ test_tortls_shutdown(void *ignored)
method->ssl_shutdown = setting_version_and_state_ssl_shutdown;
ret = tor_tls_shutdown(tls);
tt_int_op(ret, OP_EQ, TOR_TLS_ERROR_MISC);
-#endif
+#endif /* !defined(LIBRESSL_VERSION_NUMBER) */
done:
teardown_capture_of_logs();
@@ -2085,7 +2087,7 @@ test_tortls_read(void *ignored)
ret = tor_tls_read(tls, buf, 10);
tt_int_op(ret, OP_EQ, TOR_TLS_CLOSE);
tt_int_op(tls->state, OP_EQ, TOR_TLS_ST_CLOSED);
-#endif
+#endif /* !defined(LIBRESSL_VERSION_NUMBER) */
// TODO: fill up
done:
@@ -2160,7 +2162,7 @@ test_tortls_write(void *ignored)
tor_free(tls);
tor_free(method);
}
-#endif
+#endif /* !defined(OPENSSL_OPAQUE) */
#ifndef OPENSSL_OPAQUE
static int fixed_ssl_accept_result;
@@ -2240,7 +2242,7 @@ test_tortls_handshake(void *ignored)
"(null):SSLv3 write client hello B)\n");
expect_log_msg("TLS error while handshaking: (null) (in system library:"
"connect:SSLv3 write client hello B)\n");
-#endif
+#endif /* 0 */
expect_log_severity(LOG_INFO);
tls->isServer = 0;
@@ -2258,7 +2260,7 @@ test_tortls_handshake(void *ignored)
"(null) (in bignum routines:(null):SSLv3 write client hello B)\n");
expect_log_msg("TLS error while handshaking: "
"(null) (in system library:connect:SSLv3 write client hello B)\n");
-#endif
+#endif /* 0 */
expect_log_severity(LOG_WARN);
done:
@@ -2268,7 +2270,7 @@ test_tortls_handshake(void *ignored)
tor_free(tls);
tor_free(method);
}
-#endif
+#endif /* !defined(OPENSSL_OPAQUE) */
#ifndef OPENSSL_OPAQUE
static void
@@ -2343,7 +2345,7 @@ test_tortls_finish_handshake(void *ignored)
tor_free(method);
teardown_capture_of_logs();
}
-#endif
+#endif /* !defined(OPENSSL_OPAQUE) */
static int fixed_crypto_pk_new_result_index;
static crypto_pk_t *fixed_crypto_pk_new_result[5];
@@ -2568,7 +2570,7 @@ test_tortls_context_new(void *ignored)
UNMOCK(crypto_pk_generate_key_with_bits);
UNMOCK(crypto_pk_new);
}
-#endif
+#endif /* !defined(OPENSSL_OPAQUE) */
static int fixed_crypto_pk_get_evp_pkey_result_index = 0;
static EVP_PKEY *fixed_crypto_pk_get_evp_pkey_result[5];
@@ -2637,7 +2639,7 @@ test_tortls_cert_new(void *ignored)
X509_get_pubkey(cert)->type = EVP_PKEY_DSA;
ret = tor_x509_cert_new(cert);
tt_assert(ret);
-#endif
+#endif /* 0 */
#ifndef OPENSSL_OPAQUE
cert = read_cert_from(validCertString);
@@ -2645,7 +2647,7 @@ test_tortls_cert_new(void *ignored)
cert->cert_info = NULL;
ret = tor_x509_cert_new(cert);
tt_assert(ret);
-#endif
+#endif /* !defined(OPENSSL_OPAQUE) */
done:
tor_x509_cert_free(ret);
@@ -2659,18 +2661,18 @@ test_tortls_cert_is_valid(void *ignored)
tor_x509_cert_t *cert = NULL, *scert = NULL;
scert = tor_malloc_zero(sizeof(tor_x509_cert_t));
- ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, 0);
+ ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 0);
tt_int_op(ret, OP_EQ, 0);
cert = tor_malloc_zero(sizeof(tor_x509_cert_t));
- ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, 0);
+ ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 0);
tt_int_op(ret, OP_EQ, 0);
tor_free(scert);
tor_free(cert);
cert = tor_x509_cert_new(read_cert_from(validCertString));
scert = tor_x509_cert_new(read_cert_from(caCertString));
- ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, 0);
+ ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 0);
tt_int_op(ret, OP_EQ, 1);
#ifndef OPENSSL_OPAQUE
@@ -2681,7 +2683,7 @@ test_tortls_cert_is_valid(void *ignored)
ASN1_TIME_free(cert->cert->cert_info->validity->notAfter);
cert->cert->cert_info->validity->notAfter =
ASN1_TIME_set(NULL, time(NULL)-1000000);
- ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, 0);
+ ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 0);
tt_int_op(ret, OP_EQ, 0);
tor_x509_cert_free(cert);
@@ -2690,9 +2692,9 @@ test_tortls_cert_is_valid(void *ignored)
scert = tor_x509_cert_new(read_cert_from(caCertString));
X509_PUBKEY_free(cert->cert->cert_info->key);
cert->cert->cert_info->key = NULL;
- ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, 1);
+ ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 1);
tt_int_op(ret, OP_EQ, 0);
-#endif
+#endif /* !defined(OPENSSL_OPAQUE) */
#if 0
tor_x509_cert_free(cert);
@@ -2701,7 +2703,7 @@ test_tortls_cert_is_valid(void *ignored)
scert = tor_x509_cert_new(read_cert_from(caCertString));
/* This doesn't actually change the key in the cert. XXXXXX */
BN_one(EVP_PKEY_get1_RSA(X509_get_pubkey(cert->cert))->n);
- ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, 1);
+ ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 1);
tt_int_op(ret, OP_EQ, 0);
tor_x509_cert_free(cert);
@@ -2710,7 +2712,7 @@ test_tortls_cert_is_valid(void *ignored)
scert = tor_x509_cert_new(read_cert_from(caCertString));
/* This doesn't actually change the key in the cert. XXXXXX */
X509_get_pubkey(cert->cert)->type = EVP_PKEY_EC;
- ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, 1);
+ ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 1);
tt_int_op(ret, OP_EQ, 0);
tor_x509_cert_free(cert);
@@ -2719,7 +2721,7 @@ test_tortls_cert_is_valid(void *ignored)
scert = tor_x509_cert_new(read_cert_from(caCertString));
/* This doesn't actually change the key in the cert. XXXXXX */
X509_get_pubkey(cert->cert)->type = EVP_PKEY_EC;
- ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, 0);
+ ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 0);
tt_int_op(ret, OP_EQ, 1);
tor_x509_cert_free(cert);
@@ -2729,9 +2731,9 @@ test_tortls_cert_is_valid(void *ignored)
/* This doesn't actually change the key in the cert. XXXXXX */
X509_get_pubkey(cert->cert)->type = EVP_PKEY_EC;
X509_get_pubkey(cert->cert)->ameth = NULL;
- ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, 0);
+ ret = tor_tls_cert_is_valid(LOG_WARN, cert, scert, time(NULL), 0);
tt_int_op(ret, OP_EQ, 0);
-#endif
+#endif /* 0 */
done:
tor_x509_cert_free(cert);
@@ -2764,7 +2766,7 @@ test_tortls_context_init_one(void *ignored)
{ #name, NULL, TT_SKIP, NULL, NULL }
#else
#define INTRUSIVE_TEST_CASE(name, flags) LOCAL_TEST_CASE(name, flags)
-#endif
+#endif /* defined(OPENSSL_OPAQUE) */
struct testcase_t tortls_tests[] = {
LOCAL_TEST_CASE(errno_to_tls_error, 0),
diff --git a/src/test/test_util.c b/src/test/test_util.c
index 0b707caeeb..0519a4758f 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"
@@ -9,6 +9,7 @@
#define CONTROL_PRIVATE
#define UTIL_PRIVATE
#include "or.h"
+#include "buffers.h"
#include "config.h"
#include "control.h"
#include "test.h"
@@ -69,7 +70,7 @@ test_util_read_until_eof_impl(const char *fname, size_t file_len,
fd = open(fifo_name, O_RDONLY|O_BINARY);
tt_int_op(fd, OP_GE, 0);
str = read_file_to_str_until_eof(fd, read_limit, &sz);
- tt_assert(str != NULL);
+ tt_ptr_op(str, OP_NE, NULL);
if (read_limit < file_len)
tt_int_op(sz, OP_EQ, read_limit);
@@ -366,7 +367,7 @@ test_util_time(void *arg)
* calculations internally, then catches the overflow. */
#define TV_SEC_MAX TIME_MAX
#define TV_SEC_MIN TIME_MIN
-#endif
+#endif /* defined(_WIN32) */
/* Assume tv_usec is an unsigned integer until proven otherwise */
#define TV_USEC_MAX UINT_MAX
@@ -634,13 +635,16 @@ test_util_time(void *arg)
* time_t */
a_time.tm_year = 2039-1900;
#if SIZEOF_TIME_T == 4
+ setup_full_capture_of_logs(LOG_WARN);
tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time));
+ expect_single_log_msg_containing("Result does not fit in tor_timegm");
+ teardown_capture_of_logs();
#elif SIZEOF_TIME_T == 8
t_res = 2178252895UL;
tt_int_op(t_res, OP_EQ, tor_timegm(&a_time));
tor_gmtime_r(&t_res, &b_time);
TM_EQUAL(a_time, b_time);
-#endif
+#endif /* SIZEOF_TIME_T == 4 || ... */
/* Test tor_timegm out of range */
@@ -650,8 +654,7 @@ test_util_time(void *arg)
setup_full_capture_of_logs(LOG_WARN); \
} while (0)
#define CHECK_TIMEGM_WARNING(msg) do { \
- expect_log_msg_containing(msg); \
- tt_int_op(1, OP_EQ, smartlist_len(mock_saved_logs())); \
+ expect_single_log_msg_containing(msg); \
teardown_capture_of_logs(); \
} while (0)
@@ -688,7 +691,7 @@ test_util_time(void *arg)
CAPTURE();
tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time));
CHECK_TIMEGM_ARG_OUT_OF_RANGE();
-#endif
+#endif /* SIZEOF_INT == 4 || SIZEOF_INT == 8 */
#if SIZEOF_INT == 8
a_time.tm_year = -1*(1 << 48);
@@ -710,7 +713,7 @@ test_util_time(void *arg)
CAPTURE();
tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time));
CHECK_TIMEGM_ARG_OUT_OF_RANGE();
-#endif
+#endif /* SIZEOF_INT == 8 */
/* Wrong year >= INT32_MAX - 1900 */
#if SIZEOF_INT == 4 || SIZEOF_INT == 8
@@ -723,7 +726,7 @@ test_util_time(void *arg)
CAPTURE();
tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time));
CHECK_TIMEGM_ARG_OUT_OF_RANGE();
-#endif
+#endif /* SIZEOF_INT == 4 || SIZEOF_INT == 8 */
#if SIZEOF_INT == 8
/* one of the largest tm_year values my 64 bit system supports */
@@ -751,7 +754,7 @@ test_util_time(void *arg)
CAPTURE();
tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time));
CHECK_TIMEGM_ARG_OUT_OF_RANGE();
-#endif
+#endif /* SIZEOF_INT == 8 */
/* month */
a_time.tm_year = 2007-1900; /* restore valid year */
@@ -887,7 +890,7 @@ test_util_time(void *arg)
teardown_capture_of_logs();
}
}
-#endif
+#endif /* SIZEOF_TIME_T == 8 */
/* time_t >= INT_MAX yields a year clamped to 2037 or 9999,
* depending on whether the implementation of the system gmtime(_r)
@@ -903,7 +906,7 @@ test_util_time(void *arg)
tt_assert(b_time.tm_year == (2037-1900) ||
b_time.tm_year == (2038-1900));
}
-#endif
+#endif /* SIZEOF_TIME_T == 4 || SIZEOF_TIME_T == 8 */
#if SIZEOF_TIME_T == 8
{
@@ -928,7 +931,7 @@ test_util_time(void *arg)
tt_assert(b_time.tm_year == (2037-1900) ||
b_time.tm_year == (9999-1900));
}
-#endif
+#endif /* SIZEOF_TIME_T == 8 */
/* Test {format,parse}_rfc1123_time */
@@ -964,7 +967,9 @@ test_util_time(void *arg)
strlcpy(timestr, "Wed, 17 Feb 2038 06:13:20 GMT", sizeof(timestr));
t_res = 0;
+ CAPTURE();
i = parse_rfc1123_time(timestr, &t_res);
+ CHECK_TIMEGM_WARNING("does not fit in tor_timegm");
tt_int_op(-1,OP_EQ, i);
#elif SIZEOF_TIME_T == 8
tt_str_op("Wed, 17 Feb 2038 06:13:20 GMT",OP_EQ, timestr);
@@ -973,7 +978,7 @@ test_util_time(void *arg)
i = parse_rfc1123_time(timestr, &t_res);
tt_int_op(0,OP_EQ, i);
tt_int_op(t_res,OP_EQ, (time_t)2150000000UL);
-#endif
+#endif /* SIZEOF_TIME_T == 4 || ... */
/* The timezone doesn't matter */
t_res = 0;
@@ -1039,13 +1044,16 @@ test_util_time(void *arg)
/* This value is out of range with 32 bit time_t, but in range for 64 bit
* time_t */
t_res = 0;
- i = parse_iso_time("2038-02-17 06:13:20", &t_res);
#if SIZEOF_TIME_T == 4
+ CAPTURE();
+ i = parse_iso_time("2038-02-17 06:13:20", &t_res);
tt_int_op(-1,OP_EQ, i);
+ CHECK_TIMEGM_WARNING("does not fit in tor_timegm");
#elif SIZEOF_TIME_T == 8
+ i = parse_iso_time("2038-02-17 06:13:20", &t_res);
tt_int_op(0,OP_EQ, i);
tt_int_op(t_res,OP_EQ, (time_t)2150000000UL);
-#endif
+#endif /* SIZEOF_TIME_T == 4 || ... */
tt_int_op(-1,OP_EQ, parse_iso_time("2004-08-zz 99-99x99", &t_res));
tt_int_op(-1,OP_EQ, parse_iso_time("2011-03-32 00:00:00", &t_res));
@@ -1059,6 +1067,23 @@ test_util_time(void *arg)
tt_int_op(-1,OP_EQ, parse_iso_time("2004-08-04 00:48:22.100", &t_res));
tt_int_op(-1,OP_EQ, parse_iso_time("2004-08-04 00:48:22XYZ", &t_res));
+ /* but... that _is_ acceptable if we aren't being strict. */
+ t_res = 0;
+ i = parse_iso_time_("2004-08-04 00:48:22XYZ", &t_res, 0, 0);
+ tt_int_op(0,OP_EQ, i);
+ tt_int_op(t_res,OP_EQ, (time_t)1091580502UL);
+
+ /* try nospace variant. */
+ t_res = 0;
+ i = parse_iso_time_nospace("2004-08-04T00:48:22", &t_res);
+ tt_int_op(0,OP_EQ, i);
+ tt_int_op(t_res,OP_EQ, (time_t)1091580502UL);
+
+ tt_int_op(-1,OP_EQ, parse_iso_time("2004-08-04T00:48:22", &t_res));
+ tt_int_op(-1,OP_EQ, parse_iso_time_nospace("2004-08-04 00:48:22", &t_res));
+ tt_int_op(-1,OP_EQ, parse_iso_time("2004-08-04x00:48:22", &t_res));
+ tt_int_op(-1,OP_EQ, parse_iso_time_nospace("2004-08-04x00:48:22", &t_res));
+
/* Test tor_gettimeofday */
end.tv_sec = 4;
@@ -1111,7 +1136,7 @@ test_util_time(void *arg)
/* This SHOULD work on windows too; see bug #18665 */
tt_str_op("2038-02-17 06:13:20",OP_EQ, timestr);
#endif
-#endif
+#endif /* SIZEOF_TIME_T == 4 || ... */
#undef CAPTURE
#undef CHECK_TIMEGM_ARG_OUT_OF_RANGE
@@ -1200,13 +1225,16 @@ test_util_parse_http_time(void *arg)
#if SIZEOF_TIME_T == 4
/* parse_http_time should indicate failure on overflow, but it doesn't yet.
* Hopefully #18480 will improve the failure semantics in this case. */
+ setup_full_capture_of_logs(LOG_WARN);
tt_int_op(0,OP_EQ,parse_http_time("Wed, 17 Feb 2038 06:13:20 GMT", &a_time));
tt_int_op((time_t)-1,OP_EQ, tor_timegm(&a_time));
+ expect_single_log_msg_containing("does not fit in tor_timegm");
+ teardown_capture_of_logs();
#elif SIZEOF_TIME_T == 8
tt_int_op(0,OP_EQ,parse_http_time("Wed, 17 Feb 2038 06:13:20 GMT", &a_time));
tt_int_op((time_t)2150000000UL,OP_EQ, tor_timegm(&a_time));
T("2038-02-17 06:13:20");
-#endif
+#endif /* SIZEOF_TIME_T == 4 || ... */
tt_int_op(-1,OP_EQ, parse_http_time("2004-08-zz 99-99x99 GMT", &a_time));
tt_int_op(-1,OP_EQ, parse_http_time("2011-03-32 00:00:00 GMT", &a_time));
@@ -1219,7 +1247,7 @@ test_util_parse_http_time(void *arg)
#undef T
done:
- ;
+ teardown_capture_of_logs();
}
static void
@@ -1453,7 +1481,7 @@ test_util_config_line_comment_character(void *arg)
tor_free(k); tor_free(v);
test_streq(str, "");
-#endif
+#endif /* 0 */
done:
tor_free(k);
@@ -1584,7 +1612,7 @@ test_util_config_line_escaped_content(void *arg)
str = parse_config_line_from_str_verbose(str, &k, &v, NULL);
tt_ptr_op(str, OP_EQ, NULL);
tor_free(k); tor_free(v);
-#endif
+#endif /* 0 */
str = buf6;
@@ -1656,14 +1684,14 @@ test_util_config_line_crlf(void *arg)
tt_assert(str);
tt_str_op(k,OP_EQ,"Hello");
tt_str_op(v,OP_EQ,"world");
- tt_assert(!err);
+ tt_ptr_op(err, OP_EQ, NULL);
tor_free(k); tor_free(v);
str = parse_config_line_from_str_verbose(str, &k, &v, &err);
tt_assert(str);
tt_str_op(k,OP_EQ,"Hello");
tt_str_op(v,OP_EQ,"nice big world");
- tt_assert(!err);
+ tt_ptr_op(err, OP_EQ, NULL);
tor_free(k); tor_free(v);
tt_str_op(str,OP_EQ, "");
@@ -1768,7 +1796,7 @@ test_util_expand_filename(void *arg)
done:
tor_free(str);
}
-#endif
+#endif /* !defined(_WIN32) */
/** Test tor_escape_str_for_pt_args(). */
static void
@@ -1923,7 +1951,7 @@ test_util_strmisc(void *arg)
tt_assert(!tor_mem_is_zero(buf, 10));
/* Test 'escaped' */
- tt_assert(NULL == escaped(NULL));
+ tt_ptr_op(escaped(NULL), OP_EQ, NULL);
tt_str_op("\"\"",OP_EQ, escaped(""));
tt_str_op("\"abcd\"",OP_EQ, escaped("abcd"));
tt_str_op("\"\\\\ \\n\\r\\t\\\"\\'\"",OP_EQ, escaped("\\ \n\r\t\"'"));
@@ -1981,23 +2009,23 @@ test_util_strmisc(void *arg)
/* Test memmem and memstr */
{
const char *haystack = "abcde";
- tt_assert(!tor_memmem(haystack, 5, "ef", 2));
+ tt_ptr_op(tor_memmem(haystack, 5, "ef", 2), OP_EQ, NULL);
tt_ptr_op(tor_memmem(haystack, 5, "cd", 2),OP_EQ, haystack + 2);
tt_ptr_op(tor_memmem(haystack, 5, "cde", 3),OP_EQ, haystack + 2);
- tt_assert(!tor_memmem(haystack, 4, "cde", 3));
+ tt_ptr_op(tor_memmem(haystack, 4, "cde", 3), OP_EQ, NULL);
haystack = "ababcad";
tt_ptr_op(tor_memmem(haystack, 7, "abc", 3),OP_EQ, haystack + 2);
tt_ptr_op(tor_memmem(haystack, 7, "ad", 2),OP_EQ, haystack + 5);
tt_ptr_op(tor_memmem(haystack, 7, "cad", 3),OP_EQ, haystack + 4);
- tt_assert(!tor_memmem(haystack, 7, "dadad", 5));
- tt_assert(!tor_memmem(haystack, 7, "abcdefghij", 10));
+ tt_ptr_op(tor_memmem(haystack, 7, "dadad", 5), OP_EQ, NULL);
+ tt_ptr_op(tor_memmem(haystack, 7, "abcdefghij", 10), OP_EQ, NULL);
/* memstr */
tt_ptr_op(tor_memstr(haystack, 7, "abc"),OP_EQ, haystack + 2);
tt_ptr_op(tor_memstr(haystack, 7, "cad"),OP_EQ, haystack + 4);
- tt_assert(!tor_memstr(haystack, 6, "cad"));
- tt_assert(!tor_memstr(haystack, 7, "cadd"));
- tt_assert(!tor_memstr(haystack, 7, "fe"));
- tt_assert(!tor_memstr(haystack, 7, "ababcade"));
+ tt_ptr_op(tor_memstr(haystack, 6, "cad"), OP_EQ, NULL);
+ tt_ptr_op(tor_memstr(haystack, 7, "cadd"), OP_EQ, NULL);
+ tt_ptr_op(tor_memstr(haystack, 7, "fe"), OP_EQ, NULL);
+ tt_ptr_op(tor_memstr(haystack, 7, "ababcade"), OP_EQ, NULL);
}
/* Test hex_str */
@@ -2107,10 +2135,13 @@ test_util_parse_integer(void *arg)
/* Base different than 10 */
tt_int_op(2L,OP_EQ, tor_parse_long("10",2,0,100,NULL,NULL));
tt_int_op(0L,OP_EQ, tor_parse_long("2",2,0,100,NULL,NULL));
- tt_int_op(0L,OP_EQ, tor_parse_long("10",-2,0,100,NULL,NULL));
tt_int_op(68284L,OP_EQ, tor_parse_long("10abc",16,0,70000,NULL,NULL));
tt_int_op(68284L,OP_EQ, tor_parse_long("10ABC",16,0,70000,NULL,NULL));
+ tor_capture_bugs_(2);
+ tt_int_op(0L,OP_EQ, tor_parse_long("10",-2,0,100,NULL,NULL));
tt_int_op(0,OP_EQ, tor_parse_long("10ABC",-1,0,70000,&i,NULL));
+ tt_int_op(2, OP_EQ, smartlist_len(tor_get_captured_bug_log_()));
+ tor_end_capture_bugs_();
tt_int_op(i,OP_EQ, 0);
/* Test parse_ulong */
@@ -2123,7 +2154,10 @@ test_util_parse_integer(void *arg)
tt_int_op(0UL,OP_EQ, tor_parse_ulong("8",8,0,100,NULL,NULL));
tt_int_op(50UL,OP_EQ, tor_parse_ulong("50",10,50,100,NULL,NULL));
tt_int_op(0UL,OP_EQ, tor_parse_ulong("-50",10,0,100,NULL,NULL));
+ tor_capture_bugs_(1);
tt_int_op(0UL,OP_EQ, tor_parse_ulong("50",-1,50,100,&i,NULL));
+ tt_int_op(1, OP_EQ, smartlist_len(tor_get_captured_bug_log_()));
+ tor_end_capture_bugs_();
tt_int_op(0,OP_EQ, i);
tt_int_op(0UL,OP_EQ, tor_parse_ulong("-50",10,0,100,&i,NULL));
tt_int_op(0,OP_EQ, i);
@@ -2139,8 +2173,11 @@ test_util_parse_integer(void *arg)
tt_assert(U64_LITERAL(0) ==
tor_parse_uint64("12345678901",10,500,INT32_MAX, &i, &cp));
tt_int_op(0,OP_EQ, i);
+ tor_capture_bugs_(1);
tt_assert(U64_LITERAL(0) ==
tor_parse_uint64("123",-1,0,INT32_MAX, &i, &cp));
+ tt_int_op(1, OP_EQ, smartlist_len(tor_get_captured_bug_log_()));
+ tor_end_capture_bugs_();
tt_int_op(0,OP_EQ, i);
{
@@ -2152,10 +2189,13 @@ test_util_parse_integer(void *arg)
tt_int_op(1,OP_EQ, i);
tt_assert(DBL_TO_U64(d) == 0);
d = tor_parse_double(" ", 0, (double)UINT64_MAX,&i,NULL);
+ tt_double_op(fabs(d), OP_LT, 1e-10);
tt_int_op(0,OP_EQ, i);
d = tor_parse_double(".0a", 0, (double)UINT64_MAX,&i,NULL);
+ tt_double_op(fabs(d), OP_LT, 1e-10);
tt_int_op(0,OP_EQ, i);
d = tor_parse_double(".0a", 0, (double)UINT64_MAX,&i,&cp);
+ tt_double_op(fabs(d), OP_LT, 1e-10);
tt_int_op(1,OP_EQ, i);
d = tor_parse_double("-.0", 0, (double)UINT64_MAX,&i,NULL);
tt_int_op(1,OP_EQ, i);
@@ -2224,114 +2264,340 @@ 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;
- 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_compress_supports_method(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);
+ if (method != NO_METHOD) {
+ tt_ptr_op(tor_compress_version_str(method), OP_NE, NULL);
+ tt_ptr_op(tor_compress_header_version_str(method), OP_NE, NULL);
+ }
- tor_free(buf2);
- tor_free(buf3);
+ 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,
- 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_ptr_op(buf2, OP_NE, 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_ptr_op(buf3, OP_NE, 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_ptr_op(buf3, OP_EQ, 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_int_op(tor_compress_state_size(state), OP_GT, 0);
+
+ 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
+test_util_decompress_concatenated_impl(compress_method_t method)
+{
+ char input[4096];
+ char *c1 = NULL, *c2 = NULL, *c3 = NULL;
+ char *result = NULL;
+ size_t sz1, sz2, sz3, szr;
+ int r;
+
+ crypto_rand(input, sizeof(input));
+
+ /* Compress the input in two chunks. */
+ r = tor_compress(&c1, &sz1, input, 2048, method);
+ tt_int_op(r, OP_EQ, 0);
+ r = tor_compress(&c2, &sz2, input+2048, 2048, method);
+ tt_int_op(r, OP_EQ, 0);
+
+ /* concatenate the chunks. */
+ sz3 = sz1 + sz2;
+ c3 = tor_malloc(sz3);
+ memcpy(c3, c1, sz1);
+ memcpy(c3+sz1, c2, sz2);
+
+ /* decompress the concatenated result */
+ r = tor_uncompress(&result, &szr, c3, sz3, method, 0, LOG_WARN);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(szr, OP_EQ, sizeof(input));
+ tt_mem_op(result, OP_EQ, input, sizeof(input));
+
+ done:
+ tor_free(c1);
+ tor_free(c2);
+ tor_free(c3);
+ tor_free(result);
+}
+
+static void
+test_util_decompress_concatenated(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();
+ }
+
+ test_util_decompress_concatenated_impl(method);
+ done:
+ ;
+}
+
+static void
+test_util_decompress_junk_impl(compress_method_t method)
+{
+ char input[4096];
+ char *result = NULL, *result2 = NULL;
+ size_t szr, szr2, sz;
+ int r;
+
+ /* This shouldn't be a compressed string according to any method. */
+ strlcpy(input, "This shouldn't be a compressed string by any means.",
+ sizeof(input));
+ sz = strlen(input);
+ setup_capture_of_logs(LOG_WARN);
+ r = tor_uncompress(&result, &szr, input, sz, method, 0, LOG_WARN);
+ tt_int_op(r, OP_EQ, -1);
+ tt_ptr_op(result, OP_EQ, NULL);
+ expect_log_msg_containing("Error while uncompressing data: bad input?");
+ mock_clean_saved_logs();
+
+ /* Now try again, with a compressed object that starts out good and turns to
+ junk. */
+ crypto_rand(input, sizeof(input));
+ r = tor_compress(&result, &szr, input, sizeof(input), method);
+ tt_int_op(r, OP_EQ, 0);
+ crypto_rand(result+szr/2, szr-(szr/2)); // trash the 2nd half of the result
+ r = tor_uncompress(&result2, &szr2, result, szr, method, 0, LOG_WARN);
+ tt_int_op(r, OP_EQ, -1);
+ expect_log_msg_containing("Error while uncompressing data: bad input?");
+
+ done:
+ teardown_capture_of_logs();
+ tor_free(result);
+ tor_free(result2);
+}
+
+static void
+test_util_decompress_junk(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();
+ }
+
+ test_util_decompress_junk_impl(method);
+ done:
+ ;
+}
+
+/* mock replacement for tor_compress_is_compression_bomb that doesn't
+ * believe in compression bombs. */
+static int
+mock_is_never_compression_bomb(size_t in, size_t out)
+{
+ (void)in;
+ (void) out;
+ return 0;
+}
+
+static void
+test_util_decompress_dos_impl(compress_method_t method)
+{
+ char *input;
+ char *result = NULL, *result2 = NULL;
+ size_t szr, szr2;
+ int r;
+
+ const size_t big = 1024*1024;
+ /* one megabyte of 0s. */
+ input = tor_malloc_zero(big);
+
+ /* Compress it into "result": it should fail. */
+ setup_full_capture_of_logs(LOG_WARN);
+ r = tor_compress(&result, &szr, input, big, method);
+ tt_int_op(r, OP_EQ, -1);
+ expect_log_msg_containing(
+ "other Tors would think this was a compression bomb");
+ teardown_capture_of_logs();
+
+ /* Try again, but this time suppress compression-bomb detection */
+ MOCK(tor_compress_is_compression_bomb, mock_is_never_compression_bomb);
+ r = tor_compress(&result, &szr, input, big, method);
+ UNMOCK(tor_compress_is_compression_bomb);
+ tt_int_op(r, OP_EQ, 0);
+ tt_ptr_op(result, OP_NE, NULL);
+
+ /* We should refuse to uncomrpess it again, since it looks like a
+ * compression bomb. */
+ setup_capture_of_logs(LOG_WARN);
+ r = tor_uncompress(&result2, &szr2, result, szr, method, 0, LOG_WARN);
+ tt_int_op(r, OP_EQ, -1);
+ expect_log_msg_containing("bomb; abandoning stream");
+
+ done:
+ teardown_capture_of_logs();
+ tor_free(input);
+ tor_free(result);
+ tor_free(result2);
+}
+
+static void
+test_util_decompress_dos(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();
+ }
+
+ test_util_decompress_dos_impl(method);
+ done:
+ ;
}
static void
@@ -2346,44 +2612,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. */
@@ -2401,7 +2667,7 @@ test_util_mmap(void *arg)
crypto_rand(buf, buflen);
mapping = tor_mmap_file(fname1);
- tt_assert(! mapping);
+ tt_ptr_op(mapping, OP_EQ, NULL);
write_str_to_file(fname1, "Short file.", 1);
@@ -2419,7 +2685,7 @@ test_util_mmap(void *arg)
tt_str_op(mapping->data,OP_EQ, "Short file.");
tt_int_op(0, OP_EQ, tor_munmap_file(mapping));
mapping = NULL;
-#endif
+#endif /* defined(_WIN32) */
/* Now a zero-length file. */
write_str_to_file(fname1, "", 1);
@@ -2430,7 +2696,7 @@ test_util_mmap(void *arg)
/* Make sure that we fail to map a no-longer-existent file. */
mapping = tor_mmap_file(fname1);
- tt_assert(! mapping);
+ tt_ptr_op(mapping, OP_EQ, NULL);
/* Now try a big file that stretches across a few pages and isn't aligned */
write_bytes_to_file(fname2, buf, buflen, 1);
@@ -2748,7 +3014,7 @@ test_util_sscanf(void *arg)
r = tor_sscanf("9223372036854775808. -9223372036854775809.",
"%d. %d.", &int1, &int2);
tt_int_op(r,OP_EQ, 0);
-#endif
+#endif /* SIZEOF_INT == 4 || ... */
#if SIZEOF_LONG == 4
/* %lu */
@@ -2843,7 +3109,7 @@ test_util_sscanf(void *arg)
r = tor_sscanf("9223372036854775808. -9223372036854775809.",
"%ld. %ld.", &lng1, &lng2);
tt_int_op(r,OP_EQ, 0);
-#endif
+#endif /* SIZEOF_LONG == 4 || ... */
r = tor_sscanf("123.456 .000007 -900123123.2000787 00003.2",
"%lf %lf %lf %lf", &d1,&d2,&d3,&d4);
@@ -2870,7 +3136,7 @@ strnlen(const char *s, size_t len)
return len;
return p - s;
}
-#endif
+#endif /* !defined(HAVE_STRNLEN) */
static void
test_util_format_time_interval(void *arg)
@@ -3237,7 +3503,7 @@ test_util_format_time_interval(void *arg)
tt_ci_char_op(label_m[0],OP_EQ, 'm');
/* and 7 or 8 seconds - ignored */
-#endif
+#endif /* SIZEOF_LONG == 4 || SIZEOF_LONG == 8 */
#if SIZEOF_LONG == 8
@@ -3275,7 +3541,7 @@ test_util_format_time_interval(void *arg)
tt_ci_char_op(label_m[0],OP_EQ, 'm');
/* and 7 or 8 seconds - ignored */
-#endif
+#endif /* SIZEOF_LONG == 8 */
done:
;
@@ -3318,7 +3584,7 @@ test_util_path_is_relative(void *arg)
tt_int_op(0,OP_EQ, path_is_relative("\\dir"));
tt_int_op(0,OP_EQ, path_is_relative("a:\\dir"));
tt_int_op(0,OP_EQ, path_is_relative("z:\\dir"));
-#endif
+#endif /* defined(_WIN32) */
done:
;
@@ -3333,6 +3599,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 /* defined(DISABLE_MEMORY_SENTINELS) */
+
(void)arg;
tt_assert(area);
@@ -3502,8 +3775,8 @@ test_util_strtok(void *arg)
}
tor_snprintf(buf, sizeof(buf), "%s", pad1);
tor_snprintf(buf2, sizeof(buf2), "%s", pad2);
- tt_assert(NULL == tor_strtok_r_impl(buf, " ", &cp1));
- tt_assert(NULL == tor_strtok_r_impl(buf2, ".!..;!", &cp2));
+ tt_ptr_op(tor_strtok_r_impl(buf, " ", &cp1), OP_EQ, NULL);
+ tt_ptr_op(tor_strtok_r_impl(buf2, ".!..;!", &cp2), OP_EQ, NULL);
tor_snprintf(buf, sizeof(buf),
"%sGraved on the dark in gestures of descent%s", pad1, pad1);
@@ -3853,7 +4126,7 @@ test_util_load_win_lib(void *ptr)
if (h)
FreeLibrary(h);
}
-#endif
+#endif /* defined(_WIN32) */
#ifndef _WIN32
static void
@@ -3905,7 +4178,7 @@ test_util_exit_status(void *ptr)
tt_int_op(n,OP_EQ, strlen(hex_errno));
tt_int_op(n,OP_EQ, HEX_ERRNO_SIZE);
-#endif
+#endif /* SIZEOF_INT == 4 || ... */
clear_hex_errno(hex_errno);
n = format_helper_exit_status(0x7F, 0, hex_errno);
@@ -3923,20 +4196,16 @@ test_util_exit_status(void *ptr)
done:
;
}
-#endif
+#endif /* !defined(_WIN32) */
#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;
@@ -3947,91 +4216,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);
+
+ 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 string that contains a nul. */
+ retlen = write(test_pipe[1], "AB\0", 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, "AB");
+ errno = 0;
- /* Send in a partial line */
- retlen = write(test_pipe[1], "A", 1);
+ /* 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_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, "AB");
errno = 0;
- /* Send in a full line */
- retlen = write(test_pipe[1], "CD\n", 3);
+ /* 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_int_op(status, OP_EQ, IO_STREAM_OKAY);
+ tt_str_op(buf, OP_EQ, "");
+ errno = 0;
+
+ /* 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 /* !defined(_WIN32) */
/**
* Test for format_hex_number_sigsafe()
@@ -4227,7 +4520,7 @@ test_util_split_lines(void *ptr)
/* Check we have not got too many lines */
tt_int_op(MAX_SPLIT_LINE_COUNT, OP_GT, j);
/* Check that there actually should be a line here */
- tt_assert(tests[i].split_line[j] != NULL);
+ tt_ptr_op(tests[i].split_line[j], OP_NE, NULL);
log_info(LD_GENERAL, "Line %d of test %d, should be <%s>",
j, i, tests[i].split_line[j]);
/* Check that the line is as expected */
@@ -4343,11 +4636,11 @@ test_util_di_map(void *arg)
char dflt_entry[] = "'You have made a good beginning', but no more";
- tt_int_op(32, ==, sizeof(key1));
- tt_int_op(32, ==, sizeof(key2));
- tt_int_op(32, ==, sizeof(key3));
+ tt_int_op(32, OP_EQ, sizeof(key1));
+ tt_int_op(32, OP_EQ, sizeof(key2));
+ tt_int_op(32, OP_EQ, sizeof(key3));
- tt_ptr_op(dflt_entry, ==, dimap_search(dimap, key1, dflt_entry));
+ tt_ptr_op(dflt_entry, OP_EQ, dimap_search(dimap, key1, dflt_entry));
char *str1 = tor_strdup("You are precisely as big as what you love"
" and precisely as small as what you allow"
@@ -4365,10 +4658,10 @@ test_util_di_map(void *arg)
dimap_add_entry(&dimap, key2, str2);
dimap_add_entry(&dimap, key3, str3);
- tt_ptr_op(str1, ==, dimap_search(dimap, key1, dflt_entry));
- tt_ptr_op(str3, ==, dimap_search(dimap, key3, dflt_entry));
- tt_ptr_op(str2, ==, dimap_search(dimap, key2, dflt_entry));
- tt_ptr_op(dflt_entry, ==, dimap_search(dimap, key4, dflt_entry));
+ tt_ptr_op(str1, OP_EQ, dimap_search(dimap, key1, dflt_entry));
+ tt_ptr_op(str3, OP_EQ, dimap_search(dimap, key3, dflt_entry));
+ tt_ptr_op(str2, OP_EQ, dimap_search(dimap, key2, dflt_entry));
+ tt_ptr_op(dflt_entry, OP_EQ, dimap_search(dimap, key4, dflt_entry));
done:
dimap_free(dimap, tor_free_);
@@ -4835,34 +5128,34 @@ test_util_round_to_next_multiple_of(void *arg)
{
(void)arg;
- tt_u64_op(round_uint64_to_next_multiple_of(0,1), ==, 0);
- tt_u64_op(round_uint64_to_next_multiple_of(0,7), ==, 0);
+ tt_u64_op(round_uint64_to_next_multiple_of(0,1), OP_EQ, 0);
+ tt_u64_op(round_uint64_to_next_multiple_of(0,7), OP_EQ, 0);
- tt_u64_op(round_uint64_to_next_multiple_of(99,1), ==, 99);
- tt_u64_op(round_uint64_to_next_multiple_of(99,7), ==, 105);
- tt_u64_op(round_uint64_to_next_multiple_of(99,9), ==, 99);
+ tt_u64_op(round_uint64_to_next_multiple_of(99,1), OP_EQ, 99);
+ tt_u64_op(round_uint64_to_next_multiple_of(99,7), OP_EQ, 105);
+ tt_u64_op(round_uint64_to_next_multiple_of(99,9), OP_EQ, 99);
- tt_u64_op(round_uint64_to_next_multiple_of(UINT64_MAX,2), ==,
+ tt_u64_op(round_uint64_to_next_multiple_of(UINT64_MAX,2), OP_EQ,
UINT64_MAX);
- tt_int_op(round_uint32_to_next_multiple_of(0,1), ==, 0);
- tt_int_op(round_uint32_to_next_multiple_of(0,7), ==, 0);
+ tt_int_op(round_uint32_to_next_multiple_of(0,1), OP_EQ, 0);
+ tt_int_op(round_uint32_to_next_multiple_of(0,7), OP_EQ, 0);
- tt_int_op(round_uint32_to_next_multiple_of(99,1), ==, 99);
- tt_int_op(round_uint32_to_next_multiple_of(99,7), ==, 105);
- tt_int_op(round_uint32_to_next_multiple_of(99,9), ==, 99);
+ tt_int_op(round_uint32_to_next_multiple_of(99,1), OP_EQ, 99);
+ tt_int_op(round_uint32_to_next_multiple_of(99,7), OP_EQ, 105);
+ tt_int_op(round_uint32_to_next_multiple_of(99,9), OP_EQ, 99);
- tt_int_op(round_uint32_to_next_multiple_of(UINT32_MAX,2), ==,
+ tt_int_op(round_uint32_to_next_multiple_of(UINT32_MAX,2), OP_EQ,
UINT32_MAX);
- tt_uint_op(round_to_next_multiple_of(0,1), ==, 0);
- tt_uint_op(round_to_next_multiple_of(0,7), ==, 0);
+ tt_uint_op(round_to_next_multiple_of(0,1), OP_EQ, 0);
+ tt_uint_op(round_to_next_multiple_of(0,7), OP_EQ, 0);
- tt_uint_op(round_to_next_multiple_of(99,1), ==, 99);
- tt_uint_op(round_to_next_multiple_of(99,7), ==, 105);
- tt_uint_op(round_to_next_multiple_of(99,9), ==, 99);
+ tt_uint_op(round_to_next_multiple_of(99,1), OP_EQ, 99);
+ tt_uint_op(round_to_next_multiple_of(99,7), OP_EQ, 105);
+ tt_uint_op(round_to_next_multiple_of(99,9), OP_EQ, 99);
- tt_uint_op(round_to_next_multiple_of(UINT_MAX,2), ==,
+ tt_uint_op(round_to_next_multiple_of(UINT_MAX,2), OP_EQ,
UINT_MAX);
done:
;
@@ -4883,26 +5176,26 @@ test_util_laplace(void *arg)
const double delta_f = 15.0, epsilon = 0.3; /* b = 15.0 / 0.3 = 50.0 */
(void)arg;
- tt_i64_op(INT64_MIN, ==, sample_laplace_distribution(mu, b, 0.0));
- tt_i64_op(-69, ==, sample_laplace_distribution(mu, b, 0.01));
- tt_i64_op(24, ==, sample_laplace_distribution(mu, b, 0.5));
- tt_i64_op(24, ==, sample_laplace_distribution(mu, b, 0.51));
- tt_i64_op(117, ==, sample_laplace_distribution(mu, b, 0.99));
+ tt_i64_op(INT64_MIN, OP_EQ, sample_laplace_distribution(mu, b, 0.0));
+ tt_i64_op(-69, OP_EQ, sample_laplace_distribution(mu, b, 0.01));
+ tt_i64_op(24, OP_EQ, sample_laplace_distribution(mu, b, 0.5));
+ tt_i64_op(24, OP_EQ, sample_laplace_distribution(mu, b, 0.51));
+ tt_i64_op(117, OP_EQ, sample_laplace_distribution(mu, b, 0.99));
/* >>> laplace.ppf([0.0, 0.1, 0.25, 0.5, 0.75, 0.9, 0.99],
* ... loc = 0, scale = 50)
* array([ -inf, -80.47189562, -34.65735903, 0. ,
* 34.65735903, 80.47189562, 195.60115027])
*/
- tt_i64_op(INT64_MIN + 20, ==,
+ tt_i64_op(INT64_MIN + 20, OP_EQ,
add_laplace_noise(20, 0.0, delta_f, epsilon));
- tt_i64_op(-60, ==, add_laplace_noise(20, 0.1, delta_f, epsilon));
- tt_i64_op(-14, ==, add_laplace_noise(20, 0.25, delta_f, epsilon));
- tt_i64_op(20, ==, add_laplace_noise(20, 0.5, delta_f, epsilon));
- tt_i64_op(54, ==, add_laplace_noise(20, 0.75, delta_f, epsilon));
- tt_i64_op(100, ==, add_laplace_noise(20, 0.9, delta_f, epsilon));
- tt_i64_op(215, ==, add_laplace_noise(20, 0.99, delta_f, epsilon));
+ tt_i64_op(-60, OP_EQ, add_laplace_noise(20, 0.1, delta_f, epsilon));
+ tt_i64_op(-14, OP_EQ, add_laplace_noise(20, 0.25, delta_f, epsilon));
+ tt_i64_op(20, OP_EQ, add_laplace_noise(20, 0.5, delta_f, epsilon));
+ tt_i64_op(54, OP_EQ, add_laplace_noise(20, 0.75, delta_f, epsilon));
+ tt_i64_op(100, OP_EQ, add_laplace_noise(20, 0.9, delta_f, epsilon));
+ tt_i64_op(215, OP_EQ, add_laplace_noise(20, 0.99, delta_f, epsilon));
/* Test extreme values of signal with maximally negative values of noise
* 1.0000000000000002 is the smallest number > 1
@@ -4915,54 +5208,54 @@ test_util_laplace(void *arg)
*/
const double noscale_df = 1.0, noscale_eps = 1.0;
- tt_i64_op(INT64_MIN, ==,
+ tt_i64_op(INT64_MIN, OP_EQ,
add_laplace_noise(0, 0.0, noscale_df, noscale_eps));
/* is it clipped to INT64_MIN? */
- tt_i64_op(INT64_MIN, ==,
+ tt_i64_op(INT64_MIN, OP_EQ,
add_laplace_noise(-1, 0.0, noscale_df, noscale_eps));
- tt_i64_op(INT64_MIN, ==,
+ tt_i64_op(INT64_MIN, OP_EQ,
add_laplace_noise(INT64_MIN, 0.0,
noscale_df, noscale_eps));
/* ... even when scaled? */
- tt_i64_op(INT64_MIN, ==,
+ tt_i64_op(INT64_MIN, OP_EQ,
add_laplace_noise(0, 0.0, delta_f, epsilon));
- tt_i64_op(INT64_MIN, ==,
+ tt_i64_op(INT64_MIN, OP_EQ,
add_laplace_noise(0, 0.0,
DBL_MAX, 1));
- tt_i64_op(INT64_MIN, ==,
+ tt_i64_op(INT64_MIN, OP_EQ,
add_laplace_noise(INT64_MIN, 0.0,
DBL_MAX, 1));
/* does it play nice with INT64_MAX? */
- tt_i64_op((INT64_MIN + INT64_MAX), ==,
+ tt_i64_op((INT64_MIN + INT64_MAX), OP_EQ,
add_laplace_noise(INT64_MAX, 0.0,
noscale_df, noscale_eps));
/* do near-zero fractional values work? */
const double min_dbl_error = 0.0000000000000002;
- tt_i64_op(-35, ==,
+ tt_i64_op(-35, OP_EQ,
add_laplace_noise(0, min_dbl_error,
noscale_df, noscale_eps));
- tt_i64_op(INT64_MIN, ==,
+ tt_i64_op(INT64_MIN, OP_EQ,
add_laplace_noise(INT64_MIN, min_dbl_error,
noscale_df, noscale_eps));
- tt_i64_op((-35 + INT64_MAX), ==,
+ tt_i64_op((-35 + INT64_MAX), OP_EQ,
add_laplace_noise(INT64_MAX, min_dbl_error,
noscale_df, noscale_eps));
- tt_i64_op(INT64_MIN, ==,
+ tt_i64_op(INT64_MIN, OP_EQ,
add_laplace_noise(0, min_dbl_error,
DBL_MAX, 1));
- tt_i64_op((INT64_MAX + INT64_MIN), ==,
+ tt_i64_op((INT64_MAX + INT64_MIN), OP_EQ,
add_laplace_noise(INT64_MAX, min_dbl_error,
DBL_MAX, 1));
- tt_i64_op(INT64_MIN, ==,
+ tt_i64_op(INT64_MIN, OP_EQ,
add_laplace_noise(INT64_MIN, min_dbl_error,
DBL_MAX, 1));
/* does it play nice with INT64_MAX? */
- tt_i64_op((INT64_MAX - 35), ==,
+ tt_i64_op((INT64_MAX - 35), OP_EQ,
add_laplace_noise(INT64_MAX, min_dbl_error,
noscale_df, noscale_eps));
@@ -4977,31 +5270,31 @@ test_util_laplace(void *arg)
const double max_dbl_lt_one = 0.9999999999999998;
/* do near-one fractional values work? */
- tt_i64_op(35, ==,
+ tt_i64_op(35, OP_EQ,
add_laplace_noise(0, max_dbl_lt_one, noscale_df, noscale_eps));
/* is it clipped to INT64_MAX? */
- tt_i64_op(INT64_MAX, ==,
+ tt_i64_op(INT64_MAX, OP_EQ,
add_laplace_noise(INT64_MAX - 35, max_dbl_lt_one,
noscale_df, noscale_eps));
- tt_i64_op(INT64_MAX, ==,
+ tt_i64_op(INT64_MAX, OP_EQ,
add_laplace_noise(INT64_MAX - 34, max_dbl_lt_one,
noscale_df, noscale_eps));
- tt_i64_op(INT64_MAX, ==,
+ tt_i64_op(INT64_MAX, OP_EQ,
add_laplace_noise(INT64_MAX, max_dbl_lt_one,
noscale_df, noscale_eps));
/* ... even when scaled? */
- tt_i64_op(INT64_MAX, ==,
+ tt_i64_op(INT64_MAX, OP_EQ,
add_laplace_noise(INT64_MAX, max_dbl_lt_one,
delta_f, epsilon));
- tt_i64_op((INT64_MIN + INT64_MAX), ==,
+ tt_i64_op((INT64_MIN + INT64_MAX), OP_EQ,
add_laplace_noise(INT64_MIN, max_dbl_lt_one,
DBL_MAX, 1));
- tt_i64_op(INT64_MAX, ==,
+ tt_i64_op(INT64_MAX, OP_EQ,
add_laplace_noise(INT64_MAX, max_dbl_lt_one,
DBL_MAX, 1));
/* does it play nice with INT64_MIN? */
- tt_i64_op((INT64_MIN + 35), ==,
+ tt_i64_op((INT64_MIN + 35), OP_EQ,
add_laplace_noise(INT64_MIN, max_dbl_lt_one,
noscale_df, noscale_eps));
@@ -5014,32 +5307,32 @@ test_util_clamp_double_to_int64(void *arg)
{
(void)arg;
- tt_i64_op(INT64_MIN, ==, clamp_double_to_int64(-INFINITY_DBL));
- tt_i64_op(INT64_MIN, ==,
+ tt_i64_op(INT64_MIN, OP_EQ, clamp_double_to_int64(-INFINITY_DBL));
+ tt_i64_op(INT64_MIN, OP_EQ,
clamp_double_to_int64(-1.0 * pow(2.0, 64.0) - 1.0));
- tt_i64_op(INT64_MIN, ==,
+ tt_i64_op(INT64_MIN, OP_EQ,
clamp_double_to_int64(-1.0 * pow(2.0, 63.0) - 1.0));
- tt_i64_op(((uint64_t) -1) << 53, ==,
+ tt_i64_op(((uint64_t) -1) << 53, OP_EQ,
clamp_double_to_int64(-1.0 * pow(2.0, 53.0)));
- tt_i64_op((((uint64_t) -1) << 53) + 1, ==,
+ tt_i64_op((((uint64_t) -1) << 53) + 1, OP_EQ,
clamp_double_to_int64(-1.0 * pow(2.0, 53.0) + 1.0));
- tt_i64_op(-1, ==, clamp_double_to_int64(-1.0));
- tt_i64_op(0, ==, clamp_double_to_int64(-0.9));
- tt_i64_op(0, ==, clamp_double_to_int64(-0.1));
- tt_i64_op(0, ==, clamp_double_to_int64(0.0));
- tt_i64_op(0, ==, clamp_double_to_int64(NAN_DBL));
- tt_i64_op(0, ==, clamp_double_to_int64(0.1));
- tt_i64_op(0, ==, clamp_double_to_int64(0.9));
- tt_i64_op(1, ==, clamp_double_to_int64(1.0));
- tt_i64_op((((int64_t) 1) << 53) - 1, ==,
+ tt_i64_op(-1, OP_EQ, clamp_double_to_int64(-1.0));
+ tt_i64_op(0, OP_EQ, clamp_double_to_int64(-0.9));
+ tt_i64_op(0, OP_EQ, clamp_double_to_int64(-0.1));
+ tt_i64_op(0, OP_EQ, clamp_double_to_int64(0.0));
+ tt_i64_op(0, OP_EQ, clamp_double_to_int64(NAN_DBL));
+ tt_i64_op(0, OP_EQ, clamp_double_to_int64(0.1));
+ tt_i64_op(0, OP_EQ, clamp_double_to_int64(0.9));
+ tt_i64_op(1, OP_EQ, clamp_double_to_int64(1.0));
+ tt_i64_op((((int64_t) 1) << 53) - 1, OP_EQ,
clamp_double_to_int64(pow(2.0, 53.0) - 1.0));
- tt_i64_op(((int64_t) 1) << 53, ==,
+ tt_i64_op(((int64_t) 1) << 53, OP_EQ,
clamp_double_to_int64(pow(2.0, 53.0)));
- tt_i64_op(INT64_MAX, ==,
+ tt_i64_op(INT64_MAX, OP_EQ,
clamp_double_to_int64(pow(2.0, 63.0)));
- tt_i64_op(INT64_MAX, ==,
+ tt_i64_op(INT64_MAX, OP_EQ,
clamp_double_to_int64(pow(2.0, 64.0)));
- tt_i64_op(INT64_MAX, ==, clamp_double_to_int64(INFINITY_DBL));
+ tt_i64_op(INT64_MAX, OP_EQ, clamp_double_to_int64(INFINITY_DBL));
done:
;
@@ -5053,7 +5346,7 @@ fd_is_cloexec(tor_socket_t fd)
int flags = fcntl(fd, F_GETFD, 0);
return (flags & FD_CLOEXEC) == FD_CLOEXEC;
}
-#endif
+#endif /* defined(FD_CLOEXEC) */
#ifndef _WIN32
#define CAN_CHECK_NONBLOCK
@@ -5063,7 +5356,7 @@ fd_is_nonblocking(tor_socket_t fd)
int flags = fcntl(fd, F_GETFL, 0);
return (flags & O_NONBLOCK) == O_NONBLOCK;
}
-#endif
+#endif /* !defined(_WIN32) */
#define ERRNO_IS_EPROTO(e) (e == SOCK_ERRNO(EPROTONOSUPPORT))
#define SOCK_ERR_IS_EPROTO(s) ERRNO_IS_EPROTO(tor_socket_errno(s))
@@ -5085,7 +5378,8 @@ test_util_socket(void *arg)
fd1 = tor_open_socket_with_extensions(domain, SOCK_STREAM, 0, 0, 0);
int err = tor_socket_errno(fd1);
- if (fd1 < 0 && err == SOCK_ERRNO(EPROTONOSUPPORT)) {
+ if (fd1 < 0 && (err == SOCK_ERRNO(EPROTONOSUPPORT) ||
+ err == SOCK_ERRNO(EAFNOSUPPORT))) {
/* Assume we're on an IPv4-only or IPv6-only system, and give up now. */
goto done;
}
@@ -5106,13 +5400,13 @@ test_util_socket(void *arg)
tt_int_op(fd_is_cloexec(fd2), OP_EQ, 0);
tt_int_op(fd_is_cloexec(fd3), OP_EQ, 1);
tt_int_op(fd_is_cloexec(fd4), OP_EQ, 1);
-#endif
+#endif /* defined(CAN_CHECK_CLOEXEC) */
#ifdef CAN_CHECK_NONBLOCK
tt_int_op(fd_is_nonblocking(fd1), OP_EQ, 0);
tt_int_op(fd_is_nonblocking(fd2), OP_EQ, 1);
tt_int_op(fd_is_nonblocking(fd3), OP_EQ, 0);
tt_int_op(fd_is_nonblocking(fd4), OP_EQ, 1);
-#endif
+#endif /* defined(CAN_CHECK_NONBLOCK) */
tor_assert(tor_close_socket == tor_close_socket__real);
@@ -5168,7 +5462,7 @@ is_there_a_localhost(int family)
return result;
}
-#endif
+#endif /* 0 */
/* Test for socketpair and ersatz_socketpair(). We test them both, since
* the latter is a tolerably good way to exersize tor_accept_socket(). */
@@ -5195,7 +5489,7 @@ test_util_socketpair(void *arg)
* Assume we're on a machine without 127.0.0.1 or ::1 and give up now. */
tt_skip();
}
-#endif
+#endif /* defined(__FreeBSD__) */
tt_int_op(0, OP_EQ, socketpair_result);
tt_assert(SOCKET_OK(fds[0]));
@@ -5356,7 +5650,7 @@ test_util_get_avail_disk_space(void *arg)
#else
tt_i64_op(val, OP_GT, 0); /* You have some space. */
tt_i64_op(val, OP_LT, ((int64_t)1)<<56); /* You don't have a zebibyte */
-#endif
+#endif /* !defined(HAVE_STATVFS) && !defined(_WIN32) */
done:
;
@@ -5406,25 +5700,25 @@ test_util_pwdb(void *arg)
/* Uncached case. */
/* Let's assume that we exist. */
me = tor_getpwuid(getuid());
- tt_assert(me != NULL);
+ tt_ptr_op(me, OP_NE, NULL);
name = tor_strdup(me->pw_name);
/* Uncached case */
me2 = tor_getpwnam(name);
- tt_assert(me2 != NULL);
+ tt_ptr_op(me2, OP_NE, NULL);
tt_int_op(me2->pw_uid, OP_EQ, getuid());
/* Cached case */
me3 = tor_getpwuid(getuid());
- tt_assert(me3 != NULL);
+ tt_ptr_op(me3, OP_NE, NULL);
tt_str_op(me3->pw_name, OP_EQ, name);
me3 = tor_getpwnam(name);
- tt_assert(me3 != NULL);
+ tt_ptr_op(me3, OP_NE, NULL);
tt_int_op(me3->pw_uid, OP_EQ, getuid());
dir = get_user_homedir(name);
- tt_assert(dir != NULL);
+ tt_ptr_op(dir, OP_NE, NULL);
/* Try failing cases. First find a user that doesn't exist by name */
char randbytes[4];
@@ -5444,7 +5738,7 @@ test_util_pwdb(void *arg)
/* We should do a LOG_ERR */
setup_full_capture_of_logs(LOG_ERR);
dir = get_user_homedir(badname);
- tt_assert(dir == NULL);
+ tt_ptr_op(dir, OP_EQ, NULL);
expect_log_msg_containing("not found");
tt_int_op(smartlist_len(mock_saved_logs()), OP_EQ, 1);
teardown_capture_of_logs();
@@ -5466,33 +5760,33 @@ test_util_pwdb(void *arg)
tor_free(dir);
teardown_capture_of_logs();
}
-#endif
+#endif /* !defined(_WIN32) */
static void
test_util_calloc_check(void *arg)
{
(void) arg;
/* Easy cases that are good. */
- tt_assert(size_mul_check__(0,0));
- tt_assert(size_mul_check__(0,100));
- tt_assert(size_mul_check__(100,0));
- tt_assert(size_mul_check__(100,100));
+ tt_assert(size_mul_check(0,0));
+ tt_assert(size_mul_check(0,100));
+ tt_assert(size_mul_check(100,0));
+ tt_assert(size_mul_check(100,100));
/* Harder cases that are still good. */
- tt_assert(size_mul_check__(SIZE_MAX, 1));
- tt_assert(size_mul_check__(1, SIZE_MAX));
- tt_assert(size_mul_check__(SIZE_MAX / 10, 9));
- tt_assert(size_mul_check__(11, SIZE_MAX / 12));
+ tt_assert(size_mul_check(SIZE_MAX, 1));
+ tt_assert(size_mul_check(1, SIZE_MAX));
+ tt_assert(size_mul_check(SIZE_MAX / 10, 9));
+ tt_assert(size_mul_check(11, SIZE_MAX / 12));
const size_t sqrt_size_max_p1 = ((size_t)1) << (sizeof(size_t) * 4);
- tt_assert(size_mul_check__(sqrt_size_max_p1, sqrt_size_max_p1 - 1));
+ tt_assert(size_mul_check(sqrt_size_max_p1, sqrt_size_max_p1 - 1));
/* Cases that overflow */
- tt_assert(! size_mul_check__(SIZE_MAX, 2));
- tt_assert(! size_mul_check__(2, SIZE_MAX));
- tt_assert(! size_mul_check__(SIZE_MAX / 10, 11));
- tt_assert(! size_mul_check__(11, SIZE_MAX / 10));
- tt_assert(! size_mul_check__(SIZE_MAX / 8, 9));
- tt_assert(! size_mul_check__(sqrt_size_max_p1, sqrt_size_max_p1));
+ tt_assert(! size_mul_check(SIZE_MAX, 2));
+ tt_assert(! size_mul_check(2, SIZE_MAX));
+ tt_assert(! size_mul_check(SIZE_MAX / 10, 11));
+ tt_assert(! size_mul_check(11, SIZE_MAX / 10));
+ tt_assert(! size_mul_check(SIZE_MAX / 8, 9));
+ tt_assert(! size_mul_check(sqrt_size_max_p1, sqrt_size_max_p1));
done:
;
@@ -5623,12 +5917,136 @@ test_util_monotonic_time_ratchet(void *arg)
;
}
+static void
+test_util_htonll(void *arg)
+{
+ (void)arg;
+#ifdef WORDS_BIGENDIAN
+ const uint64_t res_be = 0x8877665544332211;
+#else
+ const uint64_t res_le = 0x1122334455667788;
+#endif
+
+ tt_u64_op(0, OP_EQ, tor_htonll(0));
+ tt_u64_op(0, OP_EQ, tor_ntohll(0));
+ tt_u64_op(UINT64_MAX, OP_EQ, tor_htonll(UINT64_MAX));
+ tt_u64_op(UINT64_MAX, OP_EQ, tor_ntohll(UINT64_MAX));
+
+#ifdef WORDS_BIGENDIAN
+ tt_u64_op(res_be, OP_EQ, tor_htonll(0x8877665544332211));
+ tt_u64_op(res_be, OP_EQ, tor_ntohll(0x8877665544332211));
+#else
+ tt_u64_op(res_le, OP_EQ, tor_htonll(0x8877665544332211));
+ tt_u64_op(res_le, OP_EQ, tor_ntohll(0x8877665544332211));
+#endif /* defined(WORDS_BIGENDIAN) */
+
+ done:
+ ;
+}
+
+static void
+test_util_get_unquoted_path(void *arg)
+{
+ (void)arg;
+
+ char *r = NULL;
+
+ r = get_unquoted_path("\""); // "
+ tt_ptr_op(r, OP_EQ, NULL);
+ tor_free(r);
+
+ r = get_unquoted_path("\"\"\""); // """
+ tt_ptr_op(r, OP_EQ, NULL);
+ tor_free(r);
+
+ r = get_unquoted_path("\\\""); // \"
+ tt_ptr_op(r, OP_EQ, NULL);
+ tor_free(r);
+
+ r = get_unquoted_path("\\\"\\\""); // \"\"
+ tt_ptr_op(r, OP_EQ, NULL);
+ tor_free(r);
+
+ r = get_unquoted_path("A\\B\\C\""); // A\B\C"
+ tt_ptr_op(r, OP_EQ, NULL);
+ tor_free(r);
+
+ r = get_unquoted_path("\"A\\B\\C"); // "A\B\C
+ tt_ptr_op(r, OP_EQ, NULL);
+ tor_free(r);
+
+ r = get_unquoted_path("\"A\\B\"C\""); // "A\B"C"
+ tt_ptr_op(r, OP_EQ, NULL);
+ tor_free(r);
+
+ r = get_unquoted_path("A\\B\"C"); // A\B"C
+ tt_ptr_op(r, OP_EQ, NULL);
+ tor_free(r);
+
+ r = get_unquoted_path("");
+ tt_str_op(r, OP_EQ, "");
+ tor_free(r);
+
+ r = get_unquoted_path("\"\""); // ""
+ tt_str_op(r, OP_EQ, "");
+ tor_free(r);
+
+ r = get_unquoted_path("A\\B\\C"); // A\B\C
+ tt_str_op(r, OP_EQ, "A\\B\\C"); // A\B\C
+ tor_free(r);
+
+ r = get_unquoted_path("\"A\\B\\C\""); // "A\B\C"
+ tt_str_op(r, OP_EQ, "A\\B\\C"); // A\B\C
+ tor_free(r);
+
+ r = get_unquoted_path("\"\\\""); // "\"
+ tt_str_op(r, OP_EQ, "\\"); // \ /* comment to prevent line continuation */
+ tor_free(r);
+
+ r = get_unquoted_path("\"\\\"\""); // "\""
+ tt_str_op(r, OP_EQ, "\""); // "
+ tor_free(r);
+
+ r = get_unquoted_path("\"A\\B\\C\\\"\""); // "A\B\C\""
+ tt_str_op(r, OP_EQ, "A\\B\\C\""); // A\B\C"
+ tor_free(r);
+
+ r = get_unquoted_path("A\\B\\\"C"); // A\B\"C
+ tt_str_op(r, OP_EQ, "A\\B\"C"); // A\B"C
+ tor_free(r);
+
+ r = get_unquoted_path("\"A\\B\\\"C\""); // "A\B\"C"
+ tt_str_op(r, OP_EQ, "A\\B\"C"); // A\B"C
+
+ done:
+ tor_free(r);
+}
+
#define UTIL_LEGACY(name) \
{ #name, test_util_ ## name , 0, NULL, NULL }
#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) }
+
+#define COMPRESS_CONCAT(name, identifier) \
+ { "compress_concat/" #name, test_util_decompress_concatenated, 0, \
+ &passthrough_setup, \
+ (char*)(identifier) }
+
+#define COMPRESS_JUNK(name, identifier) \
+ { "compress_junk/" #name, test_util_decompress_junk, 0, \
+ &passthrough_setup, \
+ (char*)(identifier) }
+
+#define COMPRESS_DOS(name, identifier) \
+ { "compress_dos/" #name, test_util_decompress_dos, 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))
@@ -5637,7 +6055,7 @@ test_util_monotonic_time_ratchet(void *arg)
#define UTIL_TEST_NO_WIN(n, f) UTIL_TEST(n, (f))
#define UTIL_TEST_WIN_ONLY(n, f) { #n, NULL, TT_SKIP, NULL, NULL }
#define UTIL_LEGACY_NO_WIN(n) UTIL_LEGACY(n)
-#endif
+#endif /* defined(_WIN32) */
struct testcase_t util_tests[] = {
UTIL_LEGACY(time),
@@ -5653,7 +6071,23 @@ 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"),
+ COMPRESS_CONCAT(zlib, "deflate"),
+ COMPRESS_CONCAT(gzip, "gzip"),
+ COMPRESS_CONCAT(lzma, "x-tor-lzma"),
+ COMPRESS_CONCAT(zstd, "x-zstd"),
+ COMPRESS_CONCAT(none, "identity"),
+ COMPRESS_JUNK(zlib, "deflate"),
+ COMPRESS_JUNK(gzip, "gzip"),
+ COMPRESS_JUNK(lzma, "x-tor-lzma"),
+ COMPRESS_DOS(zlib, "deflate"),
+ COMPRESS_DOS(gzip, "gzip"),
+ COMPRESS_DOS(lzma, "x-tor-lzma"),
+ COMPRESS_DOS(zstd, "x-zstd"),
UTIL_TEST(gzip_compression_bomb, TT_FORK),
UTIL_LEGACY(datadir),
UTIL_LEGACY(memarea),
@@ -5677,7 +6111,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),
@@ -5716,6 +6150,8 @@ struct testcase_t util_tests[] = {
UTIL_TEST(calloc_check, 0),
UTIL_TEST(monotonic_time, 0),
UTIL_TEST(monotonic_time_ratchet, TT_FORK),
+ UTIL_TEST(htonll, 0),
+ UTIL_TEST(get_unquoted_path, 0),
END_OF_TESTCASES
};
diff --git a/src/test/test_util_format.c b/src/test/test_util_format.c
index 63a668238c..683d5fdac1 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"
@@ -11,25 +11,14 @@
#define NS_MODULE util_format
-#if !defined(HAVE_HTONLL) && !defined(htonll)
-#ifdef WORDS_BIGENDIAN
-#define htonll(x) (x)
-#else
-static uint64_t
-htonll(uint64_t a)
-{
- return htonl((uint32_t)(a>>32)) | (((uint64_t)htonl((uint32_t)a))<<32);
-}
-#endif
-#endif
-
static void
test_util_format_unaligned_accessors(void *ignored)
{
(void)ignored;
char buf[9] = "onionsoup"; // 6f6e696f6e736f7570
- tt_u64_op(get_uint64(buf+1), OP_EQ, htonll(U64_LITERAL(0x6e696f6e736f7570)));
+ tt_u64_op(get_uint64(buf+1), OP_EQ,
+ tor_htonll(U64_LITERAL(0x6e696f6e736f7570)));
tt_uint_op(get_uint32(buf+1), OP_EQ, htonl(0x6e696f6e));
tt_uint_op(get_uint16(buf+1), OP_EQ, htons(0x6e69));
tt_uint_op(get_uint8(buf+1), OP_EQ, 0x6e);
@@ -43,7 +32,7 @@ test_util_format_unaligned_accessors(void *ignored)
set_uint32(buf+1, htonl(0x78696465));
tt_mem_op(buf, OP_EQ, "oxidestop", 9);
- set_uint64(buf+1, htonll(U64_LITERAL(0x6266757363617465)));
+ set_uint64(buf+1, tor_htonll(U64_LITERAL(0x6266757363617465)));
tt_mem_op(buf, OP_EQ, "obfuscate", 9);
done:
;
@@ -144,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
@@ -207,10 +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);
+ res = base64_decode(dst, 1, real_src, 10);
tt_int_op(res, OP_EQ, -1);
const char *s = "T3BhIG11bmRv";
@@ -350,7 +345,7 @@ test_util_format_base32_decode(void *arg)
const char *src = "mjwgc2dcnrswqmjs";
ret = base32_decode(dst, strlen(expected), src, strlen(src));
- tt_int_op(ret, ==, 0);
+ tt_int_op(ret, OP_EQ, 0);
tt_str_op(expected, OP_EQ, dst);
}
@@ -361,7 +356,7 @@ test_util_format_base32_decode(void *arg)
const char *src = "mjwgc2dcnrswq";
ret = base32_decode(dst, strlen(expected), src, strlen(src));
- tt_int_op(ret, ==, 0);
+ tt_int_op(ret, OP_EQ, 0);
tt_mem_op(expected, OP_EQ, dst, strlen(expected));
}
@@ -369,20 +364,48 @@ test_util_format_base32_decode(void *arg)
{
/* Invalid character '#'. */
ret = base32_decode(dst, real_dstlen, "#abcde", 6);
- tt_int_op(ret, ==, -1);
+ tt_int_op(ret, OP_EQ, -1);
/* Make sure the destination buffer has been zeroed even on error. */
- tt_int_op(tor_mem_is_zero(dst, real_dstlen), ==, 1);
+ tt_int_op(tor_mem_is_zero(dst, real_dstlen), OP_EQ, 1);
}
done:
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 },
@@ -390,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..68ce6cfd40 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
@@ -67,7 +67,7 @@ test_util_process_clear_waitpid_callback(void *ignored)
done:
teardown_capture_of_logs();
}
-#endif /* _WIN32 */
+#endif /* !defined(_WIN32) */
#ifndef _WIN32
#define TEST(name) { #name, test_util_process_##name, 0, NULL, NULL }
diff --git a/src/test/test_util_slow.c b/src/test/test_util_slow.c
index 1e7160598c..2cd68cf118 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"
@@ -22,14 +22,14 @@
#else
#define TEST_CHILD (BUILDDIR "/src/test/test-child")
#define EOL "\n"
-#endif
+#endif /* defined(_WIN32) */
#ifdef _WIN32
/* I've assumed Windows doesn't have the gap between fork and exec
* that causes the race condition on unix-like platforms */
#define MATCH_PROCESS_STATUS(s1,s2) ((s1) == (s2))
-#else
+#else /* !(defined(_WIN32)) */
/* work around a race condition of the timing of SIGCHLD handler updates
* to the process_handle's fields, and checks of those fields
*
@@ -46,7 +46,7 @@
||((s2) == PROCESS_STATUS_RUNNING_OR_NOTRUNNING \
&& IS_RUNNING_OR_NOTRUNNING(s1)))
-#endif // _WIN32
+#endif /* defined(_WIN32) */
/** Helper function for testing tor_spawn_background */
static void
@@ -78,7 +78,7 @@ run_util_spawn_background(const char *argv[], const char *expected_out,
return;
}
- tt_assert(process_handle != NULL);
+ tt_ptr_op(process_handle, OP_NE, NULL);
/* When a spawned process forks, fails, then exits very quickly,
* (this typically occurs when exec fails)
@@ -102,7 +102,7 @@ run_util_spawn_background(const char *argv[], const char *expected_out,
* that is, PROCESS_STATUS_RUNNING_OR_NOTRUNNING */
tt_assert(process_handle->waitpid_cb != NULL
|| expected_status == PROCESS_STATUS_RUNNING_OR_NOTRUNNING);
-#endif
+#endif /* !defined(_WIN32) */
#ifdef _WIN32
tt_assert(process_handle->stdout_pipe != INVALID_HANDLE_VALUE);
@@ -112,7 +112,7 @@ run_util_spawn_background(const char *argv[], const char *expected_out,
tt_assert(process_handle->stdout_pipe >= 0);
tt_assert(process_handle->stderr_pipe >= 0);
tt_assert(process_handle->stdin_pipe >= 0);
-#endif
+#endif /* defined(_WIN32) */
/* Check stdout */
pos = tor_read_all_from_process_stdout(process_handle, stdout_buf,
@@ -178,7 +178,7 @@ test_util_spawn_background_fail(void *ptr)
/* TODO: Once we can signal failure to exec, set this to be
* PROCESS_STATUS_RUNNING_OR_ERROR */
const int expected_status = PROCESS_STATUS_RUNNING_OR_NOTRUNNING;
-#endif
+#endif /* defined(_WIN32) */
memset(expected_out, 0xf0, sizeof(expected_out));
memset(code, 0xf0, sizeof(code));
@@ -242,9 +242,9 @@ 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
+#endif /* defined(_WIN32) */
log_info(LD_GENERAL, "tor_read_all_handle() returned %d", (int)pos);
/* We would have blocked, keep on trying */
@@ -270,17 +270,17 @@ test_util_spawn_background_partial_read_impl(int exit_early)
sizeof(stdout_buf) - 1,
process_handle);
tt_int_op(0,OP_EQ, pos);
-#else
+#else /* !(defined(_WIN32)) */
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);
tt_assert(eof);
}
/* Otherwise, we got the EOF on the last read */
-#endif
+#endif /* defined(_WIN32) */
/* Check it terminated correctly */
retval = tor_get_exit_code(process_handle, 1, &exit_code);
@@ -351,7 +351,7 @@ test_util_spawn_background_waitpid_notify(void *arg)
}
tt_int_op(ms_timer, OP_GT, 0);
tt_ptr_op(process_handle->waitpid_cb, OP_EQ, NULL);
-#endif
+#endif /* !defined(_WIN32) */
ms_timer = 30*1000;
while (((retval = tor_get_exit_code(process_handle, 0, &exit_code))
diff --git a/src/test/test_workqueue.c b/src/test/test_workqueue.c
index ccb8d0c8ca..2b03173717 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"
@@ -61,9 +61,9 @@ mark_handled(int serial)
tor_assert(! bitarray_is_set(handled, serial));
bitarray_set(handled, serial);
tor_mutex_release(&bitmap_mutex);
-#else
+#else /* !(defined(TRACK_RESPONSES)) */
(void)serial;
-#endif
+#endif /* defined(TRACK_RESPONSES) */
}
static workqueue_reply_t
@@ -200,7 +200,9 @@ add_work(threadpool_t *tp)
crypto_rand((char*)w->msg, 20);
w->msglen = 20;
++rsa_sent;
- return threadpool_queue_work(tp, workqueue_do_rsa, handle_reply, w);
+ return threadpool_queue_work_priority(tp,
+ WQ_PRI_MED,
+ workqueue_do_rsa, handle_reply, w);
} else {
ecdh_work_t *w = tor_malloc_zero(sizeof(*w));
w->serial = n_sent++;
@@ -286,7 +288,7 @@ replysock_readable_cb(tor_socket_t sock, short what, void *arg)
}
puts("");
tor_mutex_release(&bitmap_mutex);
-#endif
+#endif /* defined(TRACK_RESPONSES) */
if (n_sent - (n_received+n_successful_cancel) < opt_n_lowwater) {
int n_to_send = n_received + opt_n_inflight - n_sent;
@@ -420,7 +422,7 @@ main(int argc, char **argv)
received = bitarray_init_zero(opt_n_items);
tor_mutex_init(&bitmap_mutex);
handled_len = opt_n_items;
-#endif
+#endif /* defined(TRACK_RESPONSES) */
for (i = 0; i < opt_n_inflight; ++i) {
if (! add_work(tp)) {
diff --git a/src/test/testing_common.c b/src/test/testing_common.c
index 9c6580f788..7e9c47b48d 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[];
@@ -21,6 +21,7 @@ const char tor_git_revision[] = "";
#include "rephist.h"
#include "backtrace.h"
#include "test.h"
+#include "channelpadding.h"
#include <stdio.h>
#ifdef HAVE_FCNTL_H
@@ -32,13 +33,12 @@ const char tor_git_revision[] = "";
#include <direct.h>
#else
#include <dirent.h>
-#endif
+#endif /* defined(_WIN32) */
#include "or.h"
#ifdef USE_DMALLOC
#include <dmalloc.h>
-#include <openssl/crypto.h>
#include "main.h"
#endif
@@ -84,7 +84,7 @@ setup_directory(void)
(int)getpid(), rnd32);
r = mkdir(temp_dir);
}
-#else
+#else /* !(defined(_WIN32)) */
tor_snprintf(temp_dir, sizeof(temp_dir), "/tmp/tor_test_%d_%s",
(int) getpid(), rnd32);
r = mkdir(temp_dir, 0700);
@@ -92,7 +92,7 @@ setup_directory(void)
/* undo sticky bit so tests don't get confused. */
r = chown(temp_dir, getuid(), getgid());
}
-#endif
+#endif /* defined(_WIN32) */
if (r) {
fprintf(stderr, "Can't create directory %s:", temp_dir);
perror("");
@@ -178,65 +178,6 @@ remove_directory(void)
rm_rf(temp_dir);
}
-/** Define this if unit tests spend too much time generating public keys*/
-#define CACHE_GENERATED_KEYS
-
-#define N_PREGEN_KEYS 11
-static crypto_pk_t *pregen_keys[N_PREGEN_KEYS];
-static int next_key_idx;
-
-/** Generate and return a new keypair for use in unit tests. If we're using
- * the key cache optimization, we might reuse keys. "idx" is ignored.
- * Our only guarantee is that we won't reuse a key till this function has been
- * called several times. The order in which keys are returned is slightly
- * randomized, so that tests that depend on a particular order will not be
- * reliable. */
-crypto_pk_t *
-pk_generate(int idx)
-{
- (void) idx;
-#ifdef CACHE_GENERATED_KEYS
- /* Either skip 1 or 2 keys. */
- next_key_idx += crypto_rand_int_range(1,3);
- next_key_idx %= N_PREGEN_KEYS;
- return crypto_pk_dup_key(pregen_keys[next_key_idx]);
-#else
- crypto_pk_t *result;
- int res;
- result = crypto_pk_new();
- res = crypto_pk_generate_key__real(result);
- tor_assert(!res);
- return result;
-#endif
-}
-
-#ifdef CACHE_GENERATED_KEYS
-static int
-crypto_pk_generate_key_with_bits__get_cached(crypto_pk_t *env, int bits)
-{
- if (bits != 1024)
- return crypto_pk_generate_key_with_bits__real(env, bits);
-
- crypto_pk_t *newkey = pk_generate(0);
- crypto_pk_assign_(env, newkey);
- crypto_pk_free(newkey);
- return 0;
-}
-#endif
-
-/** Free all storage used for the cached key optimization. */
-static void
-free_pregenerated_keys(void)
-{
- unsigned idx;
- for (idx = 0; idx < N_PREGEN_KEYS; ++idx) {
- if (pregen_keys[idx]) {
- crypto_pk_free(pregen_keys[idx]);
- pregen_keys[idx] = NULL;
- }
- }
-}
-
static void *
passthrough_test_setup(const struct testcase_t *testcase)
{
@@ -297,14 +238,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
+#endif /* defined(USE_DMALLOC) */
update_approx_time(time(NULL));
options = options_new();
tor_threads_init();
+ tor_compress_init();
network_init();
@@ -363,17 +305,14 @@ main(int c, const char **v)
tor_free(errmsg);
return 1;
}
+
tor_set_failed_assertion_callback(an_assertion_failed);
-#ifdef CACHE_GENERATED_KEYS
- for (i = 0; i < N_PREGEN_KEYS; ++i) {
- pregen_keys[i] = crypto_pk_new();
- int r = crypto_pk_generate_key(pregen_keys[i]);
- tor_assert(r == 0);
- }
- MOCK(crypto_pk_generate_key_with_bits,
- crypto_pk_generate_key_with_bits__get_cached);
-#endif
+ init_pregenerated_keys();
+
+ channelpadding_new_consensus_params(NULL);
+
+ predicted_ports_init();
atexit(remove_directory);
diff --git a/src/test/testing_rsakeys.c b/src/test/testing_rsakeys.c
new file mode 100644
index 0000000000..7a24c0ed14
--- /dev/null
+++ b/src/test/testing_rsakeys.c
@@ -0,0 +1,546 @@
+/* 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"
+#include "or.h"
+#include "test.h"
+
+/** Define this if unit tests spend too much time generating public keys.
+ * This module is meant to save time by using a bunch of pregenerated RSA
+keys among */
+#define USE_PREGENERATED_RSA_KEYS
+
+#ifdef USE_PREGENERATED_RSA_KEYS
+
+static const char *PREGEN_KEYS_1024[] = {
+"-----BEGIN RSA PRIVATE KEY-----\n"
+"MIICWwIBAAKBgQCZa39BCgq7KWBWFSjGYHhqmTCHvQ7WNEFAb9Mujb6Xn/Zy01fu\n"
+"WIpVvqmAKeLNEziItUm/gB8GwAN+/ZLwL9pufjIp2Ar+yqVXKySioZQxuCgTP2wm\n"
+"Ku0OfmAra1Xbtrkc2OCJllxkyNPrJ/kxfwjWR96UP0+VMbOlkBoEH1FtvwIDAQAB\n"
+"AoGAUXoygeMIYe+OdwkTt48CRHKIwH3aRE5KHSOGPyIOB05vvvmYqD8jcHgqYqNc\n"
+"DNdZXdkRin9LevU8phObFq4DTXp08XggUx4Kk4AdsFKubQtJ8gHm3xlSKbZXX2m/\n"
+"ZF0GRaZtVDQ3TRGh+OBLILt/2jT+BaFKGAyJ7al76F2nprECQQDJyLlteLDFBmrd\n"
+"0kAjNBE50S5YskBCQeQACROfyTKW8lG1J57UBeYjXvbrDFBR4alIS9DEexGai9Gz\n"
+"wxpgKg2nAkEAwqQmPstjHxvqGQRi41uXO026MLxY7dhEqs1aSw3tuT8v17pW3OEa\n"
+"Qxv7JINePZ3+sNN+Ic+3RXBR0QuD7lSSKQJAZjVSF21GvMXfY7SX4D0DbLHUNAE2\n"
+"I1mUz5/JXOpgwazETmpfPS4vwELd93kpRhBz2rbsbFmaNRoVgmSU+5jRiQJAZ1bV\n"
+"g2NilgKxEGU2x3U6Xt8Oqo9lO6omEvUCKnUTsNWuZf/l3FGbKuQxO5qPr3Ex5tny\n"
+"zqrEqBZRKgbOHfxCuQJAbJY5C3Nm5koemr031r00MY2YD1b6+hyKZyPdZ21HpyY8\n"
+"z1kWShL0POjYPX/BnKE1FkpklWcKBb7wkK7dvAKkEQ==\n"
+"-----END RSA PRIVATE KEY-----\n",
+
+"-----BEGIN RSA PRIVATE KEY-----\n"
+"MIICXQIBAAKBgQCyqMM2TfFGV5tVBTVabxLVln8146nDavIdR6q78DCUMh8Zfzkk\n"
+"h9Lbl1NX4RU+AmrCZMPq21/EjIRxRQyRdgPYJVLdp96eGeYnEzmMkqvXiswXvDg/\n"
+"tXqsjyJeYsoHMQWDTpCLfjYo4K1ol1sg8VIs4wQeq5og6QSdmhBoz7MyqQIDAQAB\n"
+"AoGBAIJekey7nZeV8Bxva4ptSRIg+v0I/2VBUiG5nUX9NIW/uV/yrXERx/VDjKaw\n"
+"8b5JJzxpKWnk4RJc83xwRYaT1qMYHiQfybxEI0K9SjhtaThAjtXkQGtZgLJILl3t\n"
+"yh3LPTh1ocwafsKjU6eGYAe/DYn9/QwYHbtyaimcigu4etp9AkEA2DgC+HndoP1i\n"
+"np26Lx+4TG0vAfrVYGSLT9FXwf2iBV3oJvdKqu6wr8ipb1SbshRPcOQd31/mCh6+\n"
+"2BR+d4ddcwJBANOHrlBbGZdHnoEu6kKbPwwkc31IZYqyfSpkqm0Lb2oWZ9SInKfc\n"
+"cz0qpH91p610XUpYmycaJr4K+N8jgrz86HMCQQCoqGBg1Ca2OpCf66bctWB8dTqS\n"
+"z8d7rlIhC8npr1+f0hWRt5pN5Wx7YgoQpq3gZgllpPtMT7DQOhVh1fKkaDnTAkA4\n"
+"XuskPPLX7t0dvhvtviOSH9CrLXTp/mD+wC7uumJpmij3aaSd01DelxOZaAhUYDNQ\n"
+"UcafKAf1E0V5aaQ4qwljAkA9NVN6CtpzzcLrstTKxrx5P1Ylt/0UYQDo1lIaqwrT\n"
+"aOFbXmOungiC9+p/4U7RbX0MEzjFDHCWlaHASviGVgta\n"
+"-----END RSA PRIVATE KEY-----\n",
+
+"-----BEGIN RSA PRIVATE KEY-----\n"
+"MIICWwIBAAKBgQDDt2V63APj3JSqaRgofUzhtB+prm0wII4uHyxfOxnpYIELOW5z\n"
+"3UHmkr+B4D+Nif5jIp0i6W4OS4S+YHewKsDsXvXKRIW78KzOt6Le4JI9rSarNjy5\n"
+"aJKksWQRALLCmxP/BdolaBFqF3fIPD5+Zxu8ESgxhkEQI4p7awUp3E730QIDAQAB\n"
+"AoGAZktfAR4p8lkCYydW9yK2ommQ+xEuBK+fYL/uYz/yxSYpjIJSFsEYhrlA21Mo\n"
+"JIRxr8MRuoOjgFk8YnztUeimuHpslDlZDaCBzjRjBRFCMepZNG9xqSEL0u7C+SH6\n"
+"KU5f2x2P6PneBj6WaHZM+6Lf2xHlOoeuaVSUfq2Pk2VBF9kCQQDtawWWNwP0+xea\n"
+"oCAQpanaLzYPjlqZfHJQ1AAI5eSkdf1qmlypIHwOtjAEa6XuEO/Or8RNkNy4nQdw\n"
+"qhcQ7PXDAkEA0wjT6Z+Lrt67FnwPgoSvl4Nukcqw4OWHbBKhaQPsO9+oc3PAXLdD\n"
+"SclUUqDF6NX1yONTV1KrPdz4zElmEua+2wJABm4inZnp2oW+cuqpU6oY+pbSwQMb\n"
+"AxMyyWukgJkxYx7q+SsrHU2K7p8Sl9wOh28f/5oVGAC3aayfGfcRXtz8HwJAIqeO\n"
+"dQzYGU1GF7kjquEzHIRewd4xEZ1fkaW1j9MvFd3ygZL+gbsud41yJWd1WHjaNbTu\n"
+"2KYgrLX+vT1IX844hQJAbg0V7iHlttQqXL7yN09jIjQLprqVhDZCUHS9s9Dxe7fz\n"
+"Ac0ZZD0D6EVNmSmBB71q7kLUWX/W/10d447TLnnfew==\n"
+"-----END RSA PRIVATE KEY-----\n",
+
+"-----BEGIN RSA PRIVATE KEY-----\n"
+"MIICXgIBAAKBgQDhCAjPEockl4lqkvoIb5O3NJJG8NWD31c63e/cPWY6MX5nOM/q\n"
+"avof2eWJxFOk0HQ2BRVwIgNex6kLxtsdw7XE0A5uZorTp9DbRCGMqUqHNhHH9ci2\n"
+"mMPP9jptq3ieWg310bH4Tad8h3WE2npSCDBvxyV6EmuH2rlQW9ZlHNoiRQIDAQAB\n"
+"AoGBAI4PgWggPTqng7PJF5mNvsYQpSutzE0VCL977nmuNUQVjMPjRLarVD4ZU+QW\n"
+"EevhQQv9R5xjjJcgGqL5pchzjeKDm0/LA+AygnZoDMs2O68Neieqvr7cPqr5ALGs\n"
+"WuZvSn+bRJTenvV9sUh2ii0/u3GQbL1v7GWDkIdD7itDbmRhAkEA8iijuEY+W67w\n"
+"7JusjY2MQ2Cm6xxxR0YcnYPzT6UDm+Z7NNJwKscQ6AjayNmxmXGpbUdukzLzXf8y\n"
+"fccI9t6iHQJBAO3kx9nZay0Ktl51QP5o2gwoqRIbnogGfR06KJOlzIPGR0aPn8cg\n"
+"uKq2SiyjewEaSBM6S/4UlxYUmvc3VKnxCEkCQQDpTjg2YQ7RPGIIRA/iLV7Wx3bq\n"
+"C/QjjCwjoi44LK6mdE9928WPoUzrkSRg4EQYpwZqL6kcDrmkdSuLPMipOGQNAkA3\n"
+"KtzlujPOiDNuiEaAORSHyU4b8ue6p7aP9pK+Wq6oyGxzAo+NABuTCx78ZxT5Vnzs\n"
+"aJKC44d+CV0+g0hQ+KJxAkEAqFYzNWIzTHX8DVDdK9BpUaBg1DFxIeP5Kk+/X3FF\n"
+"5BafG08B6OiLf8qIGGsxLXNRjIE0GVp3Sy23FUKtUymP+A==\n"
+"-----END RSA PRIVATE KEY-----\n",
+
+"-----BEGIN RSA PRIVATE KEY-----\n"
+"MIICXQIBAAKBgQDMDk01VwPxQq/BAwOBmfGUP/x5BQn+uxI0Aat6bdWuz/2CsjbS\n"
+"CWD/YLCaPm+DpHp9RMwk4HONJaw4B2XOw3ELPx7y9DEgdC1wZ9wRkJmqr2IJZoZR\n"
+"C7x43nNv+/IXTiRkkljCcMpoL1Tld+L2VbmWR29PdZwvspWRILkEZu1mNwIDAQAB\n"
+"AoGANvFK3KfXSei4xfF3yjeXEmHAKx2uOUZJenNQpqBYPr+F9ODjXd5knZ59LqrM\n"
+"/9cTnBMgHHXK5yBTpKppQSjikLeQ2BF04Ktff9oGqVcS9x/rKo0CREuxsEfawZOW\n"
+"OzOWENp4YcDKGP1I/Ctr185QzStaWrXVQftxmYQ53T77ShECQQDnhabwtqW7rfe4\n"
+"+MfkWEJ9Y2s6iMs3JWnwPOX9G9R39PiAD4vAghHJyHHttS9Ipxmvp0hThu0x7a4g\n"
+"8BfUpqgjAkEA4aFAmzarWKigREAACVTYH2RHpXbuk05vF9WqfMPiEvQUd5a1q6vc\n"
+"xkGZsE3v/TExLjPRZP4FeUNV5sD7THzA3QJBAJxPoRlNx3GCEAlDdfnWGPX9JI09\n"
+"hC40RWUcSI7ttjJTI1+an1kWuBnLChhaRpU/tFjikTNLmmMmPHUihIRfDI8CQG7g\n"
+"3WzpKr8A7vFbOilbxnF2yDaqAYfmTXW7DHMPl/OUetJh/5kDdhT/e9VGF5+nIvH/\n"
+"iPFGW85Bpt8lCtmFnQkCQQDjpp9iy2qesE7KKX4Kv3++QfCJ2w3g7lwg4iyncoDd\n"
+"JrM53p29HROM21R6eekvqeWIe9tEX754b+E/N60ZjpGm\n"
+"-----END RSA PRIVATE KEY-----\n",
+
+"-----BEGIN RSA PRIVATE KEY-----\n"
+"MIICXgIBAAKBgQDdDn3H+Eu0AW5GKohqDBntw6ubnd3VaJwZGzZyga4J2kLg8peP\n"
+"RAW6GDD6pcHzW+KZbFWHtRk70FSwvmyGcf+DY0r5tfyCHyDGmbJyPR0o6OVCgSFl\n"
+"ccf4eDvbyszzMdlx3uL05ABIpCShoKtEUqvyIQla3Jon+QBwuVkizMzyVwIDAQAB\n"
+"AoGACoKh4Fwh3VEkGRn0mnYw1Wk0Q5Xh8j+jDF6K3C7mQ3mpLGDca+dkDlEQIxq2\n"
+"egeoYnsQJf+qT3m8TRsAtfO9nj7+7IX4BfCtdIi4RNcorbs5YMWtFyaywnM6SQjS\n"
+"+1qf74aL4On9WRO2FtvnTMjFAAkiWNbQp7mWwTmB59i620ECQQDwde6/PwhUzvZh\n"
+"dyslKJdna5RjkDQyDIuh0zD/tFZ0Iko7Luec8q6n52ev/n0OiTLGetUh8goePsPP\n"
+"HVZHidNJAkEA61eMCmmu+GCAg2vJRtL5sDakAXsbP5M9Bf/QVHXtc4EVXHC6T2ld\n"
+"bldOJriNbBThBuPNmlQbssn9FApkyWT4nwJBAIuHIv3+CUuMvBJaH8L0BsaP+g67\n"
+"wk24Ud2Yujnl3rSMoR4uXV8IwqfS8quAs/gXTEs3QyzrUUuzh9NKZqIkK2ECQQCz\n"
+"vivBEDKIlPvSZBJYO25kfXcJgoKvLb9fw5/TwjXXD/HGpnpFiI3JZnjT7gRlVhT/\n"
+"9CDmC/MTvF3EXqPXhXy1AkEAo3a2me23Ljmub21jycSKaCk09dK85QTRRMe9c/hs\n"
+"i+pcGi9ZZW0Mm7cyQo47oXjNurkkv0fEvXIobVTEXAGU7w==\n"
+"-----END RSA PRIVATE KEY-----\n",
+
+"-----BEGIN RSA PRIVATE KEY-----\n"
+"MIICXAIBAAKBgQCv8R1IbfYnE3R3kNeezJ7m02XnyCBDDy0YfrQldQ+urdg1CFye\n"
+"bO0iPniJb8fmV8NW7x6nUZTDznCg+igroKXtK/w0WYmJJiH4A7Oi5xNjAfRIPvJ/\n"
+"J5GI8szS8rH8tp8pW1h8k/kNg2pnBjwQ2U9omhp95RGaHDQSRYzzH/fEFQIDAQAB\n"
+"AoGAcy7+BcH/iZuB/xjzIIJDcUhqibCJ9n0D/+pLU85sYuZrCmUcBZe4M1gEn61v\n"
+"iExilRJc1hthskL/l1POYql8lk+aqeeDuh38fWJj60TCV/sENiuXOsTmoFVA5pNn\n"
+"lwlG8JlpBMsgr1fGqg1C/WLFfMmvXdKVGvpRqI06j7AYUa0CQQDfZ5rI+FhXBlxo\n"
+"PR5CM1LB90DuHUMW+Kqoj0c9d2esXEQM7UqQ/9BiBQbL6Py7Z3VwCxibOqyz7+V7\n"
+"2aGUMAKnAkEAyZy5Mu2tHs6YBBxPYam7huzMUYjddN7ixAZUyGwxQp9kTIF2NbSQ\n"
+"yVDjKrco3s2lO4qj4pSumwVe3GGlsi6G4wJAOOS3pIqqZK84BUvbUtyjLMZ9AKbv\n"
+"GQCG5ZpneB3ahyiQJAKiRL8BIJVLH87b3hYA8GHDCHUu2jwz4xCPd5+qbQJAV0TP\n"
+"pYvb9AnZI25drhiaY7z8dA6aTYxs/A0Bhf/PEteLwtIHKRgP1BR/QG4n8slxTGSm\n"
+"q91P9ypL9XkPECGzoQJBAIMvGEM7ZGevQHBjJ8HhU8IsgT4cYH/XEYb8jRy4F+Ui\n"
+"jKxHPxLuFK4urAZunNUNrqhT0PxbB7hRjtHZrmFkrcc=\n"
+"-----END RSA PRIVATE KEY-----\n",
+
+"-----BEGIN RSA PRIVATE KEY-----\n"
+"MIICXQIBAAKBgQDSpmV8ncLwc8gXzdFsZGPDtMO7C/IN9jKCIK13WIseMg1APlMt\n"
+"PB5lMQ9fa3m9ZRU0L8HzRo+u/Xdos3yIBI38X2Avy0laGKnQxiOKaDT/5ZHeiBBh\n"
+"nMZjP2WY5V1sgqNP9RD8enE6WaSvq1j0BM++mn9KEe//5+dWD8tboBKF4QIDAQAB\n"
+"AoGBALgVoerdE1Z+WAY1XyaSNHz6o3H6ZnW9CTaex/jb7/dbVikmThnhx842qXCB\n"
+"w8m3ZGhOs/edWkNaTde5wsI6+LhVGco/PWxN4v61jokxUU+5KvUvGacXhXIjzKwG\n"
+"DrNCYmle62QCI1z4+TLQW/Lq+jw2Wzk70NWEvoP58gt5SJoBAkEA9wubRKRs49LW\n"
+"5JNQZ9hjc+mAfP9YK/sMe4jkdloMMWXjSMlF3Z4mI9XQSpfbBqwWIBXsjU/15LIS\n"
+"ftmujZsMKQJBANpJEZI7UFoRdSP7AlM0YJuXWnVGyn/K+VIeEso5AlZdKXCTpxqp\n"
+"9blWq0UVC6jLesZ5UNPuBiAnrBaVwDA8YvkCQF+FQVfdK607TJO80g4VAP9EfcXX\n"
+"BUScIUtytsN8NdKzzpnKGRWDnMOmXI87ABkoWLW3RGuvSyhOIhCiInfmR2ECQASc\n"
+"FmroJcJBLCAeZOYs7P1cLOTdIdmhB7LcP7lVit8YCJAADj9Z536KfgNvdleSNH2M\n"
+"glB3blmvfMrdTrm2DMECQQDj6GJ/Tc2rCsq534xknasVjrgtJMQFxmQCTVgBx9pc\n"
+"gTflJAHAmNDvstacVqeObLCF2ZIvya8fSXGbDOJYeGDv\n"
+"-----END RSA PRIVATE KEY-----\n",
+
+"-----BEGIN RSA PRIVATE KEY-----\n"
+"MIICXAIBAAKBgQDGgUJAm7vf/3focNGwzv4TkzYF2XwpAirnb61dyxvfug1zKv2k\n"
+"AUg3qACiurR7JrI+kAbmxEnNaKV7ts7uO763wP9KE8YAuFZsp7NFA295rEZhw38T\n"
+"rUlWHMCeaZ3mqW2q8gA14C/ZJCG4gS91SIHLjNGsbHwr2Jvri2ItwIP8FQIDAQAB\n"
+"AoGAONceb32oiHWQkkBr6uL6ogRPPdGO2fdC7c5uqCLWsnOGEmpHAsVTNoym0fIA\n"
+"aBsmgv+e2klukKDccdZg3prA+z7lHcc2a4bIFguF6ei80hLIis/dds66fFXofCzy\n"
+"DMlkncSbJwIvQHG9gblxp9qSKElZF7XjABZEImarfUlakGkCQQD//msGy5N0ZhMI\n"
+"yGMXkwXRJXfmRrIrOqHx6u1eUp4OuqDW+hBz4KCHnWfuRJkNGQIammSf18jPasP5\n"
+"YHyr/LifAkEAxoJ8R8Vusexo9ZjuU44qXCSvJQ26UBV7mn6TGEAn2DRK1RWKDaHv\n"
+"j2vnRjt3CO9WPDQL7SB/1HNAy+dIMPyqywJBAIB6tESIz8zPniX+TJ18UKMTZwXP\n"
+"3YQMvVKpUdDRLjq+OBMtFizSRD9MJOlUzGvibUfkzTPcHRDcyNbUMj4vbIkCQBx4\n"
+"6sqAjvgGKKfRX52sbnb47AYsieSisC/gp8h6qzxfg7w8cqix6WJw36M7ND+b1Iqe\n"
+"DHfeiXc3cLvOWJRuKTECQCEYkujtSjXWb26xaESFWGtUI/nEvCyqYPQAFBpaGzQ3\n"
+"tiTDeKHzypesWYoTxOiNQWCQMLrFGuUbDpYOuDOVNjw=\n"
+"-----END RSA PRIVATE KEY-----\n",
+
+"-----BEGIN RSA PRIVATE KEY-----\n"
+"MIICXQIBAAKBgQCcwSAfytnspSSDX/sKmCPOMnpuCYeWA4wbz1wLyb63a8/KXhhG\n"
+"6o2W0kt3x1vnGZkeWwZOeBFUqwoc+xHhoNcZFsMOyqbqA3UMZW5cx27MsexRTQHs\n"
+"Go1newu/E+8NNCohY51G7z1Hdo0L6mi/Tldh7puuGsMwKqNG/Vvo/GQDgwIDAQAB\n"
+"AoGBAIUdpBAbjXDe1OET0vYuOMnUKA/l29RS8tpy/zGrg1/0GCM8QNWIPfEEaL4w\n"
+"+CSKonMazYI5iE4kaZQuygKXOdFqKxX8nrGK2hR0DIEUHhhiqyGMUKrf4ELkAJzK\n"
+"tHtcO64OFEU2EGa72wCmyk2MhqhLxWxA7E00x24uvW6pen6xAkEAzHhbzlRgLZ+K\n"
+"QuXmQHEqkGaS2Ccf6c9TA5Bf5S2/5zBl+OqVyJJQH0yrbPYR6Nn1NeSv3R4IDJYg\n"
+"fSZLaVzWHQJBAMRCU6QtTnZoQ97pLvXCSKRYKJF+CnE3zDFTyoJrpK0W1FSnb1EE\n"
+"DWjjdSdMLynf/InX+VOaLk3Gxwjme4NKjh8CQQCg2b4/HplayrsVzY3I/D2jw02Z\n"
+"xY2RfYusrhMCU284DBbsLn8OfiuRs9rXqOyF5ZDFiNXgeROT8zYzvcBtbp7xAkBU\n"
+"ZET9IvJLXjhZISItUXbVHIeNUIqC9sBaMbKx9EGioF97a2gliT2O7cgRtuPM+ODq\n"
+"ETHILlNc5G3vuNRBt4x3AkBV98Y1SZA3TQlUVTsjGraxkFTfU1IlomiOdOwTQ+xZ\n"
+"x+JxhhgZwZ+kgI3PidEufFCTZJ3WO6Wk9gk18Bx7CLjm\n"
+"-----END RSA PRIVATE KEY-----\n",
+
+"-----BEGIN RSA PRIVATE KEY-----\n"
+"MIICXgIBAAKBgQDq/K7wNW3fcTbaRTjNZlM4W0G7tKeO+X0bca4+9uin3ML3ogNJ\n"
+"6qT/B0QAZB6Vyi9kKa3E8plQkjmPuX8Q27zj2QjEuDZ12RGFnikeOosUhOYiDh3Z\n"
+"T9CHnr6stozzgk79Xd6VI7bqRcgRwbY0uc9QVr6vwddyIfSploSpVcgspQIDAQAB\n"
+"AoGBAJfUpo/sZc6uzxtfCKGmkPTj+ef3hSBbUZuu60AhtxfnC06HrwpOg0eJAUYj\n"
+"aqOsHMziJTYQ7kDiCjE0UMaqxDNS5hueumznq2xM2mSN0nYoktU00kpANVkW4VPA\n"
+"33TB16DyqlKq2/21Rs1g8/8+IKkKDbRLTC//1WqNHASQVoGNAkEA/+z4hxTVXZkr\n"
+"9hz29tAHKURlqzxUEKLnS0eL+XGJRNfGJ+65eXL+gFiIbTnpVeidL1+lKWkZyYzl\n"
+"75cNRdUHhwJBAOsOJ9mUOqTbLW5tzh18ewZGOa1JcxhOvf2E1d56N8tDK6lvoqkF\n"
+"oUUb8kIweDxPLCVLCl8qFrbjn619fxDInXMCQAfEZGKNIlCd5nSoumIRPDZnagKB\n"
+"aTe8CfMB7+CZLoZVWiE6IIzsDYdNqI5QFKHT1nlqmLOiCfNRAGV+GxwEdB8CQQDE\n"
+"sHu4HclU2fMSTOAE3H01qt3om2WsGXfyBI3SNQMrG3IVvkymkwd4BQKbUGPMU5Pl\n"
+"QP3U1CtdruuXCUSijrzxAkEAoqYub6+0zM8fakSQZcZ01TG9Fuo2xVFDCQsvqR3m\n"
+"ZhRT/oinIvOxSh4fQs40bmt1RBmc2L1Is6YB2NTVQEBZDQ==\n"
+"-----END RSA PRIVATE KEY-----\n",
+
+"-----BEGIN RSA PRIVATE KEY-----\n"
+"MIICWwIBAAKBgQCrf0rPvHYaGYQrc1ciRwaONs8TUvSVmUU98HMYXoFEkBL4CAGH\n"
+"4oNHFk8kXHEOsBED0eccSYegWhqKHSz7PbjmJaXloExWrtx5ea3Twf8VTgcfDWQP\n"
+"0TzD3G1TYjAFPQ1/LAZCpQFmwpMmTGGxegUhOzkpEWXdLVEVc9Uw4C4L2QIDAQAB\n"
+"AoGAZXAJZA5pHM7y6nBynYe9TOkGWru6h7H8zsImkcd0VoWRcrvpi+JjG+0KKsuy\n"
+"46kop0XEmWq0mhgxknfnX0QG1MKTqGMIUGN4qCaezOabIpCOdA4d/pr/mWoNgOWw\n"
+"9Kc/tNCrKxPKsQMAlWP6ktHN30XRSlHgAjSeUVUiNHztvTECQQDUNin2nyIvj8ZA\n"
+"QAsFW9qW+TiTkeUK6yiZ9Gvgf20gwZRWOe5/xnMxVvtN6v7Av1ew/l4VhBoj/w5g\n"
+"ydIZk+2LAkEAzuJwdt+ccllG19qmEcbo9XFafgi2PvlEjPJmT1rHV2ns/7HIMu27\n"
+"PJY36GgExSfFco6VmicaoOt+RKg+5acgqwJBAKQxAEjcGWQ5VsgRhTVxO3DChX7Q\n"
+"TColhrWPwwPhM/s7K92HVzwvvKL5TNmdr9xMb7n3Ja56FouxZVuH6/J0XT8CQAat\n"
+"Mhnz/3WFQg8HRGLAe5YoMVZt64u+uaKe1ARtlo9QoNBjqWVTXL6IzocWjEjcjrey\n"
+"uEtARdC5qNqIX3dD3H8CP3pVCPvpHOTxkUaktmLYowSA1HSfO9wkE6bMCHhkLwXF\n"
+"yTIJ+N7c5u5YN1B6hhVqpKbdnSv+K0MQ0xbfwOWNMw==\n"
+"-----END RSA PRIVATE KEY-----\n",
+
+"-----BEGIN RSA PRIVATE KEY-----\n"
+"MIICXAIBAAKBgQDGQmrKfO3WovoXkOTSh/shO9qjbX4izhg4pccVU3Tp45v/dgAE\n"
+"uDUuaa/clToyH5AhOtuazO/asC3ZNajg1ia5VPzmQU3gtqiIZIEXFaOovPlOrXru\n"
+"wyQnxaGORndJwfDXicG6bUwI+PDpNq8c4VOTujReeF0r74qMSc7TQLVlUQIDAQAB\n"
+"AoGAakR/aTm9YibJVohbnl00xoOGlcLCsXU2lmaFZ3DsYdGWdD+TkvQJzW7ozJtQ\n"
+"Lj2sy6L4wujGR7nXWW3hr2IaLpoc1UoyJpieAZM5os6bMN+N4MCqdcZMlazMtSWV\n"
+"UDO7O7xQGFpcvvZmnfKCyluFaJ5K/tWxP+2TnS1/m0BDRIECQQD5DYvToA0eKBt+\n"
+"7K4eEI8pzDot9NlcL21D86kNgpmuY4pifALU7GvXr299JpFFiYa2A1JVRfpQaoI3\n"
+"hZzz0ze1AkEAy8opWJP+T2q4reD5Qq5UjjrHUXFID23KeJEjh5YF40/bHqyVpWVR\n"
+"UMntNgAzs+13vRij48Zn6I8GRhStaQ3ArQJASPyFS8GN1paeaDXoWPs1WWR2cF1f\n"
+"DbsAZHeVxVXOv+J//ZimI8wdVpodLCoPTLee+NxEVqUpVEPCYY8QjgwKOQJAATmj\n"
+"6f5pxvxzQ8hYd0gpBfngfOLbdgxI7VSiDAyg2G8AeDy9YZMsW/n6zRpPNUO2NpLR\n"
+"WWs18LX7aaxyJnGIuQJBAPPfy9pd4XEFsRBIIe3N23Gua1XkS/407RJtAGm73Vrt\n"
+"QhtWh3i6D5gfpEApMoaE8aaQQ7H0z+0Uh1t8SWesy10=\n"
+"-----END RSA PRIVATE KEY-----\n",
+
+"-----BEGIN RSA PRIVATE KEY-----\n"
+"MIICWwIBAAKBgQCc/M/X8etUqrxnmH3PyuAYLIPZhwNySch8qz9NB47izYjxzuBG\n"
+"GSls6H7WeKIrB8UJY1gW8TLkdOLcrI/0hTANNHEPaueOE0xdABFj7tAaiiGPIM25\n"
+"N0wc76me0ZAMYJrZTHk8JZK153y9wInYBwVZreXCVSVf11RuVwe+iFQa5QIDAQAB\n"
+"AoGAQC4XJtivdhDLL6snHFF7pkZkrQTGgu3pOhakrXA+mTigGQOTqvTUe8LdP/9X\n"
+"hTIK+tiTheWcAcxLhx5BSB0/VDKjYhS0ROpTc33Iq9KalOQaTJbBYGA4eagpQjwU\n"
+"jGwr9u2sUsM9WI/Jg0VvLSKhfnNwYIUzLpK3BbWb2qAdh+0CQQDQ2s/8DlibFSBK\n"
+"UsFK7lLpV8UgMk9CkaNM2BPzI8Hsjpp6s3pULVRd36m4YTSg15EEHv7bZ1N/+krX\n"
+"mXb9xUULAkEAwGy5wHsUSjTK+kntkNXjlCU/+9R+HFpzg9Bwm/PqXTBwEWeU24hV\n"
+"iRjPvqPtWFZrWi/nfcviuMaqtdliw1I1zwJAZ2mQxhtMYC2LuYFUWAe9YfClmJWQ\n"
+"jUOTef8bka5I3RqW/t5TWc7AEWMnpDXtWx6hnUrDolt9Cschu7MvKeQ9lQJAL18U\n"
+"46PpPNN+XNuyVoOxgRkihVasrUI/SeYYsuv7eHGiRUagyOLpW9T139LvbV3pE8zT\n"
+"So7VA/Q0towL2lX01QJAGcoBNNouSpum9+5NvGQK1XXsZweawE+pFR2BE5XcjG+n\n"
+"FnaLEUBX7nTxhTU2cSQET1PKRNp568a281NEna0nxw==\n"
+"-----END RSA PRIVATE KEY-----\n",
+
+"-----BEGIN RSA PRIVATE KEY-----\n"
+"MIICXAIBAAKBgQDFOqqGG/VtIScxayZYZ+BT+hcs5W1bD5qRxunbG9O36UVT18UE\n"
+"CWw9HUf0Q5sDMGvVmBxwZ4GjbR5FDPfhIXaRCzobnejJXq/0k+O5NAVkcSPtJvhK\n"
+"AaUqBrWA41vnjKOtJudTsZLfufKafzYwVonze7fXGyVsBRjVwHNS4iqq2QIDAQAB\n"
+"AoGAJCoStI6R3RXUKvKb0GATuTJFZ50WBTmCPTK9FMkwdCuY47vPy2Ky7y3cUMTI\n"
+"urf5PewrYs0H72CFyWGMXkKVi8aOYshsATEXMfGSqOcqXn+UDssRzvabZFlpnAUa\n"
+"WDVt/iN092AdakXNna7/DxrLisDpq8HHJfjtlWGPfkXRg4ECQQDpHeKimTvwJcPc\n"
+"iDa6Qb/n9gwLeRckfzhYtfX1luJYLIOHh+J9vjQN75thenBLQB/B6qlKtOn9ejxg\n"
+"5z+3zIOpAkEA2JbxXVTCOA802p9khvHxDtLHdKi3w/BjjJiC7Mgqo69ZI+s3PB9E\n"
+"F2HJA69kZqpGqvybWHDapjWsq7rcMlxrsQJBAME2yvR3y00VEAyGPc4M1vF8ZqlP\n"
+"uRW/+ETWtEDUyU/JvU6lGt2bu2tdkEyv/cjxIiFIzP4litdT7B1pLc+6S9kCQBwE\n"
+"usiWFGHoJbA6emiyl7qRLdg7kzo3uMkRWa6D3nA6WM+6t/SBHu/faH+fit91G5s2\n"
+"/mmcf8yMmP/GNoIVTqECQFl4Pt6yGiz/YVoYSp35ljY5n3JB6T8o2pOmIrRLuPmT\n"
+"6kgyygtJBAmx5nnQoeG8n08tl9QakWznKzkNJ0DIFKI=\n"
+"-----END RSA PRIVATE KEY-----\n",
+
+"-----BEGIN RSA PRIVATE KEY-----\n"
+"MIICXQIBAAKBgQDCaOqJ0lsSAEBcnNB6X7BvVcEcol+evi/nJsPe0uT1SbtW50Ch\n"
+"vYOHwK6aQR2C5x9VSs47cLynTL7tNt5d8oeryF3NpI8VTPLImDJCcvUZhS7p4bxn\n"
+"JO+Wm+D/e3TWfyjreuWtdL+Mfimw2gzwWuBEtmj51GzQ89eYm7fh11SB6QIDAQAB\n"
+"AoGAWaakMbZNxPlUtOCjyysBY/Y5vYira7rswD3CKak7aFn+CE9QIMYSN7IFUqEg\n"
+"iNMoQd7jR8nvVX8wtJeO5+gF48W13C3n8FZSrW7c5N3bmfMIgo0xa/TGfeXHP98o\n"
+"7vhH0I58j3ZZt0Q+3wTm7t7WPE/nJzgrCk30TqmoaEmstTkCQQDtV6YZ6juEK2Lp\n"
+"LGUiqohcS/WJxvFrF5+LNpk86Xdgomf6FphZlkq42KYkvl7qibKDcfDqLKTbHHle\n"
+"vQQeCgZ7AkEA0bFHi7F8o4iHtKleBvt4QCj1neA0q3CRDypCI5EqFSrNpxY4Krhh\n"
+"WYSVX+xT00QYaCpKKWfYQztCw7Anylv96wJACl86Mwe5ch0zRV1bThiFvQLUyCCZ\n"
+"jESMBFlueOr6/I4cXSF/puqaeVl+aTyoiTdbRcNE8/bffXPRGgLIm0d04QJBAJSY\n"
+"lmTN789Lby99Xh6AkaSV4ghw26Ip8QHYJmph8npxjK69Niw/4Oy44cnKBVUPSmR2\n"
+"o3tYFY7/Lb7S1D+4lOUCQQDbMQUGVsZT+ZjuOG1bAjIuXoAOfOd3mgH5VgQHjSgJ\n"
+"ourZtlJ4OUpNrq9IfWqPkM+zSE8+0Dk8/9MS5ngBA/SJ\n"
+"-----END RSA PRIVATE KEY-----\n",
+
+"-----BEGIN RSA PRIVATE KEY-----\n"
+"MIICXQIBAAKBgQDNbHjwg+7tVNr9erMLowXRnIcttp4pUJbr3B7Jo/u+kD/Yo3F3\n"
+"4rIKhHpJl1uEHP1QmvAD+4ApFFI2hNG54xYI8dGflxL5HOs5xxyOPpkrwzQ8Qvnv\n"
+"LPg7Gf6PAW9zF4McG4wK0TkrV28G6NhqcPs5VFY6UyvfZ0fEdWAeoWTIfQIDAQAB\n"
+"AoGBAKOmkMp7MLLd8QAS6eSRYSdWHdLrMyES1MjduaFGBF4SKOr7en/Zl6ENXSaX\n"
+"cA7V0XCPnjpt9/HCAKTyNupx4LCeFWiqdu8VGXhlzX8bdb896OSR2brKbxgRY5tF\n"
+"36uL8akrZdrYgocykQCxmRARMB7/rHwDusiamjL6RUZ3+c45AkEA6UPTVmKZQRMr\n"
+"A7Qgg5nXrXo9117Lpqf3FdZ1wdni9V59Ptf5xrx9oGZNZzctJPXSAH4M4cumSJrV\n"
+"sZ1V8qE7AwJBAOFx+5luLrVKrdlG7MyOhTAdhKYUvKIvL4wvVSY6y+L2nNEx/cTx\n"
+"KYbxGC+H1RJbkCS09rYir3VfDRWQ3W1c1n8CQH+X4hn2hO3blkPIW6CgniD+JKWR\n"
+"7MOUTMtdK7yFemfM76VYbgAPSohabSxwOfllnSE30cQQqTw9tXYaIdE98BECQG+M\n"
+"QWxSS0QillB6unIgVqBPCrJOcmNhK4qWZPBMiVNcqI0Nyj2nAeAl7MyfzfqOWY0A\n"
+"CU5nbR+LD2NLUXRqSisCQQCN3IGv1WOWInmA5xhU6vCFDX5u48Dcji7VLJO/Nv/i\n"
+"b/zHKAgjHk5Js7bi5ZWEGaUgA4Jt6cKmGdERheqTMKxx\n"
+"-----END RSA PRIVATE KEY-----\n"
+};
+
+static const char *PREGEN_KEYS_2048[] = {
+"-----BEGIN RSA PRIVATE KEY-----\n"
+"MIIEpAIBAAKCAQEAoksI1qIuIaFCqT4QbgDvOQCmr9Z9F0E7ku+U5Ep/5dWNANqB\n"
+"bSzAOq0+cxiisfF+H4desoqiWDUwlOwXH74qD3ZsbChhvFUD78cQBWQkF+whLVHb\n"
+"296QmF0LZqosqz9HMS9CdoMUc1brZb78Hb25QIOOjrg25KYHLZHaqcet1wfhHow6\n"
+"Uehc6QTuWgOWFhJnfiXzYgen2o8lnLixxZozhk7Lm7Aix9ur2ckXdQ2Wgny4xw70\n"
+"JW84Hapnd8oFUD98XXrExk4VFuIcA8qo7r7y18II6wx4Cw1suKru6bhW65cM/y51\n"
+"KC4lB7VkvuoJCelRFdM1PfKZLv2tJP63oAqJrQIDAQABAoIBAQCWc38PEqw3avqU\n"
+"UMAEaoNa0bq1Gd8/Nq8WqVnbRSFKHO2pk+cWIb1W6BITuwvgcGKesezdEV4s7apK\n"
+"9I7/U1hEm2Ep50mrwRh0KZM1nD9Fmharn851Bt//D4qpMytT2caS1yADI8NKpZJ1\n"
+"8VZh7+cT4qG+txHUaAIRgbw3VrBWvTIMu6SOSOZm+e3eOr5UU3du1KvjdJHJ2c2k\n"
+"TceHvUdKxV7OYt+BBSN1oBOhs3ajUSRge1v3twRDg3cmbwG0DeXvwHNhGUTcF8IH\n"
+"JO1RF5njbkFvyqdAi3ltjU41zYd4OMuPtrwzFOtxUjKT62Soz109HUXXE2CGKFPZ\n"
+"PVi5/BIhAoGBANN1xqS5BgHszIB0nXbw5ImYpTRmyhO0KsTblBT9+8Q/B7BCK7bM\n"
+"zl+dOPeyvEadSwE7RSMMt6CAlTakWIf3Quw/VZajvXy9C9/LHf52pEKXjxMFMPKE\n"
+"aGLHpQnwMtDi8/H8AEAXxI3hpxB2KVR7sAYHWihSGjRJ6oPGvEmKEkb5AoGBAMR6\n"
+"G2PKz0xk1vFrjfjSY+y13gH/t7xHaXUggjggUSGKaknQh2BDUllXjadeI0fi1eLW\n"
+"r98ZImZZgntAgjaIZ4bAlooTDk4gRHaz9jI+z8lsRwOKnWdiigM7txiXZTMVwMqj\n"
+"o5mMNGMA+A+ACkTViRHmkDI7S/9FqAvnbOqVwgFVAoGBALUcY6WDvwx5B3Jh7tgH\n"
+"XIYpEh3+h8c2gYcX1g3gtvkPTwN8uToY0gz8eOVV1YHZiHsmi4GIi+HRH3usaRMT\n"
+"COOVHzYlSc8Dj57+tdLTRL6wVl9hC9o647ju64DGlI9qQquYPZKniLZIdbFYsu9j\n"
+"/JA9Tc/I+h6czFpPJccKlbrpAoGAAPWXrKUQ3g6f/g3IY66jTkSVEO1uuDyhBzFh\n"
+"cWS3ALLsUe/yuUWa4VTMHEUZZwB0iucBdNVqlZVaTb/C4wFHgCDwmzv8leUScIHw\n"
+"cc5ctV8R+bJzkk2o3tsrybLzi4xPpK2n3tgQaWtXyruVUUC5qpy1l4kylcyBRY2b\n"
+"uomAqQECgYAiCNWtuWIDlRBcvtIB+kHguzcoFT3vTCCNhalTEn0zi/tbi+voQgVJ\n"
+"SDJNptZv+6vRwQ/HfcQtljKIPO6hUZPYaFWRNhgbh7Ay85lRXYXQOottE8ayReBk\n"
+"zZb0fl853Qah4DPsaOugAvhjjKeBmKg6bFWO1z6hj18I3UpDf2YnVQ==\n"
+"-----END RSA PRIVATE KEY-----\n",
+
+"-----BEGIN RSA PRIVATE KEY-----\n"
+"MIIEpQIBAAKCAQEAssO0r37mSJNAkc/ISwXBsu9JjyLeWlsHPAhylQGkSAdp2rjz\n"
+"E6AT0Eh3wrocNO31I4pvHReAuh1QedGY6T1cQwO/WAAhQtRCBQDK12qWRgfbC11y\n"
+"Xu7zNYPd1Z7YIRy+FxhbL5f+lv3rEUv0HUG5c3CWhLtbANKg+jOieIDzA4Yp1s55\n"
+"ynodQBUkTZrwQiT0P8yDSjiasf+clgJRfA1k2XK12KSAMRgyDuPTE4OtBxBvUM3L\n"
+"Zvxs81PsmcOuAG4DLaFTg2a/QkCjt2VC1SYYuh/LVxpL41FFh3eMoK5g5deHkgRe\n"
+"tlywKjAHIDJu/qgNzNgNW7ymwn2CfBvry9h0/wIDAQABAoIBAEMZ4wDdCWPEokAZ\n"
+"Vn2Ss5qO53WrCPuxn42RPjFgZGIFJl7LfbKoK8fK6+lUIrJbf+DPXdX1tIQn7MVN\n"
+"P7CNL8yX44MMyW9kbUOjgIBLqgyvdjFV6lBoMTKtRN+iuE31lATnR5Md4pqaxVnA\n"
+"wOkaepoycM1x5j7w0SwZparF/HIdkYv0y/MysqT9ByupPA4Fqp/iRSrosHXahNtI\n"
+"KZYj1TyERYtuDXq91P4dr/pWq3FmDNI8O3upblkL0YouvG/ZlFLdiNy77XbAyWcX\n"
+"ps3YDddM+vECnXO3+sa3ZxgBYvXJdWrrIzM5A+jCkDRZQGsFAzK5I5/S7C2ljt6i\n"
+"SmzqvMECgYEA16bGy2XTi6KBPb8aev/OBgK9XuGLwUqK1m15mS9Y2qPHmuc22qaZ\n"
+"hw6zginPFrxAEtQWKanhZy4aVqlLkDPLwRnyeuMo1EZAc5B1gZ5ViSAKxBq99hA9\n"
+"eqyakdb+IUQsEnRDxSc2gqUQ0EagksUyw5wGG5Q/CVEALmS/r1SU3KUCgYEA1DYf\n"
+"6JYdzuRtule3vYeWXKf8sOJpdplgWV7tvLrKkQhdE564uwMCYB23HvYfwWqEdDYG\n"
+"fsYg/ur/stk9MDZ3wZKffTEM8V3sX1t1JXnC3ogSAgMGhLZ3ILOLqkoO4BEZJnsS\n"
+"dMdiNijlAtQkqs/BO/UVUAKysCtKP3v/+1775dMCgYEAvLjGFjApfnSbV/cK7IM6\n"
+"wEXbhdIqZOCgOeEaXjVyM/zKbMRVW+oaR3hVHd8KzSG3jQKv1oxFpu9Qu3ByoWLC\n"
+"uF3Ft0debs6ADuJoAyQWROeWpGGmxlUWCGpO5rxYL7KiQxAeUsXrTU+5NBvq4CbV\n"
+"MxwyuCX3OGb7mp4upfiGQcUCgYEAuhVsDYv1P4LXJVvd5viKRV2ZG5KuYC1Ga5fu\n"
+"aFxzXJI07At2eaa94oKsHR494mEBHNZzA5/BN0fiSHZuTWS1xqxH5oOokc6Gg2ez\n"
+"ZdVLp88x20nD4YQPGkHW6tBeEuVrZG7vVC+yU0Ow7bYRISdkjqrusWZsQkbzqI+X\n"
+"fFliEbkCgYEAu8x+47M1ordbI7NmbBGyiyP0r7nMRCZ+KEvGeCNYracWmsnCNnfV\n"
+"zR2UzmwtSainw3Ho8Jv/rWDC8RIDauyBRYEi2VqOnUzT2ca0iymQyLeBCudAQuio\n"
+"drOu4JU8RzZ3Ad6V3DNFnaqmX/7GA9Pa2GI8NJMyb8p1GAGv7Gi8nxc=\n"
+"-----END RSA PRIVATE KEY-----\n",
+
+"-----BEGIN RSA PRIVATE KEY-----\n"
+"MIIEowIBAAKCAQEAt01S8JuEwWy/Hzb90yO2O7oGWq3GfvfDpFOF4OQnwG3kQ/BP\n"
+"4MoPDCYHdqb3iI9aD3vykZA6Q8zpdfGwjm4+bHrgRdiSmZWv8NvRwuQ5Ji9xbiGn\n"
+"hA1XwqH9hvgFTiy6tRvirWSJ7kzH3Q/bEGpCbHUQkwMog4v6yCNKNrjlwjN++eCi\n"
+"gFK/0RMOJMLOs8BD3zY+lKjd/pd8LBRujkMyUF5SryeRueAFjD2sq4OXq8DPABGt\n"
+"zdR6vbTcsi4JwP1Q6y4x0/LIWEprzzewNU63I5E2zj0WnoRGAIM4aF+VuqcHjWUx\n"
+"VWnyLZldSen6lScZ4xj4seitiDbSFvtFkDF6VwIDAQABAoIBAGTP9im2ntDyyjqU\n"
+"uA0DuxomOZBtupniEouyFBOX5/UBe2WSKZxsBNKdp8UuFz3X+aRCeyprtF/NtyjT\n"
+"AFOVdmebPPWtIxOtK9LAUyFo+7VwqmXzxHnwDLBS/2jXx7MzDozFBWpvvRx+xf1i\n"
+"1wy0JEwaJj90oTeYKRkhr5NhJZwkX8zCNYaemBd3kHB3aGWGJasI1Y81UezeRKCn\n"
+"hSbn2CrWalI7pyJ4lsavM11nIq1Eu2ZthJiNCMghbYrHoBHd+iVWiCYchP2rNEWV\n"
+"sdHtaVHtQ9zdZ43bao3OzPu7lAjd6UAbxsuhUe+a2YdDz/+Up+6+BvQf1FCfYIjW\n"
+"KFUdCoECgYEA4t5O+u0V9gkMUhKsevYb0zgc7O/mo8ivN+V++EpAtL0mhiwxeO8p\n"
+"oef0szLyhdULQeLN9pJQDCeAbkGdwIe3L+AKU8o8BFGEWLFysZjMg9In/UTrp5MN\n"
+"mMDy2SRKKu5BqsvdYH302xpZfHq1T2cMNDWE8lrZffduH06Cgq/XEtECgYEAztbj\n"
+"bhFneADnrvk609VnOQvoQEjySeCQKFQFRRI6k/FguqMisL2IRXnMaWammosdeCAg\n"
+"m7eZchnszHIst9cwZUKXUFqmAqeDuWSNdTI7uKZH6nT/A6IDlgdjaHsqhvpK0Ac9\n"
+"ngycdHONitOZh0ZG74pdWjf828Dwzf+CuYjl9KcCgYEAmIvI6ZqvkJ8m5Kzfw1Jn\n"
+"BVCOypbJK8oOX3R2Orea6KzjEYb3wQx3nwFcHX6danYFOskpmqlpH7MT/Y8rZsEa\n"
+"4RsxdoPedTzm08iFiXtn0R9nejp0hlov402iPXXUVSedih3IflBTa1w9XaEY9wog\n"
+"P57ZBSknYzcTmgNtaDiaUnECgYA5sWauhNw/dMEq5QmrnJK2LsQRakdqo+CR3x25\n"
+"LmR4b5Nze51pfvRLrLV/kMpXwQXvQ8bUqFl8og6S2CXxAWzWUcSy/RXhF6h+RbXP\n"
+"Qru1vWvB0fBvqvklF9p6giBSle3YKKzfMNVTBggs+OiR+uA+YHG5gHRfN2nzi5mC\n"
+"9tRtcQKBgBnDSi4lRCjRe9pPnyAYaa4iyBUGhjPysScSLY9orel89+qmTBQ/Py6J\n"
+"0+sefL4ZJaOsuaR2mSSPP/lbSkF9DMFs4tHbBqY+WkVNYLshAkauHwqv26HTVCSd\n"
+"QKzeb7uZw9lNaRIzDvy/3wfCLvXfdDozPFrOUgkyaBN5pJSA/4sv\n"
+"-----END RSA PRIVATE KEY-----\n",
+
+"-----BEGIN RSA PRIVATE KEY-----\n"
+"MIIEogIBAAKCAQEA9qtiDoJWqU/eSlpj381eG6UcDzfMguFh/q4e4s7QVdRYj5J0\n"
+"Msv0PCkti8JHuvQUyncRpOPccBkhNbVjNbjIgw1pHaIZNdVotUDhP0kseRyJ6z3M\n"
+"qbZ5qKn+0mHjVjPNItVDDe6tebYMT1BZpVyRrCOqY2v5z1ecLC+ReygmHgDpzg+L\n"
+"0rWfIxGT10IPZ8pAlcdEn6xt5aEhi7mPCX/xwqfQChPIJz6zVLEC8UaPtvDBohPR\n"
+"6NQTBTeZZAAtzrQ7+oNxfz1v6Fz6RwMei7Q+qOBnMiwpQmbcDBKABM2RnXSpD0LA\n"
+"1GR7/+CiV1HQoShWVvEwrSIlM6jVAJo6iqF6WQIDAQABAoIBAHqwcdxPnfUm4aTP\n"
+"4r9NcZKEhDlZgqJSoiA/0OL1BRC7xrTanmspoLhPrvTF1FG715+Aq8j9AQbMqQUC\n"
+"zG7LEwiEIhV4K9vn4uXMeHy206UFud/E5EhBl695pmJUB/Q3XcAGnQyP+77++o50\n"
+"o7IpIdeiAbzj1uP3aplbq5u7M4JV7fUZWA/368G4HolqFTxcAfBJ05GXlp97BBwY\n"
+"AnY3/pNrKMz0NiPf3nsJHYWK18up0JCLPL3tomc94wuNZ66spIazHIL9aaKY0q3V\n"
+"LkBrelndfYM1m4xRTnSOy6STu0qKTPOpX0C8XBLYs6uiXjRsChqSYwndCCeASaH3\n"
+"LGNIcbUCgYEA/m4qvt8tdT4wEvnE+QUxEELmBtT4UFa3NnQISrzNlhNeI0Zd2xlp\n"
+"SG0/pcw83mG2uX+V5xSaWL5LYfLBkvy83Y0yIWgYbbIkyyCOUZnTpwaDGU/FjWip\n"
+"3TfXf5qpAgiez94sV+MsFpKfG05yxJh5u+3sIyGTVUAxp0HPx4LVgbMCgYEA+DD1\n"
+"fu6ttpuV1UMrsFdjuk6gBvSbyJ9OilY2jT+yE7hSRc/yP3O9ikuR74tNlVrWTnO2\n"
+"0kcYbyLJXE2cGUC2q5e4r8TDGiozNfQ7/OC2M3XaJ+xJk4zMf/8PuDDpWr+18ZXA\n"
+"Pf+ibXWTFvZ6ZeUmpbrrfCrXdvmIZnwVuOI0FcMCgYAZn26emksxq3mb75tumJ9A\n"
+"S/xuY7Q+Iv2Adl7/Z9QscPbiBowdLIn1yUrHn7Hhk2WbeMXX57NDjKZ6zr+/1cQP\n"
+"a9DInHsZUP9zlWu/vAYcpAM/4VC71PaGWMFTEHhExCl6NZ2xnCcsfseXMGdOdSyN\n"
+"SICnaRI1W6mkdnQ+W2a1EQKBgGEKA3KVr6XuPy8bDEHuaTe29irCCQbwAq1j+ABS\n"
+"HzZGoyRYocbdYgZoda7LMJJs6c3SwHCHC66oU0KbtaTKAKImuDdBH2djiJJX4/yD\n"
+"f7mvIpTpdfsS2gJRn7vMo/CvdFv4ySl0gfV6OwCHbmPYrLuv0dLCjWwfNI2dhoC7\n"
+"MNIxAoGAIPSIG4BrShzbeX4c2L18iwIg+NlOcUbtl0Ccr1t6uLGI+ge/6I6T/5XH\n"
+"DPKqYIf0IRYV8suxpfQNKiz/C0NPffA1d1M2hvuAg2v09o2cSwvdcQwdmakKZ5bl\n"
+"sdCuYKdCIwomEUOz/4XgQrJl4XDUqxftJT6/egAjWvcIYvfNCsY=\n"
+"-----END RSA PRIVATE KEY-----\n",
+
+"-----BEGIN RSA PRIVATE KEY-----\n"
+"MIIEowIBAAKCAQEA1yHZMsgRLckL+v6rgpGq9qmxVBNDxeuul1V/QlFyOlcAk5n/\n"
+"uduTalSqGQhc4NEePMxq6nFui4ucpkZOozmcEnhV0N9jld9IB9rLGt4erdg7RKl9\n"
+"+gQ+zTn69j69U36E2I47H4dM69uxeSOyWP2Odxpw+biisa3o8mMz1zCmuj4GMDtG\n"
+"DlnSpthFzgQR6N1pbvxLXrWg5F16GqFiJOD7kXDfy4/l6kB/mDs1T/3r8kav6DqR\n"
+"c/t3aQZxgWGIpI7hc9Qgvp7coZRMey5dNOZEna3tqS8dn2tZlhkpYV5uyFUjmxjG\n"
+"TERSULQ7hvUqW+eshGGsnxFtL7ANnTSc4xECowIDAQABAoIBAFhJJMhpQFuIySjd\n"
+"AGeZ/g4x/3rgWQzNNp4WUR5XLEhy0eLA7ShJywp06kVRoEQGraEHxsyldldAGS5H\n"
+"ZhgoGTufNKB+PHER646FpJpHE1IGjfQUloVW3qr8I1iQ0MOGBWCVpf+/V7rnMsLi\n"
+"+lr421FXgYuJ0QKXuyRVv72M0q9U6i+ml3aVAhgW/19oFg+dW7YccX+9iVyD05Q5\n"
+"KR64tX8xd4wrAqfAgYA3erbbE6GTyHYD5K54kIgfRr/+pIU4qc1L7XOCblnqc/rI\n"
+"BilFysEC634r2MNe66uQvNui4oQTfBcFFlXg0zAmp7d5QE0ApOL6HpCsmbImm2uJ\n"
+"sdFNYyECgYEA716kfEv7HfnF0P3pAP2AOuEsW6t8q0UtWvnHrwRQXQw8Yv90g7kD\n"
+"pUV3/BjD9VQgsQZosbdSn5wbT4j7dypRdrzYk+8m/hBk4Q8M/tWoRGVOn46NudvK\n"
+"/KX0A4ODLuulj8yAZVc7CM5Cdy4GCGJBVO+oVvBUAnHxfZziOyqBw9MCgYEA5hQg\n"
+"HEORzdxvbbfAx1ggvH1Eg1lqRhmpI43PpRkaoqb8jLwXb2CyBeuv3RBft/X2Tr6F\n"
+"mHpe0U1kN/5YEjii/Q/jUX8azIHaUNNSAjrriEeMQZOqFxmhCdiyeXuqg2fbFbhe\n"
+"K3Q6/fsB1xj9OOSwyPMqm/M5U0LsoGjmg8TFE/ECgYAlImKUIdlwOgp1NJ7MF4eo\n"
+"Gryd8AmkLFQv8+YFgb7R4I8RsJ2rva0SG6fUhScJTSbRL7RYNZ9swXP/L7oLL5Z5\n"
+"vCxBLu22pmZv/7y9X/n9ulWrLRtRhQaFkV08mk9knQwPNeOJVTIEWLM49/vZmxyV\n"
+"h6Ru8FOoGXMkUI1MLnj5HwKBgGJLkNhiacVYeuaWDa9c0EeXARFYvxWJ2wAMkvzG\n"
+"9+ErlFQP+7ciyYvMAItidnJii8NilDLrfNzQwpNFf5zxQ3j4M7bapblfdMT5M10u\n"
+"jPfhEWPm0VEjKvDI+p76HYQcd7YU2W6ZLqbZeRTLYUvQMFL5yGduBzyyJ+P0TR9Y\n"
+"jpYRAoGBAM7vYGTprw4w2tTZPFICXVk1bQ0LO06oNRtwkiQTUT6UqPjWMFyvHnmN\n"
+"11SVVBmRZ0RAk6e5eZLFX8WelJ4J4nSOGRcJheCtoEFlO7D1ewAUSbqWJ0pBqp2T\n"
+"gV4oCS8LYe8zReVoYZJjuLwoHvxZzs/hUjc3SI2HRW2W/HQRPC25\n"
+"-----END RSA PRIVATE KEY-----\n"
+};
+
+#define N_PREGEN_KEYS_1024 ARRAY_LENGTH(PREGEN_KEYS_1024)
+static crypto_pk_t *pregen_keys_1024[N_PREGEN_KEYS_1024];
+static int next_key_idx_1024;
+#define N_PREGEN_KEYS_2048 ARRAY_LENGTH(PREGEN_KEYS_2048)
+static crypto_pk_t *pregen_keys_2048[N_PREGEN_KEYS_2048];
+static int next_key_idx_2048;
+#endif /* defined(USE_PREGENERATED_RSA_KEYS) */
+
+/** Generate and return a new keypair for use in unit tests. If we're using
+ * the key cache optimization, we might reuse keys. "idx" is ignored.
+ * Our only guarantee is that we won't reuse a key till this function has been
+ * called several times. The order in which keys are returned is slightly
+ * randomized, so that tests that depend on a particular order will not be
+ * reliable. */
+static crypto_pk_t *
+pk_generate_internal(int bits)
+{
+ tor_assert(bits == 2048 || bits == 1024);
+
+#ifdef USE_PREGENERATED_RSA_KEYS
+ int *idxp;
+ int n_pregen;
+ crypto_pk_t **pregen_array;
+ if (bits == 2048) {
+ idxp = &next_key_idx_2048;
+ n_pregen = N_PREGEN_KEYS_2048;
+ pregen_array = pregen_keys_2048;
+ } else {
+ idxp = &next_key_idx_1024;
+ n_pregen = N_PREGEN_KEYS_1024;
+ pregen_array = pregen_keys_1024;
+ }
+ /* Either skip 1 or 2 keys. */
+ *idxp += crypto_rand_int_range(1,3);
+ *idxp %= n_pregen;
+ return crypto_pk_dup_key(pregen_array[*idxp]);
+#else /* !(defined(USE_PREGENERATED_RSA_KEYS)) */
+ crypto_pk_t *result;
+ int res;
+ result = crypto_pk_new();
+ res = crypto_pk_generate_key_with_bits__real(result, bits);
+ tor_assert(!res);
+ return result;
+#endif /* defined(USE_PREGENERATED_RSA_KEYS) */
+}
+
+crypto_pk_t *
+pk_generate(int idx)
+{
+ (void) idx;
+ return pk_generate_internal(1024);
+}
+
+#ifdef USE_PREGENERATED_RSA_KEYS
+static int
+crypto_pk_generate_key_with_bits__get_cached(crypto_pk_t *env, int bits)
+{
+ if (bits == 1024 || bits == 2048) {
+ crypto_pk_t *newkey = pk_generate_internal(bits);
+ crypto_pk_assign_(env, newkey);
+ crypto_pk_free(newkey);
+ } else {
+ return crypto_pk_generate_key_with_bits__real(env, bits);
+ }
+ return 0;
+}
+#endif /* defined(USE_PREGENERATED_RSA_KEYS) */
+
+/** Free all storage used for the cached key optimization. */
+void
+free_pregenerated_keys(void)
+{
+#ifdef USE_PREGENERATED_RSA_KEYS
+ unsigned idx;
+ for (idx = 0; idx < N_PREGEN_KEYS_1024; ++idx) {
+ if (pregen_keys_1024[idx]) {
+ crypto_pk_free(pregen_keys_1024[idx]);
+ pregen_keys_1024[idx] = NULL;
+ }
+ }
+ for (idx = 0; idx < N_PREGEN_KEYS_2048; ++idx) {
+ if (pregen_keys_2048[idx]) {
+ crypto_pk_free(pregen_keys_2048[idx]);
+ pregen_keys_2048[idx] = NULL;
+ }
+ }
+#endif /* defined(USE_PREGENERATED_RSA_KEYS) */
+}
+
+void
+init_pregenerated_keys(void)
+{
+#ifdef USE_PREGENERATED_RSA_KEYS
+ const char *s;
+ crypto_pk_t *pk;
+ unsigned i;
+ for (i = 0; i < N_PREGEN_KEYS_1024; ++i) {
+ pk = pregen_keys_1024[i] = crypto_pk_new();
+ s = PREGEN_KEYS_1024[i];
+ int r = crypto_pk_read_private_key_from_string(pk, s, strlen(s));
+ tor_assert(r == 0);
+ }
+ for (i = 0; i < N_PREGEN_KEYS_2048; ++i) {
+ pk = pregen_keys_2048[i] = crypto_pk_new();
+ s = PREGEN_KEYS_2048[i];
+ int r = crypto_pk_read_private_key_from_string(pk, s, strlen(s));
+ tor_assert(r == 0);
+ }
+
+ MOCK(crypto_pk_generate_key_with_bits,
+ crypto_pk_generate_key_with_bits__get_cached);
+#endif /* defined(USE_PREGENERATED_RSA_KEYS) */
+}
+