summaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
Diffstat (limited to 'src/test')
-rw-r--r--src/test/conf_examples/empty_3/expected_log2
-rw-r--r--src/test/conf_examples/include_1/expected_log2
-rw-r--r--src/test/conf_examples/include_bug_31408/expected_log2
-rw-r--r--src/test/conf_examples/large_1/expected1
-rw-r--r--src/test/conf_examples/large_1/expected_no_dirauth1
-rw-r--r--src/test/conf_examples/large_1/torrc1
-rw-r--r--src/test/conf_examples/relay_30/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_30/expected2
-rw-r--r--src/test/conf_examples/relay_30/expected_log1
-rw-r--r--src/test/conf_examples/relay_30/torrc3
-rw-r--r--src/test/conf_examples/relay_31/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_31/expected3
-rw-r--r--src/test/conf_examples/relay_31/expected_log1
-rw-r--r--src/test/conf_examples/relay_31/torrc4
-rw-r--r--src/test/conf_examples/relay_32/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_32/expected3
-rw-r--r--src/test/conf_examples/relay_32/expected_log1
-rw-r--r--src/test/conf_examples/relay_32/torrc4
-rw-r--r--src/test/conf_examples/relay_33/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_33/expected3
-rw-r--r--src/test/conf_examples/relay_33/expected_log1
-rw-r--r--src/test/conf_examples/relay_33/torrc4
-rw-r--r--src/test/conf_examples/relay_34/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/relay_34/expected4
-rw-r--r--src/test/conf_examples/relay_34/expected_log1
-rw-r--r--src/test/conf_examples/relay_34/torrc5
-rw-r--r--src/test/fuzz/fuzz_hsdescv3.c7
-rw-r--r--src/test/hs_test_helpers.c51
-rw-r--r--src/test/hs_test_helpers.h15
-rw-r--r--src/test/include.am24
-rw-r--r--src/test/log_test_helpers.h16
-rw-r--r--src/test/slow_ed25519.py2
-rw-r--r--src/test/test.c1
-rw-r--r--src/test/test.h1
-rw-r--r--src/test/test_addr.c163
-rw-r--r--src/test/test_address.c4
-rw-r--r--src/test/test_cell_formats.c78
-rw-r--r--src/test/test_channel.c39
-rw-r--r--src/test/test_channeltls.c1
-rw-r--r--src/test/test_circuitbuild.c1387
-rw-r--r--src/test/test_config.c4
-rw-r--r--src/test/test_connection.c9
-rw-r--r--src/test/test_consdiff.c14
-rw-r--r--src/test/test_crypto_slow.c2
-rw-r--r--src/test/test_dir.c20
-rw-r--r--src/test/test_dir_common.c2
-rw-r--r--src/test/test_dir_handle_get.c211
-rw-r--r--src/test/test_dns.c8
-rw-r--r--src/test/test_entrynodes.c147
-rw-r--r--src/test/test_hs_cache.c21
-rw-r--r--src/test/test_hs_client.c79
-rw-r--r--src/test/test_hs_common.c32
-rw-r--r--src/test/test_hs_config.c43
-rw-r--r--src/test/test_hs_control.c49
-rw-r--r--src/test/test_hs_descriptor.c28
-rw-r--r--src/test/test_hs_intropoint.c3
-rw-r--r--src/test/test_hs_ntor.c8
-rw-r--r--src/test/test_hs_ntor_cl.c16
-rw-r--r--src/test/test_hs_ob.c268
-rw-r--r--src/test/test_hs_service.c534
-rw-r--r--src/test/test_link_handshake.c1
-rw-r--r--src/test/test_options.c4
-rw-r--r--src/test/test_policy.c54
-rw-r--r--src/test/test_prob_distr.c6
-rw-r--r--src/test/test_protover.c47
-rw-r--r--src/test/test_pt.c4
-rw-r--r--src/test/test_shared_random.c26
-rw-r--r--src/test/test_util.c101
-rw-r--r--src/test/test_util_process.c7
-rw-r--r--src/test/test_voting_schedule.c6
-rw-r--r--src/test/testing_common.c2
71 files changed, 3261 insertions, 338 deletions
diff --git a/src/test/conf_examples/empty_3/expected_log b/src/test/conf_examples/empty_3/expected_log
index a42514f37f..e3f2365893 100644
--- a/src/test/conf_examples/empty_3/expected_log
+++ b/src/test/conf_examples/empty_3/expected_log
@@ -1 +1 @@
-Included configuration .*directory at recursion level 1.*included
+Processing configuration path \".*included\" at recursion level 1\.
diff --git a/src/test/conf_examples/include_1/expected_log b/src/test/conf_examples/include_1/expected_log
index f95cad040d..0791a494d2 100644
--- a/src/test/conf_examples/include_1/expected_log
+++ b/src/test/conf_examples/include_1/expected_log
@@ -1 +1 @@
-Included configuration file .*at recursion level 2.*nested\.inc
+Processing configuration path \".*nested\.inc\" at recursion level 2\.
diff --git a/src/test/conf_examples/include_bug_31408/expected_log b/src/test/conf_examples/include_bug_31408/expected_log
index a42514f37f..e3f2365893 100644
--- a/src/test/conf_examples/include_bug_31408/expected_log
+++ b/src/test/conf_examples/include_bug_31408/expected_log
@@ -1 +1 @@
-Included configuration .*directory at recursion level 1.*included
+Processing configuration path \".*included\" at recursion level 1\.
diff --git a/src/test/conf_examples/large_1/expected b/src/test/conf_examples/large_1/expected
index 5866f5823e..99a12ffc84 100644
--- a/src/test/conf_examples/large_1/expected
+++ b/src/test/conf_examples/large_1/expected
@@ -15,7 +15,6 @@ CellStatistics 1
CircuitBuildTimeout 200
CircuitsAvailableTimeout 10
CircuitStreamTimeout 20
-ClientAutoIPv6ORPort 1
ClientOnly 1
ClientPreferIPv6DirPort 1
ClientPreferIPv6ORPort 1
diff --git a/src/test/conf_examples/large_1/expected_no_dirauth b/src/test/conf_examples/large_1/expected_no_dirauth
index 17c11f85fc..26a33bdc7c 100644
--- a/src/test/conf_examples/large_1/expected_no_dirauth
+++ b/src/test/conf_examples/large_1/expected_no_dirauth
@@ -15,7 +15,6 @@ CellStatistics 1
CircuitBuildTimeout 200
CircuitsAvailableTimeout 10
CircuitStreamTimeout 20
-ClientAutoIPv6ORPort 1
ClientOnly 1
ClientPreferIPv6DirPort 1
ClientPreferIPv6ORPort 1
diff --git a/src/test/conf_examples/large_1/torrc b/src/test/conf_examples/large_1/torrc
index e99acd9fb7..20ddf00e16 100644
--- a/src/test/conf_examples/large_1/torrc
+++ b/src/test/conf_examples/large_1/torrc
@@ -16,7 +16,6 @@ CircuitBuildTimeout 200
CircuitPadding 1
CircuitsAvailableTimeout 10
CircuitStreamTimeout 20
-ClientAutoIPv6ORPort 1
ClientOnly 1
ClientPreferIPv6DirPort 1
ClientPreferIPv6ORPort 1
diff --git a/src/test/conf_examples/relay_30/error_no_dirauth_relay b/src/test/conf_examples/relay_30/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_30/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_30/expected b/src/test/conf_examples/relay_30/expected
new file mode 100644
index 0000000000..3a4e9feb3f
--- /dev/null
+++ b/src/test/conf_examples/relay_30/expected
@@ -0,0 +1,2 @@
+Nickname Unnamed
+ORPort auto
diff --git a/src/test/conf_examples/relay_30/expected_log b/src/test/conf_examples/relay_30/expected_log
new file mode 100644
index 0000000000..d5478c1a15
--- /dev/null
+++ b/src/test/conf_examples/relay_30/expected_log
@@ -0,0 +1 @@
+Your ContactInfo config option is not set \ No newline at end of file
diff --git a/src/test/conf_examples/relay_30/torrc b/src/test/conf_examples/relay_30/torrc
new file mode 100644
index 0000000000..bf8487fe16
--- /dev/null
+++ b/src/test/conf_examples/relay_30/torrc
@@ -0,0 +1,3 @@
+# Relay tests
+# default (IPv4) ORPort auto
+ORPort auto
diff --git a/src/test/conf_examples/relay_31/error_no_dirauth_relay b/src/test/conf_examples/relay_31/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_31/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_31/expected b/src/test/conf_examples/relay_31/expected
new file mode 100644
index 0000000000..9a40cdd588
--- /dev/null
+++ b/src/test/conf_examples/relay_31/expected
@@ -0,0 +1,3 @@
+DirPort auto
+Nickname Unnamed
+ORPort auto
diff --git a/src/test/conf_examples/relay_31/expected_log b/src/test/conf_examples/relay_31/expected_log
new file mode 100644
index 0000000000..d5478c1a15
--- /dev/null
+++ b/src/test/conf_examples/relay_31/expected_log
@@ -0,0 +1 @@
+Your ContactInfo config option is not set \ No newline at end of file
diff --git a/src/test/conf_examples/relay_31/torrc b/src/test/conf_examples/relay_31/torrc
new file mode 100644
index 0000000000..e662bb71b3
--- /dev/null
+++ b/src/test/conf_examples/relay_31/torrc
@@ -0,0 +1,4 @@
+# Relay tests
+# default (IPv4) ORPort and DirPort auto
+ORPort auto
+DirPort auto
diff --git a/src/test/conf_examples/relay_32/error_no_dirauth_relay b/src/test/conf_examples/relay_32/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_32/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_32/expected b/src/test/conf_examples/relay_32/expected
new file mode 100644
index 0000000000..14b36c8259
--- /dev/null
+++ b/src/test/conf_examples/relay_32/expected
@@ -0,0 +1,3 @@
+Nickname Unnamed
+ORPort auto
+ORPort [::1]:auto
diff --git a/src/test/conf_examples/relay_32/expected_log b/src/test/conf_examples/relay_32/expected_log
new file mode 100644
index 0000000000..d5478c1a15
--- /dev/null
+++ b/src/test/conf_examples/relay_32/expected_log
@@ -0,0 +1 @@
+Your ContactInfo config option is not set \ No newline at end of file
diff --git a/src/test/conf_examples/relay_32/torrc b/src/test/conf_examples/relay_32/torrc
new file mode 100644
index 0000000000..95a66c4852
--- /dev/null
+++ b/src/test/conf_examples/relay_32/torrc
@@ -0,0 +1,4 @@
+# Relay tests
+# default (IPv4) ORPort auto and IPv6 ORPort auto
+ORPort auto
+ORPort [::1]:auto
diff --git a/src/test/conf_examples/relay_33/error_no_dirauth_relay b/src/test/conf_examples/relay_33/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_33/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_33/expected b/src/test/conf_examples/relay_33/expected
new file mode 100644
index 0000000000..22567cbe2e
--- /dev/null
+++ b/src/test/conf_examples/relay_33/expected
@@ -0,0 +1,3 @@
+Nickname Unnamed
+ORPort 127.0.0.1:auto
+ORPort [::1]:auto
diff --git a/src/test/conf_examples/relay_33/expected_log b/src/test/conf_examples/relay_33/expected_log
new file mode 100644
index 0000000000..d5478c1a15
--- /dev/null
+++ b/src/test/conf_examples/relay_33/expected_log
@@ -0,0 +1 @@
+Your ContactInfo config option is not set \ No newline at end of file
diff --git a/src/test/conf_examples/relay_33/torrc b/src/test/conf_examples/relay_33/torrc
new file mode 100644
index 0000000000..44d16ad31a
--- /dev/null
+++ b/src/test/conf_examples/relay_33/torrc
@@ -0,0 +1,4 @@
+# Relay tests
+# explicit IPv4 ORPort auto and IPv6 ORPort auto
+ORPort 127.0.0.1:auto
+ORPort [::1]:auto
diff --git a/src/test/conf_examples/relay_34/error_no_dirauth_relay b/src/test/conf_examples/relay_34/error_no_dirauth_relay
new file mode 100644
index 0000000000..9f9c0fd8f3
--- /dev/null
+++ b/src/test/conf_examples/relay_34/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with relay mode disabled.
diff --git a/src/test/conf_examples/relay_34/expected b/src/test/conf_examples/relay_34/expected
new file mode 100644
index 0000000000..bccde684f3
--- /dev/null
+++ b/src/test/conf_examples/relay_34/expected
@@ -0,0 +1,4 @@
+DirPort 127.0.0.1:auto
+Nickname Unnamed
+ORPort 127.0.0.1:auto
+ORPort [::1]:auto
diff --git a/src/test/conf_examples/relay_34/expected_log b/src/test/conf_examples/relay_34/expected_log
new file mode 100644
index 0000000000..d5478c1a15
--- /dev/null
+++ b/src/test/conf_examples/relay_34/expected_log
@@ -0,0 +1 @@
+Your ContactInfo config option is not set \ No newline at end of file
diff --git a/src/test/conf_examples/relay_34/torrc b/src/test/conf_examples/relay_34/torrc
new file mode 100644
index 0000000000..01010a5c38
--- /dev/null
+++ b/src/test/conf_examples/relay_34/torrc
@@ -0,0 +1,5 @@
+# Relay tests
+# explicit IPv4 ORPort and DirPort auto and IPv6 ORPort auto
+ORPort 127.0.0.1:auto
+ORPort [::1]:auto
+DirPort 127.0.0.1:auto
diff --git a/src/test/fuzz/fuzz_hsdescv3.c b/src/test/fuzz/fuzz_hsdescv3.c
index 3955241389..8d7eab1a8d 100644
--- a/src/test/fuzz/fuzz_hsdescv3.c
+++ b/src/test/fuzz/fuzz_hsdescv3.c
@@ -85,12 +85,12 @@ int
fuzz_main(const uint8_t *data, size_t sz)
{
hs_descriptor_t *desc = NULL;
- uint8_t subcredential[DIGEST256_LEN];
+ hs_subcredential_t subcredential;
char *fuzzing_data = tor_memdup_nulterm(data, sz);
- memset(subcredential, 'A', sizeof(subcredential));
+ memset(&subcredential, 'A', sizeof(subcredential));
- hs_desc_decode_descriptor(fuzzing_data, subcredential, NULL, &desc);
+ hs_desc_decode_descriptor(fuzzing_data, &subcredential, NULL, &desc);
if (desc) {
log_debug(LD_GENERAL, "Decoding okay");
hs_descriptor_free(desc);
@@ -101,4 +101,3 @@ fuzz_main(const uint8_t *data, size_t sz)
tor_free(fuzzing_data);
return 0;
}
-
diff --git a/src/test/hs_test_helpers.c b/src/test/hs_test_helpers.c
index e8b99aaac8..5116fc7169 100644
--- a/src/test/hs_test_helpers.c
+++ b/src/test/hs_test_helpers.c
@@ -13,9 +13,22 @@
#include "feature/hs/hs_service.h"
#include "test/hs_test_helpers.h"
+/**
+ * Create an introduction point taken straight out of an HSv3 descriptor.
+ *
+ * Use 'signing_kp' to sign the introduction point certificates.
+ *
+ * If 'intro_auth_kp' is provided use that as the introduction point
+ * authentication keypair, otherwise generate one on the fly.
+ *
+ * If 'intro_enc_kp' is provided use that as the introduction point encryption
+ * keypair, otherwise generate one on the fly.
+ */
hs_desc_intro_point_t *
hs_helper_build_intro_point(const ed25519_keypair_t *signing_kp, time_t now,
- const char *addr, int legacy)
+ const char *addr, int legacy,
+ const ed25519_keypair_t *intro_auth_kp,
+ const curve25519_keypair_t *intro_enc_kp)
{
int ret;
ed25519_keypair_t auth_kp;
@@ -56,8 +69,12 @@ hs_helper_build_intro_point(const ed25519_keypair_t *signing_kp, time_t now,
smartlist_add(ip->link_specifiers, ls_ip);
}
- ret = ed25519_keypair_generate(&auth_kp, 0);
- tt_int_op(ret, OP_EQ, 0);
+ if (intro_auth_kp) {
+ memcpy(&auth_kp, intro_auth_kp, sizeof(ed25519_keypair_t));
+ } else {
+ ret = ed25519_keypair_generate(&auth_kp, 0);
+ tt_int_op(ret, OP_EQ, 0);
+ }
ip->auth_key_cert = tor_cert_create(signing_kp, CERT_TYPE_AUTH_HS_IP_KEY,
&auth_kp.pubkey, now,
HS_DESC_CERT_LIFETIME,
@@ -85,8 +102,12 @@ hs_helper_build_intro_point(const ed25519_keypair_t *signing_kp, time_t now,
ed25519_keypair_t ed25519_kp;
tor_cert_t *cross_cert;
- ret = curve25519_keypair_generate(&curve25519_kp, 0);
- tt_int_op(ret, OP_EQ, 0);
+ if (intro_enc_kp) {
+ memcpy(&curve25519_kp, intro_enc_kp, sizeof(curve25519_keypair_t));
+ } else {
+ ret = curve25519_keypair_generate(&curve25519_kp, 0);
+ tt_int_op(ret, OP_EQ, 0);
+ }
ed25519_keypair_from_curve25519_keypair(&ed25519_kp, &signbit,
&curve25519_kp);
cross_cert = tor_cert_create(signing_kp, CERT_TYPE_CROSS_HS_IP_KEYS,
@@ -95,6 +116,8 @@ hs_helper_build_intro_point(const ed25519_keypair_t *signing_kp, time_t now,
CERT_FLAG_INCLUDE_SIGNING_KEY);
tt_assert(cross_cert);
ip->enc_key_cert = cross_cert;
+ memcpy(ip->enc_key.public_key, curve25519_kp.pubkey.public_key,
+ CURVE25519_PUBKEY_LEN);
}
intro_point = ip;
@@ -140,7 +163,7 @@ hs_helper_build_hs_desc_impl(unsigned int no_ip,
desc->plaintext_data.lifetime_sec = 3 * 60 * 60;
hs_get_subcredential(&signing_kp->pubkey, &blinded_kp.pubkey,
- desc->subcredential);
+ &desc->subcredential);
/* Setup superencrypted data section. */
ret = curve25519_keypair_generate(&auth_ephemeral_kp, 0);
@@ -165,13 +188,17 @@ hs_helper_build_hs_desc_impl(unsigned int no_ip,
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));
+ hs_helper_build_intro_point(signing_kp, now, "1.2.3.4", 0,
+ NULL, NULL));
smartlist_add(desc->encrypted_data.intro_points,
- hs_helper_build_intro_point(signing_kp, now, "[2600::1]", 0));
+ hs_helper_build_intro_point(signing_kp, now, "[2600::1]", 0,
+ NULL, NULL));
smartlist_add(desc->encrypted_data.intro_points,
- hs_helper_build_intro_point(signing_kp, now, "3.2.1.4", 1));
+ hs_helper_build_intro_point(signing_kp, now, "3.2.1.4", 1,
+ NULL, NULL));
smartlist_add(desc->encrypted_data.intro_points,
- hs_helper_build_intro_point(signing_kp, now, "5.6.7.8", 1));
+ hs_helper_build_intro_point(signing_kp, now, "5.6.7.8", 1,
+ NULL, NULL));
}
descp = desc;
@@ -186,7 +213,7 @@ hs_helper_build_hs_desc_impl(unsigned int no_ip,
* 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)
+ hs_subcredential_t *subcred_out)
{
ed25519_keypair_t blinded_kp;
uint64_t current_time_period = hs_get_time_period_num(approx_time());
@@ -233,7 +260,7 @@ hs_helper_build_hs_desc_with_client_auth(
memcpy(&desc->superencrypted_data.auth_ephemeral_pubkey,
&auth_ephemeral_kp.pubkey, sizeof(curve25519_public_key_t));
- hs_desc_build_authorized_client(desc->subcredential, client_pk,
+ hs_desc_build_authorized_client(&desc->subcredential, client_pk,
&auth_ephemeral_kp.seckey,
descriptor_cookie, desc_client);
smartlist_add(desc->superencrypted_data.clients, desc_client);
diff --git a/src/test/hs_test_helpers.h b/src/test/hs_test_helpers.h
index a01fd45d63..23d11f2a4a 100644
--- a/src/test/hs_test_helpers.h
+++ b/src/test/hs_test_helpers.h
@@ -8,9 +8,11 @@
#include "feature/hs/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_desc_intro_point_t *
+hs_helper_build_intro_point(const ed25519_keypair_t *signing_kp, time_t now,
+ const char *addr, int legacy,
+ const ed25519_keypair_t *intro_auth_kp,
+ const curve25519_keypair_t *intro_enc_kp);
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(
@@ -21,12 +23,11 @@ hs_descriptor_t *hs_helper_build_hs_desc_with_client_auth(
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);
+struct hs_subcredential_t;
+void hs_helper_get_subcred_from_identity_keypair(ed25519_keypair_t *signing_kp,
+ struct hs_subcredential_t *subcred_out);
void hs_helper_add_client_auth(const ed25519_public_key_t *service_pk,
const curve25519_secret_key_t *client_sk);
#endif /* !defined(TOR_HS_TEST_HELPERS_H) */
-
diff --git a/src/test/include.am b/src/test/include.am
index 33556083df..7814dbca89 100644
--- a/src/test/include.am
+++ b/src/test/include.am
@@ -26,7 +26,6 @@ TESTSCRIPTS = \
src/test/test_switch_id.sh \
src/test/test_cmdline.sh \
src/test/test_parseconf.sh \
- src/test/test_switch_id.sh \
src/test/unittest_part1.sh \
src/test/unittest_part2.sh \
src/test/unittest_part3.sh \
@@ -46,7 +45,8 @@ TESTSCRIPTS += \
src/test/test_ntor.sh \
src/test/test_hs_ntor.sh \
src/test/test_bt.sh \
- scripts/maint/practracker/test_practracker.sh
+ scripts/maint/practracker/test_practracker.sh \
+ scripts/maint/run_check_subsystem_order.sh
if COVERAGE_ENABLED
# ...
@@ -70,13 +70,25 @@ TESTS += src/test/test-slow src/test/test-memwipe \
$(TESTSCRIPTS)
# These flavors are run using automake's test-driver and test-network.sh
-TEST_CHUTNEY_FLAVORS = basic-min bridges-min hs-v2-min hs-v3-min \
- single-onion-v23
+
+# run a quick test or two
+# this test only uses IPv4
+TEST_CHUTNEY_FLAVOR_QUICK = bridges+hs-v23
# only run if we can ping6 ::1 (localhost)
+TEST_CHUTNEY_FLAVOR_QUICK_IPV6 = single-onion-v23-ipv6-md
+
+# run a basic set of tests, which only use IPv4
+TEST_CHUTNEY_FLAVORS = basic-min bridges-min hs-v23-min single-onion-v23
+
+# only run if we can ping ::1 (localhost)
TEST_CHUTNEY_FLAVORS_IPV6 = bridges+ipv6-min ipv6-exit-min hs-v23-ipv6-md \
single-onion-v23-ipv6-md
+
# only run if we can find a stable (or simply another) version of tor
-TEST_CHUTNEY_FLAVORS_MIXED = mixed+hs-v2
+TEST_CHUTNEY_FLAVORS_MIXED = mixed+hs-v23
+
+# only run if IPv6 and mixed networks are run
+TEST_CHUTNEY_FLAVORS_IPV6_MIXED = mixed+hs-v23-ipv6
### This is a lovely feature, but it requires automake >= 1.12, and Tor
### doesn't require that yet.
@@ -176,6 +188,7 @@ src_test_test_SOURCES += \
src/test/test_hs_client.c \
src/test/test_hs_intropoint.c \
src/test/test_hs_control.c \
+ src/test/test_hs_ob.c \
src/test/test_handles.c \
src/test/test_hs_cache.c \
src/test/test_hs_descriptor.c \
@@ -426,6 +439,7 @@ EXTRA_DIST += \
src/test/test_rebind.sh \
src/test/test_rebind.py \
src/test/zero_length_keys.sh \
+ scripts/maint/run_check_subsystem_order.sh \
src/test/rust_supp.txt \
src/test/test_keygen.sh \
src/test/test_key_expiration.sh \
diff --git a/src/test/log_test_helpers.h b/src/test/log_test_helpers.h
index e2ddf09466..c2d71c6bcd 100644
--- a/src/test/log_test_helpers.h
+++ b/src/test/log_test_helpers.h
@@ -78,7 +78,7 @@ void mock_dump_saved_logs(void);
mock_saved_log_n_entries() == 1, \
("expected log to contain exactly 1 message \"%s\"", \
str)); \
- } while (0);
+ } while (0)
#define expect_single_log_msg_containing(str) \
do { \
@@ -86,30 +86,30 @@ void mock_dump_saved_logs(void);
mock_saved_log_n_entries() == 1 , \
("expected log to contain 1 message, containing \"%s\"",\
str)); \
- } while (0);
+ } while (0)
#define expect_no_log_msg(str) \
assert_log_predicate(!mock_saved_log_has_message(str), \
- ("expected log to not contain \"%s\"",str));
+ ("expected log to not contain \"%s\"",str))
#define expect_no_log_msg_containing(str) \
assert_log_predicate(!mock_saved_log_has_message_containing(str), \
- ("expected log to not contain \"%s\"", str));
+ ("expected log to not contain \"%s\"", str))
#define expect_log_severity(severity) \
assert_log_predicate(mock_saved_log_has_severity(severity), \
- ("expected log to contain severity " # severity));
+ ("expected log to contain severity " # severity))
#define expect_no_log_severity(severity) \
assert_log_predicate(!mock_saved_log_has_severity(severity), \
- ("expected log to not contain severity " # severity));
+ ("expected log to not contain severity " # severity))
#define expect_log_entry() \
assert_log_predicate(mock_saved_log_has_entry(), \
- ("expected log to contain entries"));
+ ("expected log to contain entries"))
#define expect_no_log_entry() \
assert_log_predicate(!mock_saved_log_has_entry(), \
- ("expected log to not contain entries"));
+ ("expected log to not contain entries"))
#endif /* !defined(TOR_LOG_TEST_HELPERS_H) */
diff --git a/src/test/slow_ed25519.py b/src/test/slow_ed25519.py
index afad678000..be4eeab857 100644
--- a/src/test/slow_ed25519.py
+++ b/src/test/slow_ed25519.py
@@ -1,5 +1,5 @@
# This is the ed25519 implementation from
-# http://ed25519.cr.yp.to/python/ed25519.py .
+# https://ed25519.cr.yp.to/python/ed25519.py .
# It is in the public domain.
#
# It isn't constant-time. Don't use it except for testing. Also, see
diff --git a/src/test/test.c b/src/test/test.c
index 1742f1d952..4b6082ce4f 100644
--- a/src/test/test.c
+++ b/src/test/test.c
@@ -721,6 +721,7 @@ struct testgroup_t testgroups[] = {
{ "hs_dos/", hs_dos_tests },
{ "hs_intropoint/", hs_intropoint_tests },
{ "hs_ntor/", hs_ntor_tests },
+ { "hs_ob/", hs_ob_tests },
{ "hs_service/", hs_service_tests },
{ "introduce/", introduce_tests },
{ "keypin/", keypin_tests },
diff --git a/src/test/test.h b/src/test/test.h
index 63e2faff95..18987719d0 100644
--- a/src/test/test.h
+++ b/src/test/test.h
@@ -141,6 +141,7 @@ extern struct testcase_t hs_descriptor[];
extern struct testcase_t hs_dos_tests[];
extern struct testcase_t hs_intropoint_tests[];
extern struct testcase_t hs_ntor_tests[];
+extern struct testcase_t hs_ob_tests[];
extern struct testcase_t hs_service_tests[];
extern struct testcase_t hs_tests[];
extern struct testcase_t introduce_tests[];
diff --git a/src/test/test_addr.c b/src/test/test_addr.c
index 42232e467a..cf5aad7e71 100644
--- a/src/test/test_addr.c
+++ b/src/test/test_addr.c
@@ -659,12 +659,7 @@ test_addr_ip6_helpers(void *arg)
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_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_uint_op(port1, OP_EQ, 1);
- tt_uint_op(port2, OP_EQ, 2);
+ tt_int_op(r, OP_EQ, -1);
r=tor_addr_parse_mask_ports("1.1.2.3/255.255.128.0",0,&t1, &mask,NULL,NULL);
tt_int_op(r, OP_EQ, AF_INET);
tt_int_op(mask,OP_EQ,17);
@@ -1653,6 +1648,159 @@ test_addr_rfc6598(void *arg)
;
}
+#define TEST_ADDR_ATON(a, rv) STMT_BEGIN \
+ struct in_addr addr; \
+ tt_int_op(tor_inet_aton(a, &addr), OP_EQ, rv); \
+ STMT_END;
+
+static void
+test_addr_octal(void *arg)
+{
+ (void)arg;
+
+ /* Test non-octal IP addresses. */
+ TEST_ADDR_ATON("0.1.2.3", 1);
+ TEST_ADDR_ATON("1.0.2.3", 1);
+ TEST_ADDR_ATON("1.2.3.0", 1);
+
+ /* Test octal IP addresses. */
+ TEST_ADDR_ATON("01.1.2.3", 0);
+ TEST_ADDR_ATON("1.02.3.4", 0);
+ TEST_ADDR_ATON("1.2.3.04", 0);
+ done:
+ ;
+}
+
+#define get_ipv4(test_addr, str, iprv) STMT_BEGIN \
+ test_addr = tor_malloc(sizeof(tor_addr_t)); \
+ test_addr->family = AF_INET; \
+ iprv = tor_inet_aton(str, &test_addr->addr.in_addr); \
+ tor_assert(iprv); \
+ STMT_END;
+
+#define get_ipv6(test_addr, str, iprv) STMT_BEGIN \
+ test_addr = tor_malloc(sizeof(tor_addr_t)); \
+ test_addr->family = AF_INET6; \
+ iprv = tor_inet_pton(AF_INET6, str, &test_addr->addr.in6_addr); \
+ tor_assert(iprv); \
+ STMT_END;
+
+#define get_af_unix(test_addr) STMT_BEGIN \
+ test_addr = tor_malloc_zero(sizeof(tor_addr_t)); \
+ test_addr->family = AF_UNIX; \
+ STMT_END;
+
+#define get_af_unspec(test_addr) STMT_BEGIN \
+ test_addr = tor_malloc_zero(sizeof(tor_addr_t)); \
+ test_addr->family = AF_UNSPEC; \
+ STMT_END;
+
+#define TEST_ADDR_VALIDITY(a, lis, rv) STMT_BEGIN \
+ tor_assert(a); \
+ tt_int_op(tor_addr_is_valid(a, lis), OP_EQ, rv); \
+ STMT_END;
+
+/* Here we can change the addresses we are testing for. */
+#define IP4_TEST_ADDR "123.98.45.1"
+#define IP6_TEST_ADDR "2001:0DB8:AC10:FE01::"
+
+static void
+test_addr_is_valid(void *arg)
+{
+ (void)arg;
+ tor_addr_t *test_addr;
+ int iprv;
+
+ /* Tests for IPv4 addresses. */
+
+ /* Test for null IPv4 address. */
+ get_ipv4(test_addr, "0.0.0.0", iprv);
+ TEST_ADDR_VALIDITY(test_addr, 0, 0);
+ TEST_ADDR_VALIDITY(test_addr, 1, 1);
+ tor_free(test_addr);
+
+ /* Test for non-null IPv4 address. */
+ get_ipv4(test_addr, IP4_TEST_ADDR, iprv);
+ TEST_ADDR_VALIDITY(test_addr, 0, 1);
+ TEST_ADDR_VALIDITY(test_addr, 1, 1);
+ tor_free(test_addr);
+
+ /* Tests for IPv6 addresses. */
+
+ /* Test for null IPv6 address. */
+ get_ipv6(test_addr, "::", iprv);
+ TEST_ADDR_VALIDITY(test_addr, 0, 0);
+ TEST_ADDR_VALIDITY(test_addr, 1, 1);
+ tor_free(test_addr);
+
+ /* Test for non-null IPv6 address. */
+ get_ipv6(test_addr, IP6_TEST_ADDR, iprv);
+ TEST_ADDR_VALIDITY(test_addr, 0, 1);
+ TEST_ADDR_VALIDITY(test_addr, 1, 1);
+ tor_free(test_addr);
+
+ /* Test for address of type AF_UNIX. */
+
+ get_af_unix(test_addr);
+ TEST_ADDR_VALIDITY(test_addr, 0, 0);
+ TEST_ADDR_VALIDITY(test_addr, 1, 0);
+ tor_free(test_addr);
+
+ /* Test for address of type AF_UNSPEC. */
+
+ get_af_unspec(test_addr);
+ TEST_ADDR_VALIDITY(test_addr, 0, 0);
+ TEST_ADDR_VALIDITY(test_addr, 1, 0);
+
+ done:
+ tor_free(test_addr);
+}
+
+#define TEST_ADDR_IS_NULL(a, rv) STMT_BEGIN \
+ tor_assert(a); \
+ tt_int_op(tor_addr_is_null(a), OP_EQ, rv); \
+ STMT_END;
+
+static void
+test_addr_is_null(void *arg)
+{
+ (void)arg;
+ tor_addr_t *test_addr;
+ int iprv;
+
+ /* Test for null IPv4. */
+ get_ipv4(test_addr, "0.0.0.0", iprv);
+ TEST_ADDR_IS_NULL(test_addr, 1);
+ tor_free(test_addr);
+
+ /* Test for non-null IPv4. */
+ get_ipv4(test_addr, IP4_TEST_ADDR, iprv);
+ TEST_ADDR_IS_NULL(test_addr, 0);
+ tor_free(test_addr);
+
+ /* Test for null IPv6. */
+ get_ipv6(test_addr, "::", iprv);
+ TEST_ADDR_IS_NULL(test_addr, 1);
+ tor_free(test_addr);
+
+ /* Test for non-null IPv6. */
+ get_ipv6(test_addr, IP6_TEST_ADDR, iprv);
+ TEST_ADDR_IS_NULL(test_addr, 0);
+ tor_free(test_addr);
+
+ /* Test for address family AF_UNIX. */
+ get_af_unix(test_addr);
+ TEST_ADDR_IS_NULL(test_addr, 1);
+ tor_free(test_addr);
+
+ /* Test for address family AF_UNSPEC. */
+ get_af_unspec(test_addr);
+ TEST_ADDR_IS_NULL(test_addr, 1);
+
+ done:
+ tor_free(test_addr);
+}
+
#ifndef COCCI
#define ADDR_LEGACY(name) \
{ #name, test_addr_ ## name , 0, NULL, NULL }
@@ -1671,5 +1819,8 @@ struct testcase_t addr_tests[] = {
{ "is_loopback", test_addr_is_loopback, 0, NULL, NULL },
{ "make_null", test_addr_make_null, 0, NULL, NULL },
{ "rfc6598", test_addr_rfc6598, 0, NULL, NULL },
+ { "octal", test_addr_octal, 0, NULL, NULL },
+ { "address_validity", test_addr_is_valid, 0, NULL, NULL },
+ { "address_is_null", test_addr_is_null, 0, NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_address.c b/src/test/test_address.c
index e068c99d97..4cedbda347 100644
--- a/src/test/test_address.c
+++ b/src/test/test_address.c
@@ -460,7 +460,7 @@ test_address_ifreq_to_smartlist(void *arg)
ifc->ifc_len = sizeof(struct ifreq);
ifc->ifc_ifcu.ifcu_req = ifr;
- results = ifreq_to_smartlist(ifc->ifc_buf,ifc->ifc_len);
+ results = ifreq_to_smartlist((const uint8_t *)ifc->ifc_buf,ifc->ifc_len);
tt_int_op(smartlist_len(results),OP_EQ,1);
tor_addr = smartlist_get(results, 0);
@@ -483,7 +483,7 @@ test_address_ifreq_to_smartlist(void *arg)
SMARTLIST_FOREACH(results, tor_addr_t *, t, tor_free(t));
smartlist_free(results);
- results = ifreq_to_smartlist(ifc->ifc_buf,ifc->ifc_len);
+ results = ifreq_to_smartlist((const uint8_t *)ifc->ifc_buf,ifc->ifc_len);
tt_int_op(smartlist_len(results),OP_EQ,2);
tor_addr = smartlist_get(results, 0);
diff --git a/src/test/test_cell_formats.c b/src/test/test_cell_formats.c
index 8d6d1940fd..f9ff101c98 100644
--- a/src/test/test_cell_formats.c
+++ b/src/test/test_cell_formats.c
@@ -713,16 +713,20 @@ test_cfmt_extend_cells(void *arg)
tt_mem_op(cc->onionskin,OP_EQ, b, 99+20);
tt_int_op(0, OP_EQ, extend_cell_format(&p2_cmd, &p2_len, p2, &ec));
tt_int_op(p2_cmd, OP_EQ, RELAY_COMMAND_EXTEND2);
- /* We'll generate it minus the IPv6 address and minus the konami code */
- tt_int_op(p2_len, OP_EQ, 89+99-34-20);
+ /* We'll generate it minus the konami code */
+ tt_int_op(p2_len, OP_EQ, 89+99-34);
test_memeq_hex(p2,
- /* Two items: one that same darn IP address. */
- "02000612F40001F0F1"
- /* The next is a digest : anthropomorphization */
- "0214616e7468726f706f6d6f727068697a6174696f6e"
+ /* Three items */
+ "03"
+ /* IPv4 address */
+ "0006" "12F40001" "F0F1"
+ /* The next is an RSA digest: anthropomorphization */
+ "0214" "616e7468726f706f6d6f727068697a6174696f6e"
+ /*IPv6 address */
+ "0112" "20020000000000000000000000f0c51e" "1112"
/* Now the handshake prologue */
"01050063");
- tt_mem_op(p2+1+8+22+4,OP_EQ, b, 99+20);
+ tt_mem_op(p2+1+8+22+20+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. */
@@ -732,22 +736,31 @@ test_cfmt_extend_cells(void *arg)
/* 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);
+ tt_int_op(p2_len, OP_EQ, 89+99-34);
test_memeq_hex(p2,
- "02000612F40001F0F1"
+ "03"
+ "000612F40001F0F1"
"0214616e7468726f706f6d6f727068697a6174696f6e"
+ "011220020000000000000000000000f0c51e1112"
"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);
+ tt_int_op(p2_len, OP_EQ, 89+99);
test_memeq_hex(p2,
- "03000612F40001F0F1"
+ /* Four items */
+ "04"
+ /* IPv4 address */
+ "0006" "12F40001" "F0F1"
+ /* The next is an RSA digest: anthropomorphization */
"0214616e7468726f706f6d6f727068697a6174696f6e"
- // ed digest follows:
+ /* Then an ed public key: brownshoesdontmakeit/brownshoesd */
"0320" "62726f776e73686f6573646f6e746d616b656"
"9742f62726f776e73686f657364"
+ /*IPv6 address */
+ "0112" "20020000000000000000000000f0c51e" "1112"
+ /* Now the handshake prologue */
"01050063");
/* Can we parse that? Did the key come through right? */
memset(&ec, 0, sizeof(ec));
@@ -756,6 +769,40 @@ test_cfmt_extend_cells(void *arg)
tt_mem_op("brownshoesdontmakeit/brownshoesd", OP_EQ,
ec.ed_pubkey.pubkey, 32);
+ /* Now try IPv6 without IPv4 */
+ memset(p, 0, sizeof(p));
+ memcpy(p, "\x02", 1);
+ memcpy(p+1, "\x02\x14" "anthropomorphization", 22);
+ memcpy(p+23, "\x01\x12" "xxxxxxxxxxxxxxxxYY", 20);
+ memcpy(p+43, "\xff\xff\x00\x20", 4);
+ tt_int_op(0, OP_EQ, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
+ p, sizeof(p)));
+ tt_int_op(RELAY_COMMAND_EXTEND2, OP_EQ, ec.cell_type);
+ tt_assert(fast_mem_is_zero((const char *)&ec.orport_ipv4.addr,
+ sizeof(tor_addr_t)));
+ tt_int_op(0, OP_EQ, ec.orport_ipv4.port);
+ tt_str_op("7878:7878:7878:7878:7878:7878:7878:7878",
+ OP_EQ, fmt_addr(&ec.orport_ipv6.addr));
+ tt_int_op(22873, 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, 0xffff);
+ tt_int_op(cc->handshake_len, OP_EQ, 32);
+ tt_int_op(0, OP_EQ, extend_cell_format(&p2_cmd, &p2_len, p2, &ec));
+ tt_int_op(p2_cmd, OP_EQ, RELAY_COMMAND_EXTEND2);
+ tt_int_op(p2_len, OP_EQ, 47+32);
+ test_memeq_hex(p2,
+ /* Two items */
+ "02"
+ /* The next is an RSA digest: anthropomorphization */
+ "0214" "616e7468726f706f6d6f727068697a6174696f6e"
+ /*IPv6 address */
+ "0112" "78787878787878787878787878787878" "5959"
+ /* Now the handshake prologue */
+ "ffff0020");
+ tt_int_op(0, OP_EQ, create_cell_format_relayed(&cell, cc));
+
/* == Now try parsing some junk */
/* Try a too-long handshake */
@@ -811,13 +858,6 @@ test_cfmt_extend_cells(void *arg)
memcpy(p+48, "\xff\xff\x00\x20", 4);
tt_int_op(-1, OP_EQ, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
p, sizeof(p)));
- memset(p, 0, sizeof(p));
- memcpy(p, "\x02", 1);
- memcpy(p+1, "\x02\x14" "anarchoindividualist", 22);
- memcpy(p+23, "\x01\x12" "xxxxxxxxxxxxxxxxYY", 18);
- memcpy(p+41, "\xff\xff\x00\x20", 4);
- tt_int_op(-1, OP_EQ, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
- p, sizeof(p)));
/* Running out of space in specifiers */
memset(p,0,sizeof(p));
diff --git a/src/test/test_channel.c b/src/test/test_channel.c
index 01aa01b4db..83b69cc80b 100644
--- a/src/test/test_channel.c
+++ b/src/test/test_channel.c
@@ -1321,7 +1321,7 @@ test_channel_for_extend(void *arg)
channel_t *ret_chan = NULL;
char digest[DIGEST_LEN];
ed25519_public_key_t ed_id;
- tor_addr_t addr;
+ tor_addr_t ipv4_addr, ipv6_addr;
const char *msg;
int launch;
time_t now = time(NULL);
@@ -1331,6 +1331,9 @@ test_channel_for_extend(void *arg)
memset(digest, 'A', sizeof(digest));
memset(&ed_id, 'B', sizeof(ed_id));
+ tor_addr_make_null(&ipv4_addr, AF_INET);
+ tor_addr_make_null(&ipv6_addr, AF_INET6);
+
chan1 = new_fake_channel();
tt_assert(chan1);
/* Need to be registered to get added to the id map. */
@@ -1364,7 +1367,8 @@ test_channel_for_extend(void *arg)
tt_ptr_op(channel_find_by_remote_identity(digest, &ed_id), OP_EQ, chan1);
/* The expected result is chan2 because it is older than chan1. */
- ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
+ ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr,
+ &msg, &launch);
tt_assert(ret_chan);
tt_ptr_op(ret_chan, OP_EQ, chan2);
tt_int_op(launch, OP_EQ, 0);
@@ -1372,16 +1376,18 @@ test_channel_for_extend(void *arg)
/* Switch that around from previous test. */
chan2->timestamp_created = chan1->timestamp_created + 1;
- ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
+ ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr,
+ &msg, &launch);
tt_assert(ret_chan);
tt_ptr_op(ret_chan, OP_EQ, chan1);
tt_int_op(launch, OP_EQ, 0);
tt_str_op(msg, OP_EQ, "Connection is fine; using it.");
/* Same creation time, num circuits will be used and they both have 0 so the
- * channel 2 should be picked due to how channel_is_better() work. */
+ * channel 2 should be picked due to how channel_is_better() works. */
chan2->timestamp_created = chan1->timestamp_created;
- ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
+ ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr,
+ &msg, &launch);
tt_assert(ret_chan);
tt_ptr_op(ret_chan, OP_EQ, chan1);
tt_int_op(launch, OP_EQ, 0);
@@ -1392,7 +1398,8 @@ test_channel_for_extend(void *arg)
/* Condemned the older channel. */
chan1->state = CHANNEL_STATE_CLOSING;
- ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
+ ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr,
+ &msg, &launch);
tt_assert(ret_chan);
tt_ptr_op(ret_chan, OP_EQ, chan2);
tt_int_op(launch, OP_EQ, 0);
@@ -1401,7 +1408,8 @@ test_channel_for_extend(void *arg)
/* Make the older channel a client one. */
channel_mark_client(chan1);
- ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
+ ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr,
+ &msg, &launch);
tt_assert(ret_chan);
tt_ptr_op(ret_chan, OP_EQ, chan2);
tt_int_op(launch, OP_EQ, 0);
@@ -1411,8 +1419,9 @@ test_channel_for_extend(void *arg)
/* Non matching ed identity with valid digest. */
ed25519_public_key_t dumb_ed_id;
memset(&dumb_ed_id, 0, sizeof(dumb_ed_id));
- ret_chan = channel_get_for_extend(digest, &dumb_ed_id, &addr, &msg,
- &launch);
+ ret_chan = channel_get_for_extend(digest, &dumb_ed_id,
+ &ipv4_addr, &ipv6_addr,
+ &msg, &launch);
tt_assert(!ret_chan);
tt_str_op(msg, OP_EQ, "Not connected. Connecting.");
tt_int_op(launch, OP_EQ, 1);
@@ -1421,7 +1430,8 @@ test_channel_for_extend(void *arg)
test_chan_should_match_target = 1;
chan1->state = CHANNEL_STATE_OPENING;
chan2->state = CHANNEL_STATE_OPENING;
- ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
+ ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr,
+ &msg, &launch);
tt_assert(!ret_chan);
tt_str_op(msg, OP_EQ, "Connection in progress; waiting.");
tt_int_op(launch, OP_EQ, 0);
@@ -1430,7 +1440,8 @@ test_channel_for_extend(void *arg)
/* Mark channel 1 as bad for circuits. */
channel_mark_bad_for_new_circs(chan1);
- ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
+ ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr,
+ &msg, &launch);
tt_assert(ret_chan);
tt_ptr_op(ret_chan, OP_EQ, chan2);
tt_int_op(launch, OP_EQ, 0);
@@ -1440,7 +1451,8 @@ test_channel_for_extend(void *arg)
/* Mark both channels as unusable. */
channel_mark_bad_for_new_circs(chan1);
channel_mark_bad_for_new_circs(chan2);
- ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
+ ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr,
+ &msg, &launch);
tt_assert(!ret_chan);
tt_str_op(msg, OP_EQ, "Connections all too old, or too non-canonical. "
" Launching a new one.");
@@ -1451,7 +1463,8 @@ test_channel_for_extend(void *arg)
/* Non canonical channels. */
test_chan_should_be_canonical = 0;
test_chan_should_match_target = 0;
- ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
+ ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr,
+ &msg, &launch);
tt_assert(!ret_chan);
tt_str_op(msg, OP_EQ, "Connections all too old, or too non-canonical. "
" Launching a new one.");
diff --git a/src/test/test_channeltls.c b/src/test/test_channeltls.c
index 94ce56f2be..f4f5cb447e 100644
--- a/src/test/test_channeltls.c
+++ b/src/test/test_channeltls.c
@@ -14,6 +14,7 @@
#include "core/mainloop/connection.h"
#include "core/or/connection_or.h"
#include "app/config/config.h"
+#include "app/config/resolve_addr.h"
/* For init/free stuff */
#include "core/or/scheduler.h"
#include "lib/tls/tortls.h"
diff --git a/src/test/test_circuitbuild.c b/src/test/test_circuitbuild.c
index 70920c0c52..03fd176ead 100644
--- a/src/test/test_circuitbuild.c
+++ b/src/test/test_circuitbuild.c
@@ -8,18 +8,32 @@
#define ENTRYNODES_PRIVATE
#include "core/or/or.h"
+
#include "test/test.h"
#include "test/test_helpers.h"
#include "test/log_test_helpers.h"
+
+#define CONFIG_PRIVATE
#include "app/config/config.h"
+
+#include "core/or/channel.h"
#include "core/or/circuitbuild.h"
#include "core/or/circuitlist.h"
+#include "core/or/onion.h"
+#include "core/or/cell_st.h"
#include "core/or/cpath_build_state_st.h"
#include "core/or/extend_info_st.h"
#include "core/or/origin_circuit_st.h"
+#include "core/or/or_circuit_st.h"
#include "feature/client/entrynodes.h"
+#include "feature/nodelist/nodelist.h"
+#include "feature/relay/circuitbuild_relay.h"
+#include "feature/relay/router.h"
+#include "feature/relay/routermode.h"
+
+#include "feature/nodelist/node_st.h"
/* Dummy nodes smartlist for testing */
static smartlist_t dummy_nodes;
@@ -114,6 +128,14 @@ test_new_route_len_unhandled_exit(void *arg)
int r;
(void)arg;
+#ifdef ALL_BUGS_ARE_FATAL
+ /* Coverity (and maybe clang analyser) complain that the code following
+ * tt_skip() is unconditionally unreachable. */
+#if !defined(__COVERITY__) && !defined(__clang_analyzer__)
+ tt_skip();
+#endif
+#endif /* defined(ALL_BUGS_ARE_FATAL) */
+
MOCK(count_acceptable_nodes, mock_count_acceptable_nodes);
tor_capture_bugs_(1);
@@ -125,10 +147,10 @@ test_new_route_len_unhandled_exit(void *arg)
"!(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:
+ teardown_capture_of_logs();
+ tor_end_capture_bugs_();
UNMOCK(count_acceptable_nodes);
}
@@ -172,12 +194,1361 @@ test_upgrade_from_guard_wait(void *arg)
entry_guard_free_(guard);
}
+static int server = 0;
+static int
+mock_server_mode(const or_options_t *options)
+{
+ (void)options;
+ return server;
+}
+
+/* Test the different cases in circuit_extend_state_valid_helper(). */
+static void
+test_circuit_extend_state_valid(void *arg)
+{
+ (void)arg;
+ circuit_t *circ = tor_malloc_zero(sizeof(circuit_t));
+
+ server = 0;
+ MOCK(server_mode, mock_server_mode);
+
+ setup_full_capture_of_logs(LOG_INFO);
+
+ /* Clients can't extend */
+ server = 0;
+ tt_int_op(circuit_extend_state_valid_helper(NULL), OP_EQ, -1);
+ expect_log_msg("Got an extend cell, but running as a client. Closing.\n");
+ mock_clean_saved_logs();
+
+#ifndef ALL_BUGS_ARE_FATAL
+ /* Circuit must be non-NULL */
+ tor_capture_bugs_(1);
+ server = 1;
+ tt_int_op(circuit_extend_state_valid_helper(NULL), OP_EQ, -1);
+ 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,
+ "!(ASSERT_PREDICT_UNLIKELY_(!circ))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+#endif /* !defined(ALL_BUGS_ARE_FATAL) */
+
+ /* n_chan and n_hop are NULL, this should succeed */
+ server = 1;
+ tt_int_op(circuit_extend_state_valid_helper(circ), OP_EQ, 0);
+ mock_clean_saved_logs();
+
+ /* But clients still can't extend */
+ server = 0;
+ tt_int_op(circuit_extend_state_valid_helper(circ), OP_EQ, -1);
+ expect_log_msg("Got an extend cell, but running as a client. Closing.\n");
+ mock_clean_saved_logs();
+
+ /* n_chan must be NULL */
+ circ->n_chan = tor_malloc_zero(sizeof(channel_t));
+ server = 1;
+ tt_int_op(circuit_extend_state_valid_helper(circ), OP_EQ, -1);
+ expect_log_msg("n_chan already set. Bug/attack. Closing.\n");
+ mock_clean_saved_logs();
+ tor_free(circ->n_chan);
+
+ /* n_hop must be NULL */
+ circ->n_hop = tor_malloc_zero(sizeof(extend_info_t));
+ server = 1;
+ tt_int_op(circuit_extend_state_valid_helper(circ), OP_EQ, -1);
+ expect_log_msg("conn to next hop already launched. Bug/attack. Closing.\n");
+ mock_clean_saved_logs();
+ tor_free(circ->n_hop);
+
+ done:
+ tor_end_capture_bugs_();
+ teardown_capture_of_logs();
+
+ UNMOCK(server_mode);
+ server = 0;
+
+ tor_free(circ->n_chan);
+ tor_free(circ->n_hop);
+ tor_free(circ);
+}
+
+static node_t *mocked_node = NULL;
+static const node_t *
+mock_node_get_by_id(const char *identity_digest)
+{
+ (void)identity_digest;
+ return mocked_node;
+}
+
+static int mocked_supports_ed25519_link_authentication = 0;
+static int
+mock_node_supports_ed25519_link_authentication(const node_t *node,
+ int compatible_with_us)
+{
+ (void)node;
+ (void)compatible_with_us;
+ return mocked_supports_ed25519_link_authentication;
+}
+
+static ed25519_public_key_t * mocked_ed25519_id = NULL;
+static const ed25519_public_key_t *
+mock_node_get_ed25519_id(const node_t *node)
+{
+ (void)node;
+ return mocked_ed25519_id;
+}
+
+/* Test the different cases in circuit_extend_add_ed25519_helper(). */
+static void
+test_circuit_extend_add_ed25519(void *arg)
+{
+ (void)arg;
+ extend_cell_t *ec = tor_malloc_zero(sizeof(extend_cell_t));
+ extend_cell_t *old_ec = tor_malloc_zero(sizeof(extend_cell_t));
+ extend_cell_t *zero_ec = tor_malloc_zero(sizeof(extend_cell_t));
+
+ node_t *fake_node = tor_malloc_zero(sizeof(node_t));
+ ed25519_public_key_t *fake_ed25519_id = NULL;
+ fake_ed25519_id = tor_malloc_zero(sizeof(ed25519_public_key_t));
+
+ MOCK(node_get_by_id, mock_node_get_by_id);
+ MOCK(node_supports_ed25519_link_authentication,
+ mock_node_supports_ed25519_link_authentication);
+ MOCK(node_get_ed25519_id, mock_node_get_ed25519_id);
+
+ setup_full_capture_of_logs(LOG_INFO);
+
+#ifndef ALL_BUGS_ARE_FATAL
+ /* The extend cell must be non-NULL */
+ tor_capture_bugs_(1);
+ tt_int_op(circuit_extend_add_ed25519_helper(NULL), OP_EQ, -1);
+ 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,
+ "!(ASSERT_PREDICT_UNLIKELY_(!ec))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+#endif /* !defined(ALL_BUGS_ARE_FATAL) */
+
+ /* The node id must be non-zero */
+ memcpy(old_ec, ec, sizeof(extend_cell_t));
+ tt_int_op(circuit_extend_add_ed25519_helper(ec), OP_EQ, -1);
+ expect_log_msg(
+ "Client asked me to extend without specifying an id_digest.\n");
+ /* And nothing should have changed */
+ tt_mem_op(ec, OP_EQ, old_ec, sizeof(extend_cell_t));
+ mock_clean_saved_logs();
+
+ /* Fill in fake node_id, and try again */
+ memset(ec->node_id, 0xAA, sizeof(ec->node_id));
+ memcpy(old_ec, ec, sizeof(extend_cell_t));
+ tt_int_op(circuit_extend_add_ed25519_helper(ec), OP_EQ, 0);
+ /* There's no node with that id, so the ed pubkey should still be zeroed */
+ tt_mem_op(&ec->ed_pubkey, OP_EQ, &zero_ec->ed_pubkey, sizeof(ec->ed_pubkey));
+ /* In fact, nothing should have changed */
+ tt_mem_op(ec, OP_EQ, old_ec, sizeof(extend_cell_t));
+ mock_clean_saved_logs();
+
+ /* Provide 2 out of 3 of node, supports link auth, and ed_id.
+ * The ed_id should remain zeroed. */
+
+ /* Provide node and supports link auth */
+ memset(ec->node_id, 0xAA, sizeof(ec->node_id));
+ memcpy(old_ec, ec, sizeof(extend_cell_t));
+ /* Set up the fake variables */
+ mocked_node = fake_node;
+ mocked_supports_ed25519_link_authentication = 1;
+ /* Do the test */
+ tt_int_op(circuit_extend_add_ed25519_helper(ec), OP_EQ, 0);
+ /* The ed pubkey should still be zeroed */
+ tt_mem_op(&ec->ed_pubkey, OP_EQ, &zero_ec->ed_pubkey, sizeof(ec->ed_pubkey));
+ /* In fact, nothing should have changed */
+ tt_mem_op(ec, OP_EQ, old_ec, sizeof(extend_cell_t));
+ /* Cleanup */
+ mock_clean_saved_logs();
+ mocked_node = NULL;
+ mocked_supports_ed25519_link_authentication = 0;
+ mocked_ed25519_id = NULL;
+ memset(fake_ed25519_id, 0x00, sizeof(ed25519_public_key_t));
+
+ /* Provide supports link auth and ed id */
+ memset(ec->node_id, 0xAA, sizeof(ec->node_id));
+ memcpy(old_ec, ec, sizeof(extend_cell_t));
+ /* Set up the fake variables */
+ mocked_supports_ed25519_link_authentication = 1;
+ memset(fake_ed25519_id, 0xEE, sizeof(ed25519_public_key_t));
+ mocked_ed25519_id = fake_ed25519_id;
+ /* Do the test */
+ tt_int_op(circuit_extend_add_ed25519_helper(ec), OP_EQ, 0);
+ /* The ed pubkey should still be zeroed */
+ tt_mem_op(&ec->ed_pubkey, OP_EQ, &zero_ec->ed_pubkey, sizeof(ec->ed_pubkey));
+ /* In fact, nothing should have changed */
+ tt_mem_op(ec, OP_EQ, old_ec, sizeof(extend_cell_t));
+ /* Cleanup */
+ mock_clean_saved_logs();
+ mocked_node = NULL;
+ mocked_supports_ed25519_link_authentication = 0;
+ mocked_ed25519_id = NULL;
+ memset(fake_ed25519_id, 0x00, sizeof(ed25519_public_key_t));
+
+ /* Provide node and ed id */
+ memset(ec->node_id, 0xAA, sizeof(ec->node_id));
+ memcpy(old_ec, ec, sizeof(extend_cell_t));
+ /* Set up the fake variables */
+ mocked_node = fake_node;
+ memset(fake_ed25519_id, 0xEE, sizeof(ed25519_public_key_t));
+ mocked_ed25519_id = fake_ed25519_id;
+ /* Do the test */
+ tt_int_op(circuit_extend_add_ed25519_helper(ec), OP_EQ, 0);
+ /* The ed pubkey should still be zeroed */
+ tt_mem_op(&ec->ed_pubkey, OP_EQ, &zero_ec->ed_pubkey, sizeof(ec->ed_pubkey));
+ /* In fact, nothing should have changed */
+ tt_mem_op(ec, OP_EQ, old_ec, sizeof(extend_cell_t));
+ /* Cleanup */
+ mock_clean_saved_logs();
+ mocked_node = NULL;
+ mocked_supports_ed25519_link_authentication = 0;
+ mocked_ed25519_id = NULL;
+ memset(fake_ed25519_id, 0x00, sizeof(ed25519_public_key_t));
+
+ /* Now do the real lookup */
+ memset(ec->node_id, 0xAA, sizeof(ec->node_id));
+ memcpy(old_ec, ec, sizeof(extend_cell_t));
+ /* Set up the fake variables */
+ mocked_node = fake_node;
+ mocked_supports_ed25519_link_authentication = 1;
+ memset(fake_ed25519_id, 0xEE, sizeof(ed25519_public_key_t));
+ mocked_ed25519_id = fake_ed25519_id;
+ /* Do the test */
+ tt_int_op(circuit_extend_add_ed25519_helper(ec), OP_EQ, 0);
+ /* The ed pubkey should match */
+ tt_mem_op(&ec->ed_pubkey, OP_EQ, fake_ed25519_id, sizeof(ec->ed_pubkey));
+ /* Nothing else should have changed */
+ memcpy(&ec->ed_pubkey, &old_ec->ed_pubkey, sizeof(ec->ed_pubkey));
+ tt_mem_op(ec, OP_EQ, old_ec, sizeof(extend_cell_t));
+ /* Cleanup */
+ mock_clean_saved_logs();
+ mocked_node = NULL;
+ mocked_supports_ed25519_link_authentication = 0;
+ mocked_ed25519_id = NULL;
+ memset(fake_ed25519_id, 0x00, sizeof(ed25519_public_key_t));
+
+ /* Now do the real lookup, but with a zeroed ed id */
+ memset(ec->node_id, 0xAA, sizeof(ec->node_id));
+ memcpy(old_ec, ec, sizeof(extend_cell_t));
+ /* Set up the fake variables */
+ mocked_node = fake_node;
+ mocked_supports_ed25519_link_authentication = 1;
+ memset(fake_ed25519_id, 0x00, sizeof(ed25519_public_key_t));
+ mocked_ed25519_id = fake_ed25519_id;
+ /* Do the test */
+ tt_int_op(circuit_extend_add_ed25519_helper(ec), OP_EQ, 0);
+ /* The ed pubkey should match */
+ tt_mem_op(&ec->ed_pubkey, OP_EQ, fake_ed25519_id, sizeof(ec->ed_pubkey));
+ /* Nothing else should have changed */
+ memcpy(&ec->ed_pubkey, &old_ec->ed_pubkey, sizeof(ec->ed_pubkey));
+ tt_mem_op(ec, OP_EQ, old_ec, sizeof(extend_cell_t));
+ /* Cleanup */
+ mock_clean_saved_logs();
+ mocked_node = NULL;
+ mocked_supports_ed25519_link_authentication = 0;
+ mocked_ed25519_id = NULL;
+ memset(fake_ed25519_id, 0x00, sizeof(ed25519_public_key_t));
+
+ done:
+ UNMOCK(node_get_by_id);
+ UNMOCK(node_supports_ed25519_link_authentication);
+ UNMOCK(node_get_ed25519_id);
+
+ tor_end_capture_bugs_();
+ teardown_capture_of_logs();
+
+ tor_free(ec);
+ tor_free(old_ec);
+ tor_free(zero_ec);
+
+ tor_free(fake_ed25519_id);
+ tor_free(fake_node);
+}
+
+static or_options_t *mocked_options = NULL;
+static const or_options_t *
+mock_get_options(void)
+{
+ return mocked_options;
+}
+
+#define PUBLIC_IPV4 "1.2.3.4"
+#define INTERNAL_IPV4 "0.0.0.1"
+
+#define PUBLIC_IPV6 "1234::cdef"
+#define INTERNAL_IPV6 "::1"
+
+#define VALID_PORT 0x1234
+
+/* Test the different cases in circuit_extend_lspec_valid_helper(). */
+static void
+test_circuit_extend_lspec_valid(void *arg)
+{
+ (void)arg;
+ extend_cell_t *ec = tor_malloc_zero(sizeof(extend_cell_t));
+ channel_t *p_chan = tor_malloc_zero(sizeof(channel_t));
+ or_circuit_t *or_circ = tor_malloc_zero(sizeof(or_circuit_t));
+ circuit_t *circ = TO_CIRCUIT(or_circ);
+
+ or_options_t *fake_options = options_new();
+ MOCK(get_options, mock_get_options);
+ mocked_options = fake_options;
+
+ setup_full_capture_of_logs(LOG_INFO);
+
+#ifndef ALL_BUGS_ARE_FATAL
+ /* Extend cell must be non-NULL */
+ tor_capture_bugs_(1);
+ tt_int_op(circuit_extend_lspec_valid_helper(NULL, circ), OP_EQ, -1);
+ 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,
+ "!(ASSERT_PREDICT_UNLIKELY_(!ec))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+
+ /* Circuit must be non-NULL */
+ tor_capture_bugs_(1);
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, NULL), OP_EQ, -1);
+ 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,
+ "!(ASSERT_PREDICT_UNLIKELY_(!circ))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+
+ /* Extend cell and circuit must be non-NULL */
+ tor_capture_bugs_(1);
+ tt_int_op(circuit_extend_lspec_valid_helper(NULL, NULL), OP_EQ, -1);
+ /* Since we're using IF_BUG_ONCE(), we might not log any bugs */
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_GE, 0);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_LE, 2);
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+#endif /* !defined(ALL_BUGS_ARE_FATAL) */
+
+ /* IPv4 and IPv6 addr and port are all zero, this should fail */
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ expect_log_msg("Client asked me to extend to a zero destination port "
+ "or unspecified address '[scrubbed]'.\n");
+ mock_clean_saved_logs();
+
+ /* Now ask for the actual address in the logs */
+ fake_options->SafeLogging_ = SAFELOG_SCRUB_NONE;
+
+ /* IPv4 port is 0, IPv6 addr and port are both zero, this should fail */
+ tor_addr_parse(&ec->orport_ipv4.addr, PUBLIC_IPV4);
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ expect_log_msg("Client asked me to extend to a zero destination port "
+ "or IPv4 address '1.2.3.4:0'.\n");
+ mock_clean_saved_logs();
+ tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET);
+ tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6);
+
+ /* IPv4 addr is 0, IPv6 addr and port are both zero, this should fail */
+ ec->orport_ipv4.port = VALID_PORT;
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ expect_log_msg("Client asked me to extend to a zero destination port "
+ "or IPv4 address '0.0.0.0:4660'.\n");
+ mock_clean_saved_logs();
+ ec->orport_ipv4.port = 0;
+ tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET);
+ tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6);
+
+ /* IPv4 addr is internal, and port is valid.
+ * (IPv6 addr and port are both zero.)
+ * Result depends on ExtendAllowPrivateAddresses. */
+ tor_addr_parse(&ec->orport_ipv4.addr, INTERNAL_IPV4);
+ ec->orport_ipv4.port = VALID_PORT;
+
+ fake_options->ExtendAllowPrivateAddresses = 0;
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ expect_log_msg("Client asked me to extend "
+ "to a private IPv4 address '0.0.0.1'.\n");
+ mock_clean_saved_logs();
+ fake_options->ExtendAllowPrivateAddresses = 0;
+ tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET);
+ tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6);
+
+ /* Now do the same tests, but for IPv6 */
+
+ /* IPv6 port is 0, IPv4 addr and port are both zero, this should fail */
+ tor_addr_parse(&ec->orport_ipv6.addr, PUBLIC_IPV6);
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ expect_log_msg("Client asked me to extend to a zero destination port "
+ "or IPv6 address '[1234::cdef]:0'.\n");
+ mock_clean_saved_logs();
+ tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET);
+ tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6);
+
+ /* IPv6 addr is 0, IPv4 addr and port are both zero, this should fail */
+ ec->orport_ipv6.port = VALID_PORT;
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ expect_log_msg("Client asked me to extend to a zero destination port "
+ "or IPv6 address '[::]:4660'.\n");
+ mock_clean_saved_logs();
+ ec->orport_ipv4.port = 0;
+ tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET);
+ tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6);
+
+ /* IPv6 addr is internal, and port is valid.
+ * (IPv4 addr and port are both zero.)
+ * Result depends on ExtendAllowPrivateAddresses. */
+ tor_addr_parse(&ec->orport_ipv6.addr, INTERNAL_IPV6);
+ ec->orport_ipv6.port = VALID_PORT;
+
+ fake_options->ExtendAllowPrivateAddresses = 0;
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ expect_log_msg("Client asked me to extend "
+ "to a private IPv6 address '[::1]'.\n");
+ mock_clean_saved_logs();
+ fake_options->ExtendAllowPrivateAddresses = 0;
+ tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET);
+ tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6);
+
+ /* Both addresses are internal.
+ * Result depends on ExtendAllowPrivateAddresses. */
+ tor_addr_parse(&ec->orport_ipv4.addr, INTERNAL_IPV4);
+ ec->orport_ipv4.port = VALID_PORT;
+ tor_addr_parse(&ec->orport_ipv6.addr, INTERNAL_IPV6);
+ ec->orport_ipv6.port = VALID_PORT;
+
+ fake_options->ExtendAllowPrivateAddresses = 0;
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ expect_log_msg("Client asked me to extend "
+ "to a private IPv4 address '0.0.0.1'.\n");
+ expect_log_msg("Client asked me to extend "
+ "to a private IPv6 address '[::1]'.\n");
+ mock_clean_saved_logs();
+ fake_options->ExtendAllowPrivateAddresses = 0;
+ tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET);
+ tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6);
+
+#ifndef ALL_BUGS_ARE_FATAL
+ /* If we pass the private address check, but don't have the right
+ * OR circuit magic number, we trigger another bug */
+ tor_addr_parse(&ec->orport_ipv4.addr, INTERNAL_IPV4);
+ ec->orport_ipv4.port = VALID_PORT;
+ tor_addr_parse(&ec->orport_ipv6.addr, INTERNAL_IPV6);
+ ec->orport_ipv6.port = VALID_PORT;
+ fake_options->ExtendAllowPrivateAddresses = 1;
+
+ tor_capture_bugs_(1);
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ 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,
+ "!(ASSERT_PREDICT_UNLIKELY_(circ->magic != 0x98ABC04Fu))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+ fake_options->ExtendAllowPrivateAddresses = 0;
+ tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET);
+ tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6);
+
+ /* Fail again, but this time only set an IPv4 address. */
+ tor_addr_parse(&ec->orport_ipv4.addr, INTERNAL_IPV4);
+ ec->orport_ipv4.port = VALID_PORT;
+ fake_options->ExtendAllowPrivateAddresses = 1;
+ tor_capture_bugs_(1);
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ /* Since we're using IF_BUG_ONCE(), expect 0-1 bug logs */
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_GE, 0);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_LE, 1);
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+ fake_options->ExtendAllowPrivateAddresses = 0;
+#endif /* !defined(ALL_BUGS_ARE_FATAL) */
+
+ /* Now set the right magic */
+ or_circ->base_.magic = OR_CIRCUIT_MAGIC;
+
+#ifndef ALL_BUGS_ARE_FATAL
+ /* If we pass the OR circuit magic check, but don't have p_chan,
+ * we trigger another bug */
+ fake_options->ExtendAllowPrivateAddresses = 1;
+ tor_capture_bugs_(1);
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ 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,
+ "!(ASSERT_PREDICT_UNLIKELY_(!p_chan))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+ fake_options->ExtendAllowPrivateAddresses = 0;
+
+ /* We can also pass the OR circuit magic check with a public address */
+ tor_addr_parse(&ec->orport_ipv4.addr, PUBLIC_IPV4);
+ fake_options->ExtendAllowPrivateAddresses = 0;
+ tor_capture_bugs_(1);
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ /* Since we're using IF_BUG_ONCE(), expect 0-1 bug logs */
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_GE, 0);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_LE, 1);
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+ fake_options->ExtendAllowPrivateAddresses = 0;
+
+ tor_addr_make_null(&ec->orport_ipv4.addr, AF_INET);
+ ec->orport_ipv4.port = 0x0000;
+#endif /* !defined(ALL_BUGS_ARE_FATAL) */
+
+ /* Now let's fake a p_chan and the addresses */
+ tor_addr_parse(&ec->orport_ipv4.addr, PUBLIC_IPV4);
+ ec->orport_ipv4.port = VALID_PORT;
+ or_circ->p_chan = p_chan;
+
+ /* This is a trivial failure: node_id and p_chan->identity_digest are both
+ * zeroed */
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ expect_log_msg("Client asked me to extend back to the previous hop.\n");
+ mock_clean_saved_logs();
+
+ /* Let's check with non-zero identities as well */
+ memset(ec->node_id, 0xAA, sizeof(ec->node_id));
+ memset(p_chan->identity_digest, 0xAA, sizeof(p_chan->identity_digest));
+
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ expect_log_msg("Client asked me to extend back to the previous hop.\n");
+ mock_clean_saved_logs();
+
+ memset(ec->node_id, 0, sizeof(ec->node_id));
+ memset(p_chan->identity_digest, 0, sizeof(p_chan->identity_digest));
+
+ /* Let's pass the node_id test */
+ memset(ec->node_id, 0xAA, sizeof(ec->node_id));
+ memset(p_chan->identity_digest, 0xBB, sizeof(p_chan->identity_digest));
+
+ /* ed_pubkey is zero, and that's allowed, so we should succeed */
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, 0);
+ mock_clean_saved_logs();
+
+ /* Now let's check that we warn, but succeed, when only one address is
+ * private */
+ tor_addr_parse(&ec->orport_ipv4.addr, INTERNAL_IPV4);
+ ec->orport_ipv4.port = VALID_PORT;
+ tor_addr_parse(&ec->orport_ipv6.addr, PUBLIC_IPV6);
+ ec->orport_ipv6.port = VALID_PORT;
+ fake_options->ExtendAllowPrivateAddresses = 0;
+
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, 0);
+ expect_log_msg("Client asked me to extend "
+ "to a private IPv4 address '0.0.0.1'.\n");
+ mock_clean_saved_logs();
+ tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET);
+ tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6);
+
+ /* Now with private IPv6 */
+ tor_addr_parse(&ec->orport_ipv4.addr, PUBLIC_IPV4);
+ ec->orport_ipv4.port = VALID_PORT;
+ tor_addr_parse(&ec->orport_ipv6.addr, INTERNAL_IPV6);
+ ec->orport_ipv6.port = VALID_PORT;
+ fake_options->ExtendAllowPrivateAddresses = 0;
+
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, 0);
+ expect_log_msg("Client asked me to extend "
+ "to a private IPv6 address '[::1]'.\n");
+ mock_clean_saved_logs();
+ tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET);
+ tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6);
+
+ /* Now reset to public IPv4 and IPv6 */
+ tor_addr_parse(&ec->orport_ipv4.addr, PUBLIC_IPV4);
+ ec->orport_ipv4.port = VALID_PORT;
+ tor_addr_parse(&ec->orport_ipv6.addr, PUBLIC_IPV6);
+ ec->orport_ipv6.port = VALID_PORT;
+
+ /* Fail on matching non-zero identities */
+ memset(&ec->ed_pubkey, 0xEE, sizeof(ec->ed_pubkey));
+ memset(&p_chan->ed25519_identity, 0xEE, sizeof(p_chan->ed25519_identity));
+
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ expect_log_msg("Client asked me to extend back to the previous hop "
+ "(by Ed25519 ID).\n");
+ mock_clean_saved_logs();
+
+ memset(&ec->ed_pubkey, 0, sizeof(ec->ed_pubkey));
+ memset(&p_chan->ed25519_identity, 0, sizeof(p_chan->ed25519_identity));
+
+ /* Succeed on different, non-zero identities */
+ memset(&ec->ed_pubkey, 0xDD, sizeof(ec->ed_pubkey));
+ memset(&p_chan->ed25519_identity, 0xEE, sizeof(p_chan->ed25519_identity));
+
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, 0);
+ mock_clean_saved_logs();
+
+ memset(&ec->ed_pubkey, 0, sizeof(ec->ed_pubkey));
+ memset(&p_chan->ed25519_identity, 0, sizeof(p_chan->ed25519_identity));
+
+ /* Succeed if the client knows the identity, but we don't */
+ memset(&ec->ed_pubkey, 0xDD, sizeof(ec->ed_pubkey));
+ memset(&p_chan->ed25519_identity, 0x00, sizeof(p_chan->ed25519_identity));
+
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, 0);
+ mock_clean_saved_logs();
+
+ memset(&ec->ed_pubkey, 0, sizeof(ec->ed_pubkey));
+ memset(&p_chan->ed25519_identity, 0, sizeof(p_chan->ed25519_identity));
+
+ /* Succeed if we know the identity, but the client doesn't */
+ memset(&ec->ed_pubkey, 0x00, sizeof(ec->ed_pubkey));
+ memset(&p_chan->ed25519_identity, 0xEE, sizeof(p_chan->ed25519_identity));
+
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, 0);
+ mock_clean_saved_logs();
+
+ memset(&ec->ed_pubkey, 0, sizeof(ec->ed_pubkey));
+ memset(&p_chan->ed25519_identity, 0, sizeof(p_chan->ed25519_identity));
+
+ /* Cleanup the node ids */
+ memset(ec->node_id, 0, sizeof(ec->node_id));
+ memset(p_chan->identity_digest, 0, sizeof(p_chan->identity_digest));
+
+ /* Cleanup the p_chan and the addresses */
+ tor_addr_make_null(&ec->orport_ipv4.addr, AF_UNSPEC);
+ ec->orport_ipv4.port = 0;
+ or_circ->p_chan = NULL;
+
+ done:
+ tor_end_capture_bugs_();
+ teardown_capture_of_logs();
+
+ UNMOCK(get_options);
+ or_options_free(fake_options);
+ mocked_options = NULL;
+
+ tor_free(ec);
+ tor_free(or_circ);
+ tor_free(p_chan);
+}
+
+static bool can_extend_over_ipv6_result = false;
+static int mock_router_can_extend_over_ipv6_calls = 0;
+static bool
+mock_router_can_extend_over_ipv6(const or_options_t *options)
+{
+ (void)options;
+ mock_router_can_extend_over_ipv6_calls++;
+ return can_extend_over_ipv6_result;
+}
+
+/* Test the different cases in circuit_choose_ip_ap_for_extend(). */
+static void
+test_circuit_choose_ip_ap_for_extend(void *arg)
+{
+ (void)arg;
+ tor_addr_port_t ipv4_ap;
+ tor_addr_port_t ipv6_ap;
+
+ /* Set up valid addresses */
+ tor_addr_parse(&ipv4_ap.addr, PUBLIC_IPV4);
+ ipv4_ap.port = VALID_PORT;
+ tor_addr_parse(&ipv6_ap.addr, PUBLIC_IPV6);
+ ipv6_ap.port = VALID_PORT;
+
+ or_options_t *fake_options = options_new();
+ MOCK(get_options, mock_get_options);
+ mocked_options = fake_options;
+
+ MOCK(router_can_extend_over_ipv6,
+ mock_router_can_extend_over_ipv6);
+ can_extend_over_ipv6_result = true;
+ mock_router_can_extend_over_ipv6_calls = 0;
+
+ /* No valid addresses */
+ can_extend_over_ipv6_result = true;
+ mock_router_can_extend_over_ipv6_calls = 0;
+ tt_ptr_op(circuit_choose_ip_ap_for_extend(NULL, NULL), OP_EQ, NULL);
+ tt_int_op(mock_router_can_extend_over_ipv6_calls, OP_EQ, 1);
+
+ can_extend_over_ipv6_result = false;
+ mock_router_can_extend_over_ipv6_calls = 0;
+ tt_ptr_op(circuit_choose_ip_ap_for_extend(NULL, NULL), OP_EQ, NULL);
+ tt_int_op(mock_router_can_extend_over_ipv6_calls, OP_EQ, 1);
+
+ /* One valid address: IPv4 */
+ can_extend_over_ipv6_result = true;
+ mock_router_can_extend_over_ipv6_calls = 0;
+ tt_ptr_op(circuit_choose_ip_ap_for_extend(&ipv4_ap, NULL), OP_EQ, &ipv4_ap);
+ tt_int_op(mock_router_can_extend_over_ipv6_calls, OP_EQ, 1);
+
+ can_extend_over_ipv6_result = false;
+ mock_router_can_extend_over_ipv6_calls = 0;
+ tt_ptr_op(circuit_choose_ip_ap_for_extend(&ipv4_ap, NULL), OP_EQ, &ipv4_ap);
+ tt_int_op(mock_router_can_extend_over_ipv6_calls, OP_EQ, 1);
+
+ /* One valid address: IPv6 */
+ can_extend_over_ipv6_result = true;
+ mock_router_can_extend_over_ipv6_calls = 0;
+ tt_ptr_op(circuit_choose_ip_ap_for_extend(NULL, &ipv6_ap), OP_EQ, &ipv6_ap);
+ tt_int_op(mock_router_can_extend_over_ipv6_calls, OP_EQ, 1);
+
+ can_extend_over_ipv6_result = false;
+ mock_router_can_extend_over_ipv6_calls = 0;
+ tt_ptr_op(circuit_choose_ip_ap_for_extend(NULL, &ipv6_ap), OP_EQ, NULL);
+ tt_int_op(mock_router_can_extend_over_ipv6_calls, OP_EQ, 1);
+
+ /* Two valid addresses */
+ const tor_addr_port_t *chosen_addr = NULL;
+
+ can_extend_over_ipv6_result = true;
+ mock_router_can_extend_over_ipv6_calls = 0;
+ chosen_addr = circuit_choose_ip_ap_for_extend(&ipv4_ap, &ipv6_ap);
+ tt_assert(chosen_addr == &ipv4_ap || chosen_addr == &ipv6_ap);
+ tt_int_op(mock_router_can_extend_over_ipv6_calls, OP_EQ, 1);
+
+ can_extend_over_ipv6_result = false;
+ mock_router_can_extend_over_ipv6_calls = 0;
+ tt_ptr_op(circuit_choose_ip_ap_for_extend(&ipv4_ap, &ipv6_ap),
+ OP_EQ, &ipv4_ap);
+ tt_int_op(mock_router_can_extend_over_ipv6_calls, OP_EQ, 1);
+
+ done:
+ UNMOCK(get_options);
+ or_options_free(fake_options);
+ mocked_options = NULL;
+
+ UNMOCK(router_can_extend_over_ipv6);
+
+ tor_free(fake_options);
+}
+
+static int mock_circuit_close_calls = 0;
+static void
+mock_circuit_mark_for_close_(circuit_t *circ, int reason,
+ int line, const char *cfile)
+{
+ (void)circ;
+ (void)reason;
+ (void)line;
+ (void)cfile;
+ mock_circuit_close_calls++;
+}
+
+static int mock_channel_connect_calls = 0;
+static channel_t *mock_channel_connect_nchan = NULL;
+static channel_t *
+mock_channel_connect_for_circuit(const tor_addr_t *addr,
+ uint16_t port,
+ const char *id_digest,
+ const struct ed25519_public_key_t *ed_id)
+{
+ (void)addr;
+ (void)port;
+ (void)id_digest;
+ (void)ed_id;
+ mock_channel_connect_calls++;
+ return mock_channel_connect_nchan;
+}
+
+/* Test the different cases in circuit_open_connection_for_extend().
+ * Chooses different IP addresses depending on the first character in arg:
+ * - 4: IPv4
+ * - 6: IPv6
+ * - d: IPv4 and IPv6 (dual-stack)
+ */
+static void
+test_circuit_open_connection_for_extend(void *arg)
+{
+ const char ip_version = ((const char *)arg)[0];
+ const bool use_ipv4 = (ip_version == '4' || ip_version == 'd');
+ const bool use_ipv6 = (ip_version == '6' || ip_version == 'd');
+ tor_assert(use_ipv4 || use_ipv6);
+
+ extend_cell_t *ec = tor_malloc_zero(sizeof(extend_cell_t));
+ circuit_t *circ = tor_malloc_zero(sizeof(circuit_t));
+ channel_t *fake_n_chan = tor_malloc_zero(sizeof(channel_t));
+
+ or_options_t *fake_options = options_new();
+ MOCK(get_options, mock_get_options);
+ mocked_options = fake_options;
+
+ MOCK(circuit_mark_for_close_, mock_circuit_mark_for_close_);
+ mock_circuit_close_calls = 0;
+ MOCK(channel_connect_for_circuit, mock_channel_connect_for_circuit);
+ mock_channel_connect_calls = 0;
+ mock_channel_connect_nchan = NULL;
+
+ MOCK(router_can_extend_over_ipv6,
+ mock_router_can_extend_over_ipv6);
+ can_extend_over_ipv6_result = true;
+
+ setup_full_capture_of_logs(LOG_INFO);
+
+#ifndef ALL_BUGS_ARE_FATAL
+ /* Circuit must be non-NULL */
+ mock_circuit_close_calls = 0;
+ mock_channel_connect_calls = 0;
+ tor_capture_bugs_(1);
+ circuit_open_connection_for_extend(ec, NULL, 0);
+ /* We can't close a NULL circuit */
+ tt_int_op(mock_circuit_close_calls, OP_EQ, 0);
+ tt_int_op(mock_channel_connect_calls, OP_EQ, 0);
+ 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,
+ "!(ASSERT_PREDICT_UNLIKELY_(!circ))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+
+ /* Extend cell must be non-NULL */
+ mock_circuit_close_calls = 0;
+ mock_channel_connect_calls = 0;
+ tor_capture_bugs_(1);
+ circuit_open_connection_for_extend(NULL, circ, 0);
+ tt_int_op(mock_circuit_close_calls, OP_EQ, 1);
+ tt_int_op(mock_channel_connect_calls, OP_EQ, 0);
+ 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,
+ "!(ASSERT_PREDICT_UNLIKELY_(!ec))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+
+ /* Extend cell and circuit must be non-NULL */
+ mock_circuit_close_calls = 0;
+ mock_channel_connect_calls = 0;
+ tor_capture_bugs_(1);
+ circuit_open_connection_for_extend(NULL, NULL, 0);
+ /* We can't close a NULL circuit */
+ tt_int_op(mock_circuit_close_calls, OP_EQ, 0);
+ tt_int_op(mock_channel_connect_calls, OP_EQ, 0);
+ /* Since we're using IF_BUG_ONCE(), we might not log any bugs */
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_GE, 0);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_LE, 2);
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+
+ /* Fail, because neither address is valid */
+ mock_circuit_close_calls = 0;
+ mock_channel_connect_calls = 0;
+ tor_capture_bugs_(1);
+ circuit_open_connection_for_extend(ec, circ, 0);
+ /* Close the circuit, don't connect */
+ tt_int_op(mock_circuit_close_calls, OP_EQ, 1);
+ tt_int_op(mock_channel_connect_calls, OP_EQ, 0);
+ /* Check state */
+ tt_ptr_op(circ->n_hop, OP_EQ, NULL);
+ tt_ptr_op(circ->n_chan_create_cell, OP_EQ, NULL);
+ tt_int_op(circ->state, OP_EQ, 0);
+ /* Cleanup */
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+#endif /* !defined(ALL_BUGS_ARE_FATAL) */
+
+ /* Set up valid addresses */
+ if (use_ipv4) {
+ tor_addr_parse(&ec->orport_ipv4.addr, PUBLIC_IPV4);
+ ec->orport_ipv4.port = VALID_PORT;
+ }
+ if (use_ipv6) {
+ tor_addr_parse(&ec->orport_ipv6.addr, PUBLIC_IPV6);
+ ec->orport_ipv6.port = VALID_PORT;
+ }
+
+ /* Succeed, but don't try to open a connection */
+ mock_circuit_close_calls = 0;
+ mock_channel_connect_calls = 0;
+ circuit_open_connection_for_extend(ec, circ, 0);
+ /* If we haven't closed the circuit, that's success */
+ tt_int_op(mock_circuit_close_calls, OP_EQ, 0);
+ tt_int_op(mock_channel_connect_calls, OP_EQ, 0);
+ /* Check state */
+ tt_ptr_op(circ->n_hop, OP_NE, NULL);
+ tt_ptr_op(circ->n_chan_create_cell, OP_NE, NULL);
+ tt_int_op(circ->state, OP_EQ, CIRCUIT_STATE_CHAN_WAIT);
+ /* Cleanup */
+ mock_clean_saved_logs();
+ tor_free(circ->n_hop);
+ tor_free(circ->n_chan_create_cell);
+ circ->state = 0;
+
+ /* Try to open a connection, but fail with a NULL n_chan */
+ mock_circuit_close_calls = 0;
+ mock_channel_connect_calls = 0;
+ circuit_open_connection_for_extend(ec, circ, 1);
+ /* Try to connect, but fail, and close the circuit */
+ tt_int_op(mock_circuit_close_calls, OP_EQ, 1);
+ tt_int_op(mock_channel_connect_calls, OP_EQ, 1);
+ expect_log_msg("Launching n_chan failed. Closing circuit.\n");
+ /* Check state */
+ tt_ptr_op(circ->n_hop, OP_NE, NULL);
+ tt_ptr_op(circ->n_chan_create_cell, OP_NE, NULL);
+ tt_int_op(circ->state, OP_EQ, CIRCUIT_STATE_CHAN_WAIT);
+ /* Cleanup */
+ mock_clean_saved_logs();
+ tor_free(circ->n_hop);
+ tor_free(circ->n_chan_create_cell);
+ circ->state = 0;
+
+ /* Try to open a connection, and succeed, because n_chan is not NULL */
+ mock_channel_connect_nchan = fake_n_chan;
+ mock_circuit_close_calls = 0;
+ mock_channel_connect_calls = 0;
+ circuit_open_connection_for_extend(ec, circ, 1);
+ /* Connection attempt succeeded, leaving the circuit open */
+ tt_int_op(mock_circuit_close_calls, OP_EQ, 0);
+ tt_int_op(mock_channel_connect_calls, OP_EQ, 1);
+ /* Check state */
+ tt_ptr_op(circ->n_hop, OP_NE, NULL);
+ tt_ptr_op(circ->n_chan_create_cell, OP_NE, NULL);
+ tt_int_op(circ->state, OP_EQ, CIRCUIT_STATE_CHAN_WAIT);
+ /* Cleanup */
+ mock_clean_saved_logs();
+ tor_free(circ->n_hop);
+ tor_free(circ->n_chan_create_cell);
+ circ->state = 0;
+ mock_channel_connect_nchan = NULL;
+
+ done:
+ tor_end_capture_bugs_();
+ teardown_capture_of_logs();
+
+ UNMOCK(circuit_mark_for_close_);
+ mock_circuit_close_calls = 0;
+ UNMOCK(channel_connect_for_circuit);
+ mock_channel_connect_calls = 0;
+
+ UNMOCK(get_options);
+ or_options_free(fake_options);
+ mocked_options = NULL;
+
+ UNMOCK(router_can_extend_over_ipv6);
+
+ tor_free(ec);
+ tor_free(circ->n_hop);
+ tor_free(circ->n_chan_create_cell);
+ tor_free(circ);
+ tor_free(fake_n_chan);
+}
+
+/* Guaranteed to be initialised to zero. */
+static extend_cell_t mock_extend_cell_parse_cell_out;
+static int mock_extend_cell_parse_result = 0;
+static int mock_extend_cell_parse_calls = 0;
+
+static int
+mock_extend_cell_parse(extend_cell_t *cell_out,
+ const uint8_t command,
+ const uint8_t *payload_in,
+ size_t payload_len)
+{
+ (void)command;
+ (void)payload_in;
+ (void)payload_len;
+
+ mock_extend_cell_parse_calls++;
+ memcpy(cell_out, &mock_extend_cell_parse_cell_out,
+ sizeof(extend_cell_t));
+ return mock_extend_cell_parse_result;
+}
+
+static int mock_channel_get_for_extend_calls = 0;
+static int mock_channel_get_for_extend_launch_out = 0;
+static channel_t *mock_channel_get_for_extend_nchan = NULL;
+static channel_t *
+mock_channel_get_for_extend(const char *rsa_id_digest,
+ const ed25519_public_key_t *ed_id,
+ const tor_addr_t *target_ipv4_addr,
+ const tor_addr_t *target_ipv6_addr,
+ const char **msg_out,
+ int *launch_out)
+{
+ (void)rsa_id_digest;
+ (void)ed_id;
+ (void)target_ipv4_addr;
+ (void)target_ipv6_addr;
+
+ /* channel_get_for_extend() requires non-NULL arguments */
+ tt_ptr_op(msg_out, OP_NE, NULL);
+ tt_ptr_op(launch_out, OP_NE, NULL);
+
+ mock_channel_get_for_extend_calls++;
+ *msg_out = NULL;
+ *launch_out = mock_channel_get_for_extend_launch_out;
+ return mock_channel_get_for_extend_nchan;
+
+ done:
+ return NULL;
+}
+
+static const char *
+mock_channel_get_canonical_remote_descr(channel_t *chan)
+{
+ (void)chan;
+ return "mock_channel_get_canonical_remote_descr()";
+}
+
+static int mock_circuit_deliver_create_cell_calls = 0;
+static int mock_circuit_deliver_create_cell_result = 0;
+static int
+mock_circuit_deliver_create_cell(circuit_t *circ,
+ const struct create_cell_t *create_cell,
+ int relayed)
+{
+ (void)create_cell;
+
+ /* circuit_deliver_create_cell() requires non-NULL arguments,
+ * but we only check circ and circ->n_chan here. */
+ tt_ptr_op(circ, OP_NE, NULL);
+ tt_ptr_op(circ->n_chan, OP_NE, NULL);
+
+ /* We should only ever get relayed cells from extends */
+ tt_int_op(relayed, OP_EQ, 1);
+
+ mock_circuit_deliver_create_cell_calls++;
+ return mock_circuit_deliver_create_cell_result;
+
+ done:
+ return -1;
+}
+
+/* Test the different cases in circuit_extend(). */
+static void
+test_circuit_extend(void *arg)
+{
+ (void)arg;
+ cell_t *cell = tor_malloc_zero(sizeof(cell_t));
+ channel_t *p_chan = tor_malloc_zero(sizeof(channel_t));
+ or_circuit_t *or_circ = tor_malloc_zero(sizeof(or_circuit_t));
+ circuit_t *circ = TO_CIRCUIT(or_circ);
+ channel_t *fake_n_chan = tor_malloc_zero(sizeof(channel_t));
+
+ server = 0;
+ MOCK(server_mode, mock_server_mode);
+
+ /* Mock a debug function, but otherwise ignore it */
+ MOCK(channel_get_canonical_remote_descr,
+ mock_channel_get_canonical_remote_descr);
+
+ setup_full_capture_of_logs(LOG_INFO);
+
+#ifndef ALL_BUGS_ARE_FATAL
+ /* Circuit must be non-NULL */
+ tor_capture_bugs_(1);
+ tt_int_op(circuit_extend(cell, NULL), OP_EQ, -1);
+ 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,
+ "!(ASSERT_PREDICT_UNLIKELY_(!circ))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+
+ /* Cell must be non-NULL */
+ tor_capture_bugs_(1);
+ tt_int_op(circuit_extend(NULL, circ), OP_EQ, -1);
+ 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,
+ "!(ASSERT_PREDICT_UNLIKELY_(!cell))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+
+ /* Extend cell and circuit must be non-NULL */
+ tor_capture_bugs_(1);
+ tt_int_op(circuit_extend(NULL, NULL), OP_EQ, -1);
+ /* Since we're using IF_BUG_ONCE(), we might not log any bugs */
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_GE, 0);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_LE, 2);
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+#endif /* !defined(ALL_BUGS_ARE_FATAL) */
+
+ /* Clients can't extend */
+ server = 0;
+ tt_int_op(circuit_extend(cell, circ), OP_EQ, -1);
+ expect_log_msg("Got an extend cell, but running as a client. Closing.\n");
+ mock_clean_saved_logs();
+
+ /* But servers can. Unpack the cell, but fail parsing. */
+ server = 1;
+ tt_int_op(circuit_extend(cell, circ), OP_EQ, -1);
+ expect_log_msg("Can't parse extend cell. Closing circuit.\n");
+ mock_clean_saved_logs();
+
+ /* Now mock parsing */
+ MOCK(extend_cell_parse, mock_extend_cell_parse);
+
+ /* And make parsing succeed, but fail on adding ed25519 */
+ memset(&mock_extend_cell_parse_cell_out, 0,
+ sizeof(mock_extend_cell_parse_cell_out));
+ mock_extend_cell_parse_result = 0;
+ mock_extend_cell_parse_calls = 0;
+
+ tt_int_op(circuit_extend(cell, circ), OP_EQ, -1);
+ tt_int_op(mock_extend_cell_parse_calls, OP_EQ, 1);
+ expect_log_msg(
+ "Client asked me to extend without specifying an id_digest.\n");
+ mock_clean_saved_logs();
+ mock_extend_cell_parse_calls = 0;
+
+ /* Now add a node_id. Fail the lspec check because IPv4 and port are zero. */
+ memset(&mock_extend_cell_parse_cell_out.node_id, 0xAA,
+ sizeof(mock_extend_cell_parse_cell_out.node_id));
+
+ tt_int_op(circuit_extend(cell, circ), OP_EQ, -1);
+ tt_int_op(mock_extend_cell_parse_calls, OP_EQ, 1);
+ expect_log_msg("Client asked me to extend to a zero destination port "
+ "or unspecified address '[scrubbed]'.\n");
+ mock_clean_saved_logs();
+ mock_extend_cell_parse_calls = 0;
+
+ /* Now add a valid IPv4 and port. Fail the OR circuit magic check. */
+ tor_addr_parse(&mock_extend_cell_parse_cell_out.orport_ipv4.addr,
+ PUBLIC_IPV4);
+ mock_extend_cell_parse_cell_out.orport_ipv4.port = VALID_PORT;
+
+#ifndef ALL_BUGS_ARE_FATAL
+ tor_capture_bugs_(1);
+ tt_int_op(circuit_extend(cell, circ), OP_EQ, -1);
+ tt_int_op(mock_extend_cell_parse_calls, OP_EQ, 1);
+ 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,
+ "!(ASSERT_PREDICT_UNLIKELY_(circ->magic != 0x98ABC04Fu))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+ mock_extend_cell_parse_calls = 0;
+#endif /* !defined(ALL_BUGS_ARE_FATAL) */
+
+ /* Now add the right magic and a p_chan. */
+ or_circ->base_.magic = OR_CIRCUIT_MAGIC;
+ or_circ->p_chan = p_chan;
+
+ /* Mock channel_get_for_extend(), so it doesn't crash. */
+ mock_channel_get_for_extend_calls = 0;
+ MOCK(channel_get_for_extend, mock_channel_get_for_extend);
+
+ /* Test circuit not established, but don't launch another one */
+ mock_channel_get_for_extend_launch_out = 0;
+ mock_channel_get_for_extend_nchan = NULL;
+ tt_int_op(circuit_extend(cell, circ), OP_EQ, 0);
+ tt_int_op(mock_extend_cell_parse_calls, OP_EQ, 1);
+ tt_int_op(mock_channel_get_for_extend_calls, OP_EQ, 1);
+
+ /* cleanup */
+ mock_clean_saved_logs();
+ mock_extend_cell_parse_calls = 0;
+ mock_channel_get_for_extend_calls = 0;
+ /* circ and or_circ are the same object */
+ tor_free(circ->n_hop);
+ tor_free(circ->n_chan_create_cell);
+
+ /* Mock channel_connect_for_circuit(), so we don't crash */
+ mock_channel_connect_calls = 0;
+ MOCK(channel_connect_for_circuit, mock_channel_connect_for_circuit);
+
+ /* Test circuit not established, and successful launch of a channel */
+ mock_channel_get_for_extend_launch_out = 1;
+ mock_channel_get_for_extend_nchan = NULL;
+ mock_channel_connect_nchan = fake_n_chan;
+ tt_int_op(circuit_extend(cell, circ), OP_EQ, 0);
+ tt_int_op(mock_extend_cell_parse_calls, OP_EQ, 1);
+ tt_int_op(mock_channel_get_for_extend_calls, OP_EQ, 1);
+ tt_int_op(mock_channel_connect_calls, OP_EQ, 1);
+
+ /* cleanup */
+ mock_clean_saved_logs();
+ mock_extend_cell_parse_calls = 0;
+ mock_channel_get_for_extend_calls = 0;
+ mock_channel_connect_calls = 0;
+ /* circ and or_circ are the same object */
+ tor_free(circ->n_hop);
+ tor_free(circ->n_chan_create_cell);
+
+ /* Mock circuit_deliver_create_cell(), so it doesn't crash */
+ mock_circuit_deliver_create_cell_calls = 0;
+ MOCK(circuit_deliver_create_cell, mock_circuit_deliver_create_cell);
+
+ /* Test circuit established, re-using channel, successful delivery */
+ mock_channel_get_for_extend_launch_out = 0;
+ mock_channel_get_for_extend_nchan = fake_n_chan;
+ mock_channel_connect_nchan = NULL;
+ mock_circuit_deliver_create_cell_result = 0;
+ tt_int_op(circuit_extend(cell, circ), OP_EQ, 0);
+ tt_int_op(mock_extend_cell_parse_calls, OP_EQ, 1);
+ tt_int_op(mock_channel_get_for_extend_calls, OP_EQ, 1);
+ tt_int_op(mock_channel_connect_calls, OP_EQ, 0);
+ tt_int_op(mock_circuit_deliver_create_cell_calls, OP_EQ, 1);
+ tt_ptr_op(circ->n_chan, OP_EQ, fake_n_chan);
+
+ /* cleanup */
+ circ->n_chan = NULL;
+ mock_clean_saved_logs();
+ mock_extend_cell_parse_calls = 0;
+ mock_channel_get_for_extend_calls = 0;
+ mock_channel_connect_calls = 0;
+ mock_circuit_deliver_create_cell_calls = 0;
+ /* circ and or_circ are the same object */
+ tor_free(circ->n_hop);
+ tor_free(circ->n_chan_create_cell);
+
+ /* Test circuit established, re-using channel, failed delivery */
+ mock_channel_get_for_extend_launch_out = 0;
+ mock_channel_get_for_extend_nchan = fake_n_chan;
+ mock_channel_connect_nchan = NULL;
+ mock_circuit_deliver_create_cell_result = -1;
+ tt_int_op(circuit_extend(cell, circ), OP_EQ, -1);
+ tt_int_op(mock_extend_cell_parse_calls, OP_EQ, 1);
+ tt_int_op(mock_channel_get_for_extend_calls, OP_EQ, 1);
+ tt_int_op(mock_channel_connect_calls, OP_EQ, 0);
+ tt_int_op(mock_circuit_deliver_create_cell_calls, OP_EQ, 1);
+ tt_ptr_op(circ->n_chan, OP_EQ, fake_n_chan);
+
+ /* cleanup */
+ circ->n_chan = NULL;
+ mock_clean_saved_logs();
+ mock_extend_cell_parse_calls = 0;
+ mock_channel_get_for_extend_calls = 0;
+ mock_channel_connect_calls = 0;
+ mock_circuit_deliver_create_cell_calls = 0;
+ /* circ and or_circ are the same object */
+ tor_free(circ->n_hop);
+ tor_free(circ->n_chan_create_cell);
+
+ done:
+ tor_end_capture_bugs_();
+ teardown_capture_of_logs();
+
+ UNMOCK(server_mode);
+ server = 0;
+
+ UNMOCK(channel_get_canonical_remote_descr);
+
+ UNMOCK(extend_cell_parse);
+ memset(&mock_extend_cell_parse_cell_out, 0,
+ sizeof(mock_extend_cell_parse_cell_out));
+ mock_extend_cell_parse_result = 0;
+ mock_extend_cell_parse_calls = 0;
+
+ UNMOCK(channel_get_for_extend);
+ mock_channel_get_for_extend_calls = 0;
+ mock_channel_get_for_extend_launch_out = 0;
+ mock_channel_get_for_extend_nchan = NULL;
+
+ UNMOCK(channel_connect_for_circuit);
+ mock_channel_connect_calls = 0;
+ mock_channel_connect_nchan = NULL;
+
+ UNMOCK(circuit_deliver_create_cell);
+ mock_circuit_deliver_create_cell_calls = 0;
+ mock_circuit_deliver_create_cell_result = 0;
+
+ tor_free(cell);
+ /* circ and or_circ are the same object */
+ tor_free(circ->n_hop);
+ tor_free(circ->n_chan_create_cell);
+ tor_free(or_circ);
+ tor_free(p_chan);
+ tor_free(fake_n_chan);
+}
+
+/* Test the different cases in onionskin_answer(). */
+static void
+test_onionskin_answer(void *arg)
+{
+ (void)arg;
+ created_cell_t *created_cell = tor_malloc_zero(sizeof(created_cell_t));
+ or_circuit_t *or_circ = tor_malloc_zero(sizeof(or_circuit_t));
+ char keys[CPATH_KEY_MATERIAL_LEN] = {0};
+ uint8_t rend_circ_nonce[DIGEST_LEN] = {0};
+
+ setup_full_capture_of_logs(LOG_INFO);
+
+#ifndef ALL_BUGS_ARE_FATAL
+ /* Circuit must be non-NULL */
+ tor_capture_bugs_(1);
+ tt_int_op(onionskin_answer(NULL, created_cell,
+ keys, CPATH_KEY_MATERIAL_LEN,
+ rend_circ_nonce), OP_EQ, -1);
+ 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,
+ "!(ASSERT_PREDICT_UNLIKELY_(!circ))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+
+ /* Created cell must be non-NULL */
+ tor_capture_bugs_(1);
+ tt_int_op(onionskin_answer(or_circ, NULL,
+ keys, CPATH_KEY_MATERIAL_LEN,
+ rend_circ_nonce), OP_EQ, -1);
+ 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,
+ "!(ASSERT_PREDICT_UNLIKELY_(!created_cell))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+
+ /* Keys must be non-NULL */
+ tor_capture_bugs_(1);
+ tt_int_op(onionskin_answer(or_circ, created_cell,
+ NULL, CPATH_KEY_MATERIAL_LEN,
+ rend_circ_nonce), OP_EQ, -1);
+ 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,
+ "!(ASSERT_PREDICT_UNLIKELY_(!keys))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+
+ /* The rend circuit nonce must be non-NULL */
+ tor_capture_bugs_(1);
+ tt_int_op(onionskin_answer(or_circ, created_cell,
+ keys, CPATH_KEY_MATERIAL_LEN,
+ NULL), OP_EQ, -1);
+ 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,
+ "!(ASSERT_PREDICT_UNLIKELY_(!rend_circ_nonce))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+#endif /* !defined(ALL_BUGS_ARE_FATAL) */
+
+ /* Also, the keys length must be CPATH_KEY_MATERIAL_LEN, but we can't catch
+ * asserts in unit tests. */
+
+ /* Fail when formatting the created cell */
+ tt_int_op(onionskin_answer(or_circ, created_cell,
+ keys, CPATH_KEY_MATERIAL_LEN,
+ rend_circ_nonce), OP_EQ, -1);
+ expect_log_msg("couldn't format created cell (type=0, len=0).\n");
+ mock_clean_saved_logs();
+
+ /* TODO: test the rest of onionskin_answer(), see #33860 */
+ /* TODO: mock created_cell_format for the next test */
+
+ done:
+ tor_end_capture_bugs_();
+ teardown_capture_of_logs();
+
+ tor_free(created_cell);
+ tor_free(or_circ);
+}
+
+#define TEST(name, flags, setup, cleanup) \
+ { #name, test_ ## name, flags, setup, cleanup }
+
+#define TEST_NEW_ROUTE_LEN(name, flags) \
+ { #name, test_new_route_len_ ## name, flags, NULL, NULL }
+
+#define TEST_CIRCUIT(name, flags) \
+ { #name, test_circuit_ ## name, flags, NULL, NULL }
+
+#ifndef COCCI
+#define TEST_CIRCUIT_PASSTHROUGH(name, flags, arg) \
+ { #name "/" arg, test_circuit_ ## name, flags, \
+ &passthrough_setup, (void *)(arg) }
+#endif
+
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 },
- { "upgrade_from_guard_wait", test_upgrade_from_guard_wait, TT_FORK,
- &helper_pubsub_setup, NULL },
+ TEST_NEW_ROUTE_LEN(noexit, 0),
+ TEST_NEW_ROUTE_LEN(safe_exit, 0),
+ TEST_NEW_ROUTE_LEN(unsafe_exit, 0),
+ TEST_NEW_ROUTE_LEN(unhandled_exit, 0),
+
+ TEST(upgrade_from_guard_wait, TT_FORK, &helper_pubsub_setup, NULL),
+
+ TEST_CIRCUIT(extend_state_valid, TT_FORK),
+ TEST_CIRCUIT(extend_add_ed25519, TT_FORK),
+ TEST_CIRCUIT(extend_lspec_valid, TT_FORK),
+ TEST_CIRCUIT(choose_ip_ap_for_extend, 0),
+ TEST_CIRCUIT_PASSTHROUGH(open_connection_for_extend, TT_FORK, "4"),
+ TEST_CIRCUIT_PASSTHROUGH(open_connection_for_extend, TT_FORK, "6"),
+ TEST_CIRCUIT_PASSTHROUGH(open_connection_for_extend, TT_FORK, "dual-stack"),
+ TEST_CIRCUIT(extend, TT_FORK),
+
+ TEST(onionskin_answer, TT_FORK, NULL, NULL),
+
END_OF_TESTCASES
};
diff --git a/src/test/test_config.c b/src/test/test_config.c
index 8ea744d4fd..71beb93f67 100644
--- a/src/test/test_config.c
+++ b/src/test/test_config.c
@@ -18,6 +18,7 @@
#include "core/or/circuitmux_ewma.h"
#include "core/or/circuitbuild.h"
#include "app/config/config.h"
+#include "app/config/resolve_addr.h"
#include "feature/relay/relay_config.h"
#include "feature/relay/transport_config.h"
#include "lib/confmgt/confmgt.h"
@@ -42,6 +43,7 @@
#include "core/or/policies.h"
#include "feature/rend/rendclient.h"
#include "feature/rend/rendservice.h"
+#include "feature/relay/relay_find_addr.h"
#include "feature/relay/router.h"
#include "feature/relay/routermode.h"
#include "feature/nodelist/dirlist.h"
@@ -4160,8 +4162,6 @@ test_config_parse_port_config__ports__ports_given(void *data)
/* Test entry port defaults as initialised in port_parse_config */
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.ipv6_traffic, OP_EQ, 1);
- tt_int_op(port_cfg->entry_cfg.prefer_ipv6, OP_EQ, 0);
tt_int_op(port_cfg->entry_cfg.onion_traffic, 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);
diff --git a/src/test/test_connection.c b/src/test/test_connection.c
index 05f7009bf4..b1252864f5 100644
--- a/src/test/test_connection.c
+++ b/src/test/test_connection.c
@@ -968,9 +968,14 @@ test_failed_orconn_tracker(void *arg)
#define CONNECTION_TESTCASE(name, fork, setup) \
{ #name, test_conn_##name, fork, &setup, NULL }
+#define STR(x) #x
/* where arg is an expression (constant, variable, compound expression) */
-#define CONNECTION_TESTCASE_ARG(name, fork, setup, arg) \
- { #name "_" #arg, test_conn_##name, fork, &setup, (void *)arg }
+#define CONNECTION_TESTCASE_ARG(name, fork, setup, arg) \
+ { #name "_" STR(x), \
+ test_conn_##name, \
+ fork, \
+ &setup, \
+ (void *)arg }
#endif /* !defined(COCCI) */
static const unsigned int PROXY_CONNECT_ARG = PROXY_CONNECT;
diff --git a/src/test/test_consdiff.c b/src/test/test_consdiff.c
index e4cfece9c3..242e2f7818 100644
--- a/src/test/test_consdiff.c
+++ b/src/test/test_consdiff.c
@@ -1030,7 +1030,7 @@ test_consdiff_apply_diff(void *arg)
/* 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")
+ expect_single_log_msg_containing("too short");
/* first line doesn't match format-version string. */
smartlist_add_linecpy(diff, area, "foo-bar");
@@ -1038,7 +1038,7 @@ test_consdiff_apply_diff(void *arg)
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")
+ expect_single_log_msg_containing("format is not known");
/* The first word of the second header line is not "hash". */
smartlist_clear(diff);
@@ -1048,7 +1048,7 @@ test_consdiff_apply_diff(void *arg)
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")
+ expect_single_log_msg_containing("does not include the necessary digests");
/* Wrong number of words after "hash". */
smartlist_clear(diff);
@@ -1057,7 +1057,7 @@ test_consdiff_apply_diff(void *arg)
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")
+ expect_single_log_msg_containing("does not include the necessary digests");
/* base16 digests do not have the expected length. */
smartlist_clear(diff);
@@ -1067,7 +1067,7 @@ test_consdiff_apply_diff(void *arg)
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")
+ "incorrect size");
/* base16 digests contain non-base16 characters. */
smartlist_clear(diff);
@@ -1078,7 +1078,7 @@ test_consdiff_apply_diff(void *arg)
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")
+ 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
@@ -1095,7 +1095,7 @@ test_consdiff_apply_diff(void *arg)
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")
+ "number");
/* Base consensus doesn't match its digest as found in the diff. */
smartlist_clear(diff);
diff --git a/src/test/test_crypto_slow.c b/src/test/test_crypto_slow.c
index 56319f2c72..1702427b08 100644
--- a/src/test/test_crypto_slow.c
+++ b/src/test/test_crypto_slow.c
@@ -342,7 +342,7 @@ test_crypto_scrypt_vectors(void *arg)
#endif
/* Test vectors from
- http://tools.ietf.org/html/draft-josefsson-scrypt-kdf-00 section 11.
+ https://tools.ietf.org/html/draft-josefsson-scrypt-kdf-00 section 11.
Note that the names of 'r' and 'N' are switched in that section. Or
possibly in libscrypt.
diff --git a/src/test/test_dir.c b/src/test/test_dir.c
index 3b2ba64d2c..3a0b8237cb 100644
--- a/src/test/test_dir.c
+++ b/src/test/test_dir.c
@@ -47,7 +47,7 @@
#include "feature/dirclient/dlstatus.h"
#include "feature/dircommon/directory.h"
#include "feature/dircommon/fp_pair.h"
-#include "feature/dircommon/voting_schedule.h"
+#include "feature/dirauth/voting_schedule.h"
#include "feature/hibernate/hibernate.h"
#include "feature/nodelist/authcert.h"
#include "feature/nodelist/dirlist.h"
@@ -3005,6 +3005,7 @@ test_dir_param_voting_lookup(void *arg)
tt_int_op(99, OP_EQ,
dirvote_get_intermediate_param_value(lst, "abcd", 1000));
+#ifndef ALL_BUGS_ARE_FATAL
/* moomin appears twice. That's a bug. */
tor_capture_bugs_(1);
tt_int_op(-100, OP_EQ,
@@ -3022,7 +3023,7 @@ test_dir_param_voting_lookup(void *arg)
dirvote_get_intermediate_param_value(lst, "jack", -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,
- "!(! ok)");
+ "!(!ok)");
tor_end_capture_bugs_();
/* electricity and opa aren't integers. */
tor_capture_bugs_(1);
@@ -3030,7 +3031,7 @@ test_dir_param_voting_lookup(void *arg)
dirvote_get_intermediate_param_value(lst, "electricity", -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,
- "!(! ok)");
+ "!(!ok)");
tor_end_capture_bugs_();
tor_capture_bugs_(1);
@@ -3038,8 +3039,9 @@ test_dir_param_voting_lookup(void *arg)
dirvote_get_intermediate_param_value(lst, "opa", -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,
- "!(! ok)");
+ "!(!ok)");
tor_end_capture_bugs_();
+#endif /* !defined(ALL_BUGS_ARE_FATAL) */
done:
SMARTLIST_FOREACH(lst, char *, cp, tor_free(cp));
@@ -3610,7 +3612,7 @@ test_a_networkstatus(
sign_skey_2 = crypto_pk_new();
sign_skey_3 = crypto_pk_new();
sign_skey_leg1 = pk_generate(4);
- voting_schedule_recalculate_timing(get_options(), now);
+ dirauth_sched_recalculate_timing(get_options(), now);
sr_state_init(0, 0);
tt_assert(!crypto_pk_read_private_key_from_string(sign_skey_1,
@@ -4989,6 +4991,14 @@ test_dir_purpose_needs_anonymity_returns_true_by_default(void *arg)
{
(void)arg;
+#ifdef ALL_BUGS_ARE_FATAL
+ /* Coverity (and maybe clang analyser) complain that the code following
+ * tt_skip() is unconditionally unreachable. */
+#if !defined(__COVERITY__) && !defined(__clang_analyzer__)
+ tt_skip();
+#endif
+#endif /* defined(ALL_BUGS_ARE_FATAL) */
+
tor_capture_bugs_(1);
setup_full_capture_of_logs(LOG_WARN);
tt_int_op(1, OP_EQ, purpose_needs_anonymity(0, 0, NULL));
diff --git a/src/test/test_dir_common.c b/src/test/test_dir_common.c
index 4533ad5c03..f2b4e8724b 100644
--- a/src/test/test_dir_common.c
+++ b/src/test/test_dir_common.c
@@ -13,7 +13,7 @@
#include "feature/dirparse/authcert_parse.h"
#include "feature/dirparse/ns_parse.h"
#include "test/test_dir_common.h"
-#include "feature/dircommon/voting_schedule.h"
+#include "feature/dirauth/voting_schedule.h"
#include "feature/nodelist/authority_cert_st.h"
#include "feature/nodelist/networkstatus_st.h"
diff --git a/src/test/test_dir_handle_get.c b/src/test/test_dir_handle_get.c
index 6293839b0d..f446bbb5eb 100644
--- a/src/test/test_dir_handle_get.c
+++ b/src/test/test_dir_handle_get.c
@@ -38,7 +38,7 @@
#include "feature/dircache/dirserv.h"
#include "feature/dirauth/dirvote.h"
#include "test/log_test_helpers.h"
-#include "feature/dircommon/voting_schedule.h"
+#include "feature/dirauth/voting_schedule.h"
#include "feature/dircommon/dir_connection_st.h"
#include "feature/dirclient/dir_server_st.h"
@@ -2080,12 +2080,12 @@ test_dir_handle_get_status_vote_d(void* data)
mock_options->TestingV3AuthInitialDistDelay = 1;
time_t now = 1441223455 -1;
- voting_schedule_recalculate_timing(mock_options, now);
+ dirauth_sched_recalculate_timing(mock_options, now);
const char *msg_out = NULL;
int status_out = 0;
- struct pending_vote_t *pv = dirvote_add_vote(VOTE_BODY_V3, &msg_out,
- &status_out);
+ struct pending_vote_t *pv = dirvote_add_vote(VOTE_BODY_V3, 0,
+ &msg_out, &status_out);
tt_assert(pv);
status_vote_current_d_test(&header, &body, &body_used);
@@ -2457,10 +2457,10 @@ test_dir_handle_get_status_vote_next_authority(void* data)
mock_options->TestingV3AuthInitialDistDelay = 1;
time_t now = 1441223455 -1;
- voting_schedule_recalculate_timing(mock_options, now);
+ dirauth_sched_recalculate_timing(mock_options, now);
- struct pending_vote_t *vote = dirvote_add_vote(VOTE_BODY_V3, &msg_out,
- &status_out);
+ struct pending_vote_t *vote = dirvote_add_vote(VOTE_BODY_V3, 0,
+ &msg_out, &status_out);
tt_assert(vote);
MOCK(get_my_v3_authority_cert, get_my_v3_authority_cert_m);
@@ -2617,10 +2617,10 @@ test_dir_handle_get_status_vote_current_authority(void* data)
mock_options->TestingV3AuthInitialDistDelay = 1;
time_t now = 1441223455;
- voting_schedule_recalculate_timing(mock_options, now-1);
+ dirauth_sched_recalculate_timing(mock_options, now-1);
- struct pending_vote_t *vote = dirvote_add_vote(VOTE_BODY_V3, &msg_out,
- &status_out);
+ struct pending_vote_t *vote = dirvote_add_vote(VOTE_BODY_V3, 0,
+ &msg_out, &status_out);
tt_assert(vote);
// move the pending vote to previous vote
@@ -2658,6 +2658,183 @@ test_dir_handle_get_status_vote_current_authority(void* data)
dirvote_free_all();
}
+/* Test that a late vote is rejected, but an on-time vote is accepted. */
+static void
+test_dir_handle_get_status_vote_too_late(void* data)
+{
+ dir_connection_t *conn = NULL;
+ char *header = NULL, *body = NULL;
+ const char *msg_out = NULL;
+ int status_out = 0;
+ size_t body_used = 0;
+ const char digest[DIGEST_LEN] = "";
+
+ dir_server_t *ds = NULL;
+ const char* mode = (const char *)data;
+
+ clear_dir_servers();
+ routerlist_free_all();
+ dirvote_free_all();
+
+ mock_cert = authority_cert_parse_from_string(TEST_CERTIFICATE,
+ strlen(TEST_CERTIFICATE),
+ NULL);
+
+ /* create a trusted ds */
+ ds = trusted_dir_server_new("ds", "127.0.0.1", 9059, 9060, NULL, digest,
+ NULL, V3_DIRINFO, 1.0);
+ tt_assert(ds);
+ dir_server_add(ds);
+
+ /* ds v3_identity_digest is the certificate's identity_key */
+ base16_decode(ds->v3_identity_digest, DIGEST_LEN,
+ TEST_CERT_IDENT_KEY, HEX_DIGEST_LEN);
+
+ tt_int_op(0, OP_EQ, trusted_dirs_load_certs_from_string(TEST_CERTIFICATE,
+ TRUSTED_DIRS_CERTS_SRC_DL_BY_ID_DIGEST, 1, NULL));
+
+ init_mock_options();
+ mock_options->AuthoritativeDir = 1;
+ mock_options->V3AuthoritativeDir = 1;
+
+ int base_delay = 0;
+ int vote_interval = 0;
+ int start_offset = 0;
+
+ tt_assert(mode);
+ /* Set the required timings, see below for details */
+ if (strcmp(mode, "min") == 0) {
+ /* The minimum valid test network timing */
+ base_delay = 2;
+ vote_interval = 10;
+ start_offset = vote_interval - 5;
+ } else if (strcmp(mode, "chutney") == 0) {
+ /* The test network timing used by chutney */
+ base_delay = 4;
+ vote_interval = 20;
+ start_offset = vote_interval - 5;
+ } else if (strcmp(mode, "half-public") == 0) {
+ /* The short consensus failure timing used in the public network */
+ base_delay = 5*60;
+ vote_interval = 30*60;
+ start_offset = vote_interval - 9*60 - 5;
+ } else if (strcmp(mode, "public") == 0) {
+ /* The standard timing used in the public network */
+ base_delay = 5*60;
+ vote_interval = 60*60;
+ start_offset = vote_interval - 9*60 - 5;
+ }
+
+ tt_assert(base_delay > 0);
+ tt_assert(vote_interval > 0);
+ tt_assert(start_offset > 0);
+
+ /* Skew the time to fit the fixed time in the vote */
+ mock_options->TestingV3AuthVotingStartOffset = start_offset;
+ /* Calculate the rest of the timings */
+ mock_options->TestingV3AuthInitialVotingInterval = vote_interval;
+ mock_options->TestingV3AuthInitialVoteDelay = base_delay;
+ mock_options->TestingV3AuthInitialDistDelay = base_delay;
+
+ time_t now = 1441223455;
+ dirauth_sched_recalculate_timing(mock_options, now-1);
+ const time_t voting_starts = voting_schedule.voting_starts;
+ const time_t fetch_missing = voting_schedule.fetch_missing_votes;
+
+ struct pending_vote_t *vote = NULL;
+
+ /* Next voting interval */
+ vote = dirvote_add_vote(VOTE_BODY_V3,
+ fetch_missing + vote_interval,
+ &msg_out, &status_out);
+ tt_assert(!vote);
+ tt_int_op(status_out, OP_EQ, 400);
+ tt_str_op(msg_out, OP_EQ,
+ "Posted vote received too late, would be dangerous to count it");
+
+ /* Just after fetch missing */
+ vote = dirvote_add_vote(VOTE_BODY_V3,
+ fetch_missing + 1,
+ &msg_out, &status_out);
+ tt_assert(!vote);
+ tt_int_op(status_out, OP_EQ, 400);
+ tt_str_op(msg_out, OP_EQ,
+ "Posted vote received too late, would be dangerous to count it");
+
+ /* On fetch missing */
+ vote = dirvote_add_vote(VOTE_BODY_V3,
+ fetch_missing,
+ &msg_out, &status_out);
+ tt_assert(vote);
+
+ /* Move the pending vote to previous vote */
+ dirvote_act(mock_options, now+1);
+ /* And reset the timing */
+ dirauth_sched_recalculate_timing(mock_options, now-1);
+
+ /* Between voting starts and fetch missing */
+ vote = dirvote_add_vote(VOTE_BODY_V3,
+ voting_starts + 1,
+ &msg_out, &status_out);
+ tt_assert(vote);
+
+ /* Move the pending vote to previous vote */
+ dirvote_act(mock_options, now+1);
+ /* And reset the timing */
+ dirauth_sched_recalculate_timing(mock_options, now-1);
+
+ /* On voting starts */
+ vote = dirvote_add_vote(VOTE_BODY_V3,
+ voting_starts,
+ &msg_out, &status_out);
+ tt_assert(vote);
+
+ /* Move the pending vote to previous vote */
+ dirvote_act(mock_options, now+1);
+ /* And reset the timing */
+ dirauth_sched_recalculate_timing(mock_options, now-1);
+
+ /* Just before voting starts */
+ vote = dirvote_add_vote(VOTE_BODY_V3,
+ voting_starts - 1,
+ &msg_out, &status_out);
+ tt_assert(vote);
+
+ /* Move the pending vote to previous vote */
+ dirvote_act(mock_options, now+1);
+
+ MOCK(get_my_v3_authority_cert, get_my_v3_authority_cert_m);
+ MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock);
+
+ conn = new_dir_conn();
+ tt_int_op(0, OP_EQ, directory_handle_command_get(conn,
+ GET("/tor/status-vote/current/authority"), NULL, 0));
+
+ fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE,
+ &body, &body_used, strlen(VOTE_BODY_V3)+1, 0);
+
+ tt_assert(header);
+ tt_ptr_op(strstr(header, "HTTP/1.0 200 OK\r\n"), OP_EQ, header);
+ tt_assert(strstr(header, "Content-Type: text/plain\r\n"));
+ tt_assert(strstr(header, "Content-Encoding: identity\r\n"));
+ tt_assert(strstr(header, "Content-Length: 4135\r\n"));
+
+ tt_str_op(VOTE_BODY_V3, OP_EQ, body);
+
+ done:
+ UNMOCK(connection_write_to_buf_impl_);
+ UNMOCK(get_my_v3_authority_cert);
+ connection_free_minimal(TO_CONN(conn));
+ tor_free(header);
+ tor_free(body);
+ authority_cert_free(mock_cert); mock_cert = NULL;
+ or_options_free(mock_options); mock_options = NULL;
+
+ clear_dir_servers();
+ routerlist_free_all();
+ dirvote_free_all();
+}
+
static void
test_dir_handle_get_parse_accept_encoding(void *arg)
{
@@ -2708,6 +2885,16 @@ test_dir_handle_get_parse_accept_encoding(void *arg)
#define DIR_HANDLE_CMD(name,flags) \
{ #name, test_dir_handle_get_##name, (flags), NULL, NULL }
+#ifdef COCCI
+/* Coccinelle doesn't like the stringification in this macro */
+#define DIR_HANDLE_CMD_ARG(name,flags,arg) \
+ DIR_HANDLE_CMD(name,flags)
+#else
+#define DIR_HANDLE_CMD_ARG(name,flags,arg) \
+ { #name "/" arg, test_dir_handle_get_##name, (flags), \
+ &passthrough_setup, (void *)(arg) }
+#endif /* defined(COCCI) */
+
struct testcase_t dir_handle_get_tests[] = {
DIR_HANDLE_CMD(not_found, 0),
DIR_HANDLE_CMD(bad_request, 0),
@@ -2747,6 +2934,10 @@ struct testcase_t dir_handle_get_tests[] = {
DIR_HANDLE_CMD(status_vote_next_not_found, 0),
DIR_HANDLE_CMD(status_vote_current_authority_not_found, 0),
DIR_HANDLE_CMD(status_vote_current_authority, 0),
+ DIR_HANDLE_CMD_ARG(status_vote_too_late, 0, "min"),
+ DIR_HANDLE_CMD_ARG(status_vote_too_late, 0, "chutney"),
+ DIR_HANDLE_CMD_ARG(status_vote_too_late, 0, "half-public"),
+ DIR_HANDLE_CMD_ARG(status_vote_too_late, 0, "public"),
DIR_HANDLE_CMD(status_vote_next_authority_not_found, 0),
DIR_HANDLE_CMD(status_vote_next_authority, 0),
DIR_HANDLE_CMD(status_vote_next_bandwidth_not_found, 0),
diff --git a/src/test/test_dns.c b/src/test/test_dns.c
index ec17e9e91e..299321ab64 100644
--- a/src/test/test_dns.c
+++ b/src/test/test_dns.c
@@ -80,11 +80,11 @@ test_dns_clip_ttl(void *arg)
{
(void)arg;
- uint32_t ttl_mid = MIN_DNS_TTL_AT_EXIT / 2 + MAX_DNS_TTL_AT_EXIT / 2;
+ uint32_t ttl_mid = MIN_DNS_TTL / 2 + MAX_DNS_TTL / 2;
- 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);
+ tt_int_op(clip_dns_ttl(MIN_DNS_TTL - 1),OP_EQ,MIN_DNS_TTL);
+ tt_int_op(clip_dns_ttl(ttl_mid),OP_EQ,MAX_DNS_TTL);
+ tt_int_op(clip_dns_ttl(MAX_DNS_TTL + 1),OP_EQ,MAX_DNS_TTL);
done:
return;
diff --git a/src/test/test_entrynodes.c b/src/test/test_entrynodes.c
index 12b4fcde3c..5ddd1a3db0 100644
--- a/src/test/test_entrynodes.c
+++ b/src/test/test_entrynodes.c
@@ -390,12 +390,13 @@ test_entry_guard_encode_for_state_minimal(void *arg)
eg->confirmed_idx = -1;
char *s = NULL;
- s = entry_guard_encode_for_state(eg);
+ s = entry_guard_encode_for_state(eg, 0);
tt_str_op(s, OP_EQ,
"in=wubwub "
"rsa_id=706C75727079666C75727079736C75727079646F "
"sampled_on=2016-11-14T00:00:00 "
+ "sampled_idx=0 "
"listed=0");
done:
@@ -421,10 +422,11 @@ test_entry_guard_encode_for_state_maximal(void *arg)
eg->currently_listed = 1;
eg->confirmed_on_date = 1479081690;
eg->confirmed_idx = 333;
+ eg->sampled_idx = 42;
eg->extra_state_fields = tor_strdup("and the green grass grew all around");
char *s = NULL;
- s = entry_guard_encode_for_state(eg);
+ s = entry_guard_encode_for_state(eg, 0);
tt_str_op(s, OP_EQ,
"in=default "
@@ -432,6 +434,7 @@ test_entry_guard_encode_for_state_maximal(void *arg)
"bridge_addr=8.8.4.4:9999 "
"nickname=Fred "
"sampled_on=2016-11-14T00:00:00 "
+ "sampled_idx=0 "
"sampled_by=1.2.3 "
"unlisted_since=2016-11-14T00:00:45 "
"listed=1 "
@@ -621,39 +624,47 @@ test_entry_guard_parse_from_state_full(void *arg)
const char STATE[] =
"Guard in=default rsa_id=214F44BD5B638E8C817D47FF7C97397790BF0345 "
"nickname=TotallyNinja sampled_on=2016-11-12T19:32:49 "
+ "sampled_idx=0 "
"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_idx=1 "
"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_idx=2 "
"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_idx=0 "
"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_idx=3 "
"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_idx=10 "
"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_idx=0 "
"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";
+ "sampled_on=2016-11-18T15:07:34 sampled_idx=1 "
+ "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));
@@ -729,35 +740,42 @@ test_entry_guard_parse_from_state_full(void *arg)
tt_str_op(joined, OP_EQ,
"Guard in=default rsa_id=052900AB0EA3ED54BAB84AE8A99E74E8693CE2B2 "
"nickname=5OfNovember sampled_on=2016-11-20T04:32:05 "
+ "sampled_idx=0 "
"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_idx=1 "
"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_idx=2 "
"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_idx=3 "
"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_idx=0 "
"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_idx=0 "
"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");
+ "sampled_on=2016-11-18T15:07:34 sampled_idx=1 "
+ "sampled_by=0.3.0.0-alpha-dev listed=1\n");
done:
config_free_lines(lines);
@@ -1461,8 +1479,8 @@ test_entry_guard_confirming_guards(void *arg)
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, 0), OP_EQ, g1);
+ tt_ptr_op(smartlist_get(gs->confirmed_entry_guards, 1), OP_EQ, g2);
tt_ptr_op(smartlist_get(gs->confirmed_entry_guards, 2), OP_EQ, g3);
/* Now make sure we can regenerate the confirmed_entry_guards list. */
@@ -1474,8 +1492,8 @@ test_entry_guard_confirming_guards(void *arg)
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, 0), OP_EQ, g1);
+ tt_ptr_op(smartlist_get(gs->confirmed_entry_guards, 1), OP_EQ, g2);
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
@@ -1492,9 +1510,9 @@ test_entry_guard_confirming_guards(void *arg)
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_int_op(g1->sampled_idx, OP_EQ, 0);
+ tt_int_op(g2->sampled_idx, OP_EQ, 1);
+ tt_int_op(g3->sampled_idx, OP_EQ, 8);
tt_assert(g1 != g2);
tt_assert(g1 != g3);
tt_assert(g2 != g3);
@@ -1510,9 +1528,6 @@ 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.
@@ -1547,32 +1562,21 @@ test_entry_guard_sample_reachable_filtered(void *arg)
{ SAMPLE_EXCLUDE_PENDING, 0 },
{ -1, -1},
};
-
+ int j;
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;
+ g = first_reachable_filtered_entry_guard(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);
+ const int should_be_set = (pos != excluded_idx &&
+ pos != 3); // filtered out.
+ tt_int_op(1, OP_EQ, should_be_set);
}
done:
guard_selection_free(gs);
- bitarray_free(selected);
}
static void
@@ -1584,7 +1588,7 @@ test_entry_guard_sample_reachable_filtered_empty(void *arg)
SMARTLIST_FOREACH(big_fake_net_nodes, node_t *, n,
n->is_possible_guard = 0);
- entry_guard_t *g = sample_reachable_filtered_entry_guards(gs, NULL, 0);
+ entry_guard_t *g = first_reachable_filtered_entry_guard(gs, NULL, 0);
tt_ptr_op(g, OP_EQ, NULL);
done:
@@ -1675,10 +1679,13 @@ test_entry_guard_manage_primary(void *arg)
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. */
+ /**
+ * If we have one confirmed guard, that guards becomes the first primary
+ * only if its sampled_idx is smaller
+ * */
- /* find a non-primary guard... */
+ /* find a non-primary guard... it should have a sampled_idx higher than
+ * existing primary guards */
entry_guard_t *confirmed = NULL;
SMARTLIST_FOREACH(gs->sampled_entry_guards, entry_guard_t *, g, {
if (! g->is_primary) {
@@ -1694,15 +1701,13 @@ test_entry_guard_manage_primary(void *arg)
smartlist_add_all(prev_guards, gs->primary_entry_guards);
entry_guards_update_primary(gs);
- /* and see what's primary now! */
+ /* the confirmed guard should be at the end of the primary list! Hopefully,
+ * one of the primary guards with a lower sampled_idx will confirm soon :)
+ * Doing this won't make the client switches between primaries depending on
+ * the order of confirming events */
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));
- });
+ tt_ptr_op(smartlist_get(gs->primary_entry_guards,
+ smartlist_len(gs->primary_entry_guards)-1), OP_EQ, confirmed);
{
entry_guard_t *prev_last_guard = smartlist_get(prev_guards, n_primary-1);
tt_assert(! prev_last_guard->is_primary);
@@ -1793,6 +1798,57 @@ test_entry_guard_guard_preferred(void *arg)
}
static void
+test_entry_guard_correct_cascading_order(void *arg)
+{
+ (void)arg;
+ smartlist_t *old_primary_guards = smartlist_new();
+ guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
+ entry_guards_expand_sample(gs);
+ /** First, a test in which the primary guards need be pulled from different
+ * lists to fill up the primary list -- this may happen, if for example, not
+ * enough guards have confirmed yet */
+ entry_guard_t *g;
+ /** just one confirmed */
+ g = smartlist_get(gs->sampled_entry_guards, 2);
+ make_guard_confirmed(gs, g);
+ entry_guards_update_primary(gs);
+ g = smartlist_get(gs->primary_entry_guards, 0);
+ tt_int_op(g->sampled_idx, OP_EQ, 0);
+ g = smartlist_get(gs->primary_entry_guards, 1);
+ tt_int_op(g->sampled_idx, OP_EQ, 1);
+ g = smartlist_get(gs->primary_entry_guards, 2);
+ tt_int_op(g->sampled_idx, OP_EQ, 2);
+
+ /** Now the primaries get all confirmed, and the primary list should not
+ * change */
+ make_guard_confirmed(gs, smartlist_get(gs->primary_entry_guards, 0));
+ make_guard_confirmed(gs, smartlist_get(gs->primary_entry_guards, 1));
+ smartlist_add_all(old_primary_guards, gs->primary_entry_guards);
+ entry_guards_update_primary(gs);
+ smartlist_ptrs_eq(gs->primary_entry_guards, old_primary_guards);
+ /** the confirmed guards should also have the same set of guards, in the same
+ * order :-) */
+ smartlist_ptrs_eq(gs->confirmed_entry_guards, gs->primary_entry_guards);
+ /** Now select a guard for a circuit, and make sure it is the first primary
+ * guard */
+ unsigned state = 9999;
+ 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));
+ /** Now, let's mark this guard as unreachable and let's update the lists */
+ g->is_reachable = GUARD_REACHABLE_NO;
+ g->failing_since = approx_time() - 10;
+ g->last_tried_to_connect = approx_time() - 10;
+ state = 9999;
+ entry_guards_update_primary(gs);
+ g = select_entry_guard_for_circuit(gs, GUARD_USAGE_TRAFFIC, NULL, &state);
+ /** we should have switched to the next one is sampled order */
+ tt_int_op(g->sampled_idx, OP_EQ, 1);
+ done:
+ smartlist_free(old_primary_guards);
+ guard_selection_free(gs);
+}
+
+static void
test_entry_guard_select_for_circuit_no_confirmed(void *arg)
{
/* Simpler cases: no gaurds are confirmed yet. */
@@ -3094,6 +3150,7 @@ struct testcase_t entrynodes_tests[] = {
BFN_TEST(sample_reachable_filtered_empty),
BFN_TEST(retry_unreachable),
BFN_TEST(manage_primary),
+ BFN_TEST(correct_cascading_order),
EN_TEST_FORK(guard_preferred),
diff --git a/src/test/test_hs_cache.c b/src/test/test_hs_cache.c
index a1df2b0eea..df96b2c791 100644
--- a/src/test/test_hs_cache.c
+++ b/src/test/test_hs_cache.c
@@ -370,7 +370,7 @@ test_hsdir_revision_counter_check(void *arg)
hs_descriptor_t *published_desc = NULL;
char *published_desc_str = NULL;
- uint8_t subcredential[DIGEST256_LEN];
+ hs_subcredential_t subcredential;
char *received_desc_str = NULL;
hs_descriptor_t *received_desc = NULL;
@@ -407,11 +407,11 @@ test_hsdir_revision_counter_check(void *arg)
const ed25519_public_key_t *blinded_key;
blinded_key = &published_desc->plaintext_data.blinded_pubkey;
- hs_get_subcredential(&signing_kp.pubkey, blinded_key, subcredential);
+ 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, NULL, &received_desc);
+ &subcredential, NULL, &received_desc);
tt_int_op(retval, OP_EQ, HS_DESC_DECODE_OK);
tt_assert(received_desc);
@@ -444,7 +444,7 @@ test_hsdir_revision_counter_check(void *arg)
received_desc_str = helper_fetch_desc_from_hsdir(blinded_key);
retval = hs_desc_decode_descriptor(received_desc_str,
- subcredential, NULL, &received_desc);
+ &subcredential, NULL, &received_desc);
tt_int_op(retval, OP_EQ, HS_DESC_DECODE_OK);
tt_assert(received_desc);
@@ -477,7 +477,7 @@ test_client_cache(void *arg)
ed25519_keypair_t signing_kp;
hs_descriptor_t *published_desc = NULL;
char *published_desc_str = NULL;
- uint8_t wanted_subcredential[DIGEST256_LEN];
+ hs_subcredential_t wanted_subcredential;
response_handler_args_t *args = NULL;
dir_connection_t *conn = NULL;
@@ -506,8 +506,10 @@ test_client_cache(void *arg)
retval = hs_desc_encode_descriptor(published_desc, &signing_kp,
NULL, &published_desc_str);
tt_int_op(retval, OP_EQ, 0);
- memcpy(wanted_subcredential, published_desc->subcredential, DIGEST256_LEN);
- tt_assert(!fast_mem_is_zero((char*)wanted_subcredential, DIGEST256_LEN));
+ memcpy(&wanted_subcredential, &published_desc->subcredential,
+ sizeof(hs_subcredential_t));
+ tt_assert(!fast_mem_is_zero((char*)wanted_subcredential.subcred,
+ DIGEST256_LEN));
}
/* Test handle_response_fetch_hsdesc_v3() */
@@ -541,8 +543,9 @@ test_client_cache(void *arg)
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);
+ tt_mem_op(cached_desc->subcredential.subcred,
+ OP_EQ, wanted_subcredential.subcred,
+ SUBCRED_LEN);
}
/* Progress time to next TP and check that desc was cleaned */
diff --git a/src/test/test_hs_client.c b/src/test/test_hs_client.c
index e797fdedd0..0cd7d81eea 100644
--- a/src/test/test_hs_client.c
+++ b/src/test/test_hs_client.c
@@ -435,9 +435,10 @@ test_client_pick_intro(void *arg)
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(!fast_mem_is_zero((char*)fetched_desc->subcredential,
+ tt_mem_op(fetched_desc->subcredential.subcred,
+ OP_EQ, desc->subcredential.subcred,
+ SUBCRED_LEN);
+ tt_assert(!fast_mem_is_zero((char*)fetched_desc->subcredential.subcred,
DIGEST256_LEN));
tor_free(encoded);
}
@@ -1194,7 +1195,11 @@ static void
test_socks_hs_errors(void *arg)
{
int ret;
+ char digest[DIGEST_LEN];
char *desc_encoded = NULL;
+ circuit_t *circ = NULL;
+ origin_circuit_t *ocirc = NULL;
+ tor_addr_t addr;
ed25519_keypair_t service_kp;
ed25519_keypair_t signing_kp;
entry_connection_t *socks_conn = NULL;
@@ -1241,6 +1246,73 @@ test_socks_hs_errors(void *arg)
desc = hs_helper_build_hs_desc_with_ip(&service_kp);
tt_assert(desc);
+ /* Before testing the client authentication error code, encode the
+ * descriptor with no client auth. */
+ ret = hs_desc_encode_descriptor(desc, &service_kp, NULL, &desc_encoded);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_assert(desc_encoded);
+
+ /*
+ * Test the introduction failure codes (X'F2' and X'F7')
+ */
+
+ /* First, we have to put all the IPs in the failure cache. */
+ SMARTLIST_FOREACH_BEGIN(desc->encrypted_data.intro_points,
+ hs_desc_intro_point_t *, ip) {
+ hs_cache_client_intro_state_note(&service_kp.pubkey,
+ &ip->auth_key_cert->signed_key,
+ INTRO_POINT_FAILURE_GENERIC);
+ } SMARTLIST_FOREACH_END(ip);
+
+ hs_client_dir_fetch_done(dir_conn, "Reason", desc_encoded, 200);
+ tt_int_op(socks_conn->socks_request->socks_extended_error_code, OP_EQ,
+ SOCKS5_HS_INTRO_FAILED);
+
+ /* Purge client cache of the descriptor so we can go again. */
+ hs_cache_purge_as_client();
+
+ /* Second, set all failures to be time outs. */
+ SMARTLIST_FOREACH_BEGIN(desc->encrypted_data.intro_points,
+ hs_desc_intro_point_t *, ip) {
+ hs_cache_client_intro_state_note(&service_kp.pubkey,
+ &ip->auth_key_cert->signed_key,
+ INTRO_POINT_FAILURE_TIMEOUT);
+ } SMARTLIST_FOREACH_END(ip);
+
+ hs_client_dir_fetch_done(dir_conn, "Reason", desc_encoded, 200);
+ tt_int_op(socks_conn->socks_request->socks_extended_error_code, OP_EQ,
+ SOCKS5_HS_INTRO_TIMEDOUT);
+
+ /* Purge client cache of the descriptor so we can go again. */
+ hs_cache_purge_as_client();
+
+ /*
+ * Test the rendezvous failure codes (X'F3')
+ */
+
+ circ = dummy_origin_circuit_new(0);
+ tt_assert(circ);
+ circ->purpose = CIRCUIT_PURPOSE_C_REND_READY;
+ ocirc = TO_ORIGIN_CIRCUIT(circ);
+ ocirc->hs_ident = hs_ident_circuit_new(&service_kp.pubkey);
+ ocirc->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
+ /* Code path will log this exit so build it. */
+ ocirc->build_state->chosen_exit = extend_info_new("TestNickname", digest,
+ NULL, NULL, NULL, &addr,
+ 4242);
+ /* Attach socks connection to this rendezvous circuit. */
+ ocirc->p_streams = ENTRY_TO_EDGE_CONN(socks_conn);
+ /* Trigger the rendezvous failure. Timeout the circuit and free. */
+ circuit_mark_for_close(circ, END_CIRC_REASON_TIMEOUT);
+
+ tt_int_op(socks_conn->socks_request->socks_extended_error_code, OP_EQ,
+ SOCKS5_HS_REND_FAILED);
+
+ /*
+ * Test client authorization codes.
+ */
+
+ tor_free(desc_encoded);
crypto_rand((char *) descriptor_cookie, sizeof(descriptor_cookie));
ret = hs_desc_encode_descriptor(desc, &service_kp, descriptor_cookie,
&desc_encoded);
@@ -1282,6 +1354,7 @@ test_socks_hs_errors(void *arg)
connection_free_minimal(TO_CONN(dir_conn));
hs_descriptor_free(desc);
tor_free(desc_encoded);
+ circuit_free(circ);
hs_free_all();
diff --git a/src/test/test_hs_common.c b/src/test/test_hs_common.c
index 6f5f21f49a..e3d130fb32 100644
--- a/src/test/test_hs_common.c
+++ b/src/test/test_hs_common.c
@@ -32,7 +32,7 @@
#include "app/config/statefile.h"
#include "core/or/circuitlist.h"
#include "feature/dirauth/shared_random.h"
-#include "feature/dircommon/voting_schedule.h"
+#include "feature/dirauth/voting_schedule.h"
#include "feature/nodelist/microdesc_st.h"
#include "feature/nodelist/networkstatus_st.h"
@@ -53,14 +53,14 @@ test_validate_address(void *arg)
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");
+ expect_log_msg_containing("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");
+ expect_log_msg_containing("Invalid length");
teardown_capture_of_logs();
/* Invalid checksum (taken from prop224) */
@@ -83,7 +83,7 @@ test_validate_address(void *arg)
ret = hs_address_is_valid(
"????????????????????????????????????????????????????????");
tt_int_op(ret, OP_EQ, 0);
- expect_log_msg_containing("can't be decoded");
+ expect_log_msg_containing("Unable to base32 decode");
teardown_capture_of_logs();
/* Valid address. */
@@ -799,6 +799,8 @@ test_parse_extended_hostname(void *arg)
"www.25njqamcweflpvkl73j4szahhihoc4xt3ktcgjnpaingr5yhkenl5sid.onion";
char address9[] =
"www.15njqamcweflpvkl73j4szahhihoc4xt3ktcgjnpaingr5yhkenl5sid.onion";
+ char address10[] =
+ "15njqamcweflpvkl73j4szahhihoc4xt3ktcgjnpaingr5yhkenl5sid7jdl.onion";
tt_assert(!parse_extended_hostname(address1, &type));
tt_int_op(type, OP_EQ, BAD_HOSTNAME);
@@ -831,7 +833,11 @@ test_parse_extended_hostname(void *arg)
/* Invalid v3 address. */
tt_assert(!parse_extended_hostname(address9, &type));
- tt_int_op(type, OP_EQ, ONION_V3_HOSTNAME);
+ tt_int_op(type, OP_EQ, BAD_HOSTNAME);
+
+ /* Invalid v3 address: too long */
+ tt_assert(!parse_extended_hostname(address10, &type));
+ tt_int_op(type, OP_EQ, BAD_HOSTNAME);
done: ;
}
@@ -860,7 +866,7 @@ test_time_between_tp_and_srv(void *arg)
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);
- voting_schedule_recalculate_timing(get_options(), ns.valid_after);
+ dirauth_sched_recalculate_timing(get_options(), ns.valid_after);
ret = hs_in_period_between_tp_and_srv(&ns, 0);
tt_int_op(ret, OP_EQ, 0);
@@ -868,7 +874,7 @@ test_time_between_tp_and_srv(void *arg)
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);
- voting_schedule_recalculate_timing(get_options(), ns.valid_after);
+ dirauth_sched_recalculate_timing(get_options(), ns.valid_after);
ret = hs_in_period_between_tp_and_srv(&ns, 0);
tt_int_op(ret, OP_EQ, 0);
@@ -876,7 +882,7 @@ test_time_between_tp_and_srv(void *arg)
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);
- voting_schedule_recalculate_timing(get_options(), ns.valid_after);
+ dirauth_sched_recalculate_timing(get_options(), ns.valid_after);
ret = hs_in_period_between_tp_and_srv(&ns, 0);
tt_int_op(ret, OP_EQ, 1);
@@ -884,7 +890,7 @@ test_time_between_tp_and_srv(void *arg)
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);
- voting_schedule_recalculate_timing(get_options(), ns.valid_after);
+ dirauth_sched_recalculate_timing(get_options(), ns.valid_after);
ret = hs_in_period_between_tp_and_srv(&ns, 0);
tt_int_op(ret, OP_EQ, 1);
@@ -892,7 +898,7 @@ test_time_between_tp_and_srv(void *arg)
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);
- voting_schedule_recalculate_timing(get_options(), ns.valid_after);
+ dirauth_sched_recalculate_timing(get_options(), ns.valid_after);
ret = hs_in_period_between_tp_and_srv(&ns, 0);
tt_int_op(ret, OP_EQ, 0);
@@ -1382,7 +1388,7 @@ run_reachability_scenario(const reachability_cfg_t *cfg, int num_scenario)
&mock_service_ns->valid_until);
set_consensus_times(cfg->service_valid_until,
&mock_service_ns->fresh_until);
- voting_schedule_recalculate_timing(get_options(),
+ dirauth_sched_recalculate_timing(get_options(),
mock_service_ns->valid_after);
/* Check that service is in the right time period point */
tt_int_op(hs_in_period_between_tp_and_srv(mock_service_ns, 0), OP_EQ,
@@ -1395,7 +1401,7 @@ run_reachability_scenario(const reachability_cfg_t *cfg, int num_scenario)
&mock_client_ns->valid_until);
set_consensus_times(cfg->client_valid_until,
&mock_client_ns->fresh_until);
- voting_schedule_recalculate_timing(get_options(),
+ dirauth_sched_recalculate_timing(get_options(),
mock_client_ns->valid_after);
/* Check that client is in the right time period point */
tt_int_op(hs_in_period_between_tp_and_srv(mock_client_ns, 0), OP_EQ,
@@ -1618,7 +1624,7 @@ helper_set_consensus_and_system_time(networkstatus_t *ns, int position)
} else {
tt_assert(0);
}
- voting_schedule_recalculate_timing(get_options(), ns->valid_after);
+ dirauth_sched_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;
diff --git a/src/test/test_hs_config.c b/src/test/test_hs_config.c
index b2537b746b..dc3b598c34 100644
--- a/src/test/test_hs_config.c
+++ b/src/test/test_hs_config.c
@@ -62,8 +62,9 @@ test_invalid_service(void *arg)
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");
+ expect_log_msg_containing("Could not parse "
+ "HiddenServiceAllowUnknownPorts: Unrecognized "
+ "value 2. Allowed values are 0 and 1.");
teardown_capture_of_logs();
}
@@ -76,8 +77,9 @@ test_invalid_service(void *arg)
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");
+ expect_log_msg_containing("Could not parse "
+ "HiddenServiceDirGroupReadable: "
+ "Unrecognized value 2.");
teardown_capture_of_logs();
}
@@ -90,8 +92,9 @@ test_invalid_service(void *arg)
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");
+ expect_log_msg_containing("Could not parse "
+ "HiddenServiceMaxStreamsCloseCircuit: "
+ "Unrecognized value 2");
teardown_capture_of_logs();
}
@@ -228,8 +231,8 @@ test_invalid_service_v2(void *arg)
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");
+ expect_log_msg_containing("HiddenServiceNumIntroductionPoints must "
+ "be between 0 and 10, not 11.");
teardown_capture_of_logs();
}
@@ -243,8 +246,9 @@ test_invalid_service_v2(void *arg)
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");
+ expect_log_msg_containing("Could not parse "
+ "HiddenServiceNumIntroductionPoints: "
+ "Integer -1 is malformed or out of bounds.");
teardown_capture_of_logs();
}
@@ -532,9 +536,10 @@ test_dos_parameters(void *arg)
setup_full_capture_of_logs(LOG_WARN);
ret = helper_config_service(conf, 0);
tt_int_op(ret, OP_EQ, -1);
- expect_log_msg_containing("HiddenServiceEnableIntroDoSRatePerSec must "
- "be between 0 and 2147483647, "
- "not 137438953472");
+ expect_log_msg_containing("Could not parse "
+ "HiddenServiceEnableIntroDoSRatePerSec: "
+ "Integer 137438953472 is malformed or out of "
+ "bounds.");
teardown_capture_of_logs();
}
@@ -551,9 +556,10 @@ test_dos_parameters(void *arg)
setup_full_capture_of_logs(LOG_WARN);
ret = helper_config_service(conf, 0);
tt_int_op(ret, OP_EQ, -1);
- expect_log_msg_containing("HiddenServiceEnableIntroDoSBurstPerSec must "
- "be between 0 and 2147483647, "
- "not 274877906944");
+ expect_log_msg_containing("Could not parse "
+ "HiddenServiceEnableIntroDoSBurstPerSec: "
+ "Integer 274877906944 is malformed or out "
+ "of bounds.");
teardown_capture_of_logs();
}
@@ -588,8 +594,9 @@ test_dos_parameters(void *arg)
setup_full_capture_of_logs(LOG_WARN);
ret = helper_config_service(conf, 0);
tt_int_op(ret, OP_EQ, -1);
- expect_log_msg_containing("HiddenServiceEnableIntroDoSRatePerSec must be "
- "between 0 and 2147483647, not -1");
+ expect_log_msg_containing("Could not parse "
+ "HiddenServiceEnableIntroDoSRatePerSec: "
+ "Integer -1 is malformed or out of bounds.");
teardown_capture_of_logs();
}
diff --git a/src/test/test_hs_control.c b/src/test/test_hs_control.c
index 8ba9f1173c..80bbf547dc 100644
--- a/src/test/test_hs_control.c
+++ b/src/test/test_hs_control.c
@@ -212,7 +212,8 @@ test_hs_control_good_onion_client_auth_add(void *arg)
MOCK(connection_write_to_buf_impl_, connection_write_to_buf_mock);
int retval;
- ed25519_public_key_t service_identity_pk_2fv, service_identity_pk_jt4;
+ ed25519_public_key_t service_identity_pk_2fv, service_identity_pk_jt4,
+ service_identity_pk_jam;
control_connection_t conn;
char *args = NULL;
char *cp1 = NULL;
@@ -238,6 +239,12 @@ test_hs_control_good_onion_client_auth_add(void *arg)
&service_identity_pk_jt4,
NULL, NULL);
tt_int_op(retval, OP_EQ, 0);
+
+ retval = hs_parse_address(
+ "jamie3vkiwibfiwucd6vxijskbhpjdyajmzeor4mc4i7yopvpo4p7cyd",
+ &service_identity_pk_jam,
+ NULL, NULL);
+ tt_int_op(retval, OP_EQ, 0);
}
digest256map_t *client_auths = get_hs_client_auths_map();
@@ -268,10 +275,24 @@ test_hs_control_good_onion_client_auth_add(void *arg)
cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
tt_str_op(cp1, OP_EQ, "250 OK\r\n");
tor_free(cp1);
+ tor_free(args);
+
+ /* Register second service (even with an unrecognized argument) */
+ args = tor_strdup("jamie3vkiwibfiwucd6vxijskbhpjdyajmzeor4mc4i7yopvpo4p7cyd "
+ "x25519:FCV0c0ELDKKDpSFgVIB8Yow8Evj5iD+GoiTtK878NkQ= "
+ "ClientName=MeganNicole ");
+
+ retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /* Check contents */
+ cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
+ tt_str_op(cp1, OP_EQ, "250 OK\r\n");
+ tor_free(cp1);
client_auths = get_hs_client_auths_map();
tt_assert(client_auths);
- tt_uint_op(digest256map_size(client_auths), OP_EQ, 2);
+ tt_uint_op(digest256map_size(client_auths), OP_EQ, 3);
hs_client_service_authorization_t *client_2fv =
digest256map_get(client_auths, service_identity_pk_2fv.pubkey);
@@ -283,6 +304,11 @@ test_hs_control_good_onion_client_auth_add(void *arg)
tt_assert(client_jt4);
tt_int_op(client_jt4->flags, OP_EQ, 0);
+ hs_client_service_authorization_t *client_jam =
+ digest256map_get(client_auths, service_identity_pk_jam.pubkey);
+ tt_assert(client_jam);
+ tt_int_op(client_jam->flags, OP_EQ, 0);
+
/* Now let's VIEW the auth credentials */
tor_free(conn.current_cmd);
conn.current_cmd = tor_strdup("ONION_CLIENT_AUTH_VIEW");
@@ -294,6 +320,9 @@ test_hs_control_good_onion_client_auth_add(void *arg)
#define VIEW_CORRECT_REPLY_NO_ADDR "250-ONION_CLIENT_AUTH_VIEW\r\n" \
"250-CLIENT 2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd " \
"x25519:iJ1tjKCrMAbiFT2bVrCjhbfMDnE1fpaRbIS5ZHKUvEQ=\r\n" \
+ "250-CLIENT jamie3vkiwibfiwucd6vxijskbhpjdyajmzeor4mc4i7yopvpo4p7cyd " \
+ "x25519:FCV0c0ELDKKDpSFgVIB8Yow8Evj5iD+GoiTtK878NkQ= " \
+ "ClientName=MeganNicole\r\n" \
"250-CLIENT jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd " \
"x25519:eIIdIGoSZwI2Q/lSzpf92akGki5I+PZIDz37MA5BhlA=\r\n" \
"250 OK\r\n"
@@ -364,7 +393,19 @@ test_hs_control_good_onion_client_auth_add(void *arg)
/* Now also remove the other one */
tor_free(args);
- args =tor_strdup("2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd");
+ args =
+ tor_strdup("2fvhjskjet3n5syd6yfg5lhvwcs62bojmthr35ko5bllr3iqdb4ctdyd");
+
+ retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
+ tt_int_op(retval, OP_EQ, 0);
+ cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
+ tt_str_op(cp1, OP_EQ, "250 OK\r\n");
+ tor_free(cp1);
+
+ /* Now also remove the other one */
+ tor_free(args);
+ args =
+ tor_strdup("jamie3vkiwibfiwucd6vxijskbhpjdyajmzeor4mc4i7yopvpo4p7cyd");
retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
tt_int_op(retval, OP_EQ, 0);
@@ -393,7 +434,7 @@ test_hs_control_good_onion_client_auth_add(void *arg)
retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
tt_int_op(retval, OP_EQ, 0);
cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
- tt_str_op(cp1, OP_EQ, "512 Invalid v3 addr \"house\"\r\n");
+ tt_str_op(cp1, OP_EQ, "512 Invalid v3 address \"house\"\r\n");
done:
tor_free(args);
diff --git a/src/test/test_hs_descriptor.c b/src/test/test_hs_descriptor.c
index c5077f7143..782b78306c 100644
--- a/src/test/test_hs_descriptor.c
+++ b/src/test/test_hs_descriptor.c
@@ -243,7 +243,7 @@ test_decode_descriptor(void *arg)
hs_descriptor_t *desc = NULL;
hs_descriptor_t *decoded = NULL;
hs_descriptor_t *desc_no_ip = NULL;
- uint8_t subcredential[DIGEST256_LEN];
+ hs_subcredential_t subcredential;
(void) arg;
@@ -252,10 +252,10 @@ test_decode_descriptor(void *arg)
desc = hs_helper_build_hs_desc_with_ip(&signing_kp);
hs_helper_get_subcred_from_identity_keypair(&signing_kp,
- subcredential);
+ &subcredential);
/* Give some bad stuff to the decoding function. */
- ret = hs_desc_decode_descriptor("hladfjlkjadf", subcredential,
+ ret = hs_desc_decode_descriptor("hladfjlkjadf", &subcredential,
NULL, &decoded);
tt_int_op(ret, OP_EQ, HS_DESC_DECODE_PLAINTEXT_ERROR);
@@ -263,7 +263,7 @@ test_decode_descriptor(void *arg)
tt_int_op(ret, OP_EQ, HS_DESC_DECODE_OK);
tt_assert(encoded);
- ret = hs_desc_decode_descriptor(encoded, subcredential, NULL, &decoded);
+ ret = hs_desc_decode_descriptor(encoded, &subcredential, NULL, &decoded);
tt_int_op(ret, OP_EQ, HS_DESC_DECODE_OK);
tt_assert(decoded);
@@ -275,7 +275,7 @@ test_decode_descriptor(void *arg)
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);
+ &subcredential);
desc_no_ip = hs_helper_build_hs_desc_no_ip(&signing_kp_no_ip);
tt_assert(desc_no_ip);
tor_free(encoded);
@@ -284,7 +284,7 @@ test_decode_descriptor(void *arg)
tt_int_op(ret, OP_EQ, 0);
tt_assert(encoded);
hs_descriptor_free(decoded);
- ret = hs_desc_decode_descriptor(encoded, subcredential, NULL, &decoded);
+ ret = hs_desc_decode_descriptor(encoded, &subcredential, NULL, &decoded);
tt_int_op(ret, OP_EQ, HS_DESC_DECODE_OK);
tt_assert(decoded);
}
@@ -308,14 +308,14 @@ test_decode_descriptor(void *arg)
&auth_ephemeral_kp.pubkey, CURVE25519_PUBKEY_LEN);
hs_helper_get_subcred_from_identity_keypair(&signing_kp,
- subcredential);
+ &subcredential);
/* Build and add the auth client to the descriptor. */
clients = desc->superencrypted_data.clients;
if (!clients) {
clients = smartlist_new();
}
- hs_desc_build_authorized_client(subcredential,
+ hs_desc_build_authorized_client(&subcredential,
&client_kp.pubkey,
&auth_ephemeral_kp.seckey,
descriptor_cookie, client);
@@ -337,21 +337,21 @@ test_decode_descriptor(void *arg)
/* If we do not have the client secret key, the decoding must fail. */
hs_descriptor_free(decoded);
- ret = hs_desc_decode_descriptor(encoded, subcredential,
+ ret = hs_desc_decode_descriptor(encoded, &subcredential,
NULL, &decoded);
tt_int_op(ret, OP_EQ, HS_DESC_DECODE_NEED_CLIENT_AUTH);
tt_assert(!decoded);
/* If we have an invalid client secret key, the decoding must fail. */
hs_descriptor_free(decoded);
- ret = hs_desc_decode_descriptor(encoded, subcredential,
+ ret = hs_desc_decode_descriptor(encoded, &subcredential,
&invalid_client_kp.seckey, &decoded);
tt_int_op(ret, OP_EQ, HS_DESC_DECODE_BAD_CLIENT_AUTH);
tt_assert(!decoded);
/* If we have the client secret key, the decoding must succeed and the
* decoded descriptor must be correct. */
- ret = hs_desc_decode_descriptor(encoded, subcredential,
+ ret = hs_desc_decode_descriptor(encoded, &subcredential,
&client_kp.seckey, &decoded);
tt_int_op(ret, OP_EQ, HS_DESC_DECODE_OK);
tt_assert(decoded);
@@ -784,7 +784,7 @@ test_build_authorized_client(void *arg)
"07d087f1d8c68393721f6e70316d3b29";
const char client_pubkey_b16[] =
"8c1298fa6050e372f8598f6deca32e27b0ad457741422c2629ebb132cf7fae37";
- uint8_t subcredential[DIGEST256_LEN];
+ hs_subcredential_t subcredential;
char *mem_op_hex_tmp=NULL;
(void) arg;
@@ -796,7 +796,7 @@ test_build_authorized_client(void *arg)
tt_int_op(ret, OP_EQ, 0);
curve25519_public_key_generate(&client_auth_pk, &client_auth_sk);
- memset(subcredential, 42, sizeof(subcredential));
+ memset(subcredential.subcred, 42, sizeof(subcredential));
desc_client = tor_malloc_zero(sizeof(hs_desc_authorized_client_t));
@@ -817,7 +817,7 @@ test_build_authorized_client(void *arg)
testing_enable_prefilled_rng("\x01", 1);
- hs_desc_build_authorized_client(subcredential,
+ hs_desc_build_authorized_client(&subcredential,
&client_auth_pk, &auth_ephemeral_sk,
descriptor_cookie, desc_client);
diff --git a/src/test/test_hs_intropoint.c b/src/test/test_hs_intropoint.c
index 5337188427..e6b27d7a50 100644
--- a/src/test/test_hs_intropoint.c
+++ b/src/test/test_hs_intropoint.c
@@ -757,12 +757,15 @@ test_introduce1_validation(void *arg)
cell = helper_create_introduce1_cell();
tt_assert(cell);
+#ifndef ALL_BUGS_ARE_FATAL
/* 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);
+#endif /* !defined(ALL_BUGS_ARE_FATAL) */
+
/* 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);
diff --git a/src/test/test_hs_ntor.c b/src/test/test_hs_ntor.c
index 4f98bc85dc..7867740a1a 100644
--- a/src/test/test_hs_ntor.c
+++ b/src/test/test_hs_ntor.c
@@ -23,7 +23,7 @@ test_hs_ntor(void *arg)
{
int retval;
- uint8_t subcredential[DIGEST256_LEN];
+ hs_subcredential_t subcredential;
ed25519_keypair_t service_intro_auth_keypair;
curve25519_keypair_t service_intro_enc_keypair;
@@ -42,7 +42,7 @@ test_hs_ntor(void *arg)
/* Generate fake data for this unittest */
{
/* Generate fake subcredential */
- memset(subcredential, 'Z', DIGEST256_LEN);
+ memset(subcredential.subcred, 'Z', DIGEST256_LEN);
/* service */
curve25519_keypair_generate(&service_intro_enc_keypair, 0);
@@ -57,7 +57,7 @@ test_hs_ntor(void *arg)
hs_ntor_client_get_introduce1_keys(&service_intro_auth_keypair.pubkey,
&service_intro_enc_keypair.pubkey,
&client_ephemeral_enc_keypair,
- subcredential,
+ &subcredential,
&client_hs_ntor_intro_cell_keys);
tt_int_op(retval, OP_EQ, 0);
@@ -66,7 +66,7 @@ test_hs_ntor(void *arg)
hs_ntor_service_get_introduce1_keys(&service_intro_auth_keypair.pubkey,
&service_intro_enc_keypair,
&client_ephemeral_enc_keypair.pubkey,
- subcredential,
+ &subcredential,
&service_hs_ntor_intro_cell_keys);
tt_int_op(retval, OP_EQ, 0);
diff --git a/src/test/test_hs_ntor_cl.c b/src/test/test_hs_ntor_cl.c
index a7cebc6af4..3acd7ef0bc 100644
--- a/src/test/test_hs_ntor_cl.c
+++ b/src/test/test_hs_ntor_cl.c
@@ -53,7 +53,7 @@ client1(int argc, char **argv)
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];
+ hs_subcredential_t subcredential;
/* Output */
hs_ntor_intro_cell_keys_t hs_ntor_intro_cell_keys;
@@ -65,7 +65,7 @@ client1(int argc, char **argv)
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);
+ BASE16(5, subcredential.subcred, DIGEST256_LEN);
/* Generate keypair */
curve25519_public_key_generate(&client_ephemeral_enc_keypair.pubkey,
@@ -74,7 +74,7 @@ client1(int argc, char **argv)
retval = hs_ntor_client_get_introduce1_keys(&intro_auth_pubkey,
&intro_enc_pubkey,
&client_ephemeral_enc_keypair,
- subcredential,
+ &subcredential,
&hs_ntor_intro_cell_keys);
if (retval < 0) {
goto done;
@@ -106,7 +106,7 @@ server1(int argc, char **argv)
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];
+ hs_subcredential_t subcredential;
/* Output */
hs_ntor_intro_cell_keys_t hs_ntor_intro_cell_keys;
@@ -119,7 +119,7 @@ server1(int argc, char **argv)
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);
+ BASE16(5, subcredential.subcred, DIGEST256_LEN);
/* Generate keypair */
curve25519_public_key_generate(&intro_enc_keypair.pubkey,
@@ -130,7 +130,7 @@ server1(int argc, char **argv)
retval = hs_ntor_service_get_introduce1_keys(&intro_auth_pubkey,
&intro_enc_keypair,
&client_ephemeral_enc_pubkey,
- subcredential,
+ &subcredential,
&hs_ntor_intro_cell_keys);
if (retval < 0) {
goto done;
@@ -188,7 +188,7 @@ client2(int argc, char **argv)
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];
+ hs_subcredential_t subcredential;
/* Output */
hs_ntor_rend_cell_keys_t hs_ntor_rend_cell_keys;
@@ -201,7 +201,7 @@ client2(int argc, char **argv)
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);
+ BASE16(6, subcredential.subcred, DIGEST256_LEN);
/* Generate keypair */
curve25519_public_key_generate(&client_ephemeral_enc_keypair.pubkey,
diff --git a/src/test/test_hs_ob.c b/src/test/test_hs_ob.c
new file mode 100644
index 0000000000..7f40187b5f
--- /dev/null
+++ b/src/test/test_hs_ob.c
@@ -0,0 +1,268 @@
+/* Copyright (c) 2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file test_hs_ob.c
+ * \brief Test hidden service onion balance functionality.
+ */
+
+#define CONFIG_PRIVATE
+#define HS_SERVICE_PRIVATE
+#define HS_OB_PRIVATE
+
+#include "test/test.h"
+#include "test/test_helpers.h"
+#include "test/log_test_helpers.h"
+
+#include "app/config/config.h"
+#include "feature/hs/hs_config.h"
+#include "feature/hs/hs_ob.h"
+#include "feature/hs/hs_service.h"
+#include "feature/nodelist/networkstatus.h"
+#include "feature/nodelist/networkstatus_st.h"
+
+static ed25519_keypair_t onion_addr_kp_1;
+static char onion_addr_1[HS_SERVICE_ADDR_LEN_BASE32 + 1];
+
+static ed25519_keypair_t onion_addr_kp_2;
+static char onion_addr_2[HS_SERVICE_ADDR_LEN_BASE32 + 1];
+
+static bool config_is_good = true;
+
+static int
+helper_tor_config(const char *conf)
+{
+ int ret = -1;
+ or_options_t *options = helper_parse_options(conf);
+ tt_assert(options);
+ ret = hs_config_service_all(options, 0);
+ done:
+ or_options_free(options);
+ return ret;
+}
+
+static networkstatus_t mock_ns;
+
+static networkstatus_t *
+mock_networkstatus_get_live_consensus(time_t now)
+{
+ (void) now;
+ return &mock_ns;
+}
+
+static char *
+mock_read_file_to_str(const char *filename, int flags, struct stat *stat_out)
+{
+ char *ret = NULL;
+
+ (void) flags;
+ (void) stat_out;
+
+ if (!strcmp(filename, get_fname("hs3" PATH_SEPARATOR "ob_config"))) {
+ if (config_is_good) {
+ tor_asprintf(&ret, "MasterOnionAddress %s.onion\n"
+ "MasterOnionAddress %s.onion\n",
+ onion_addr_1, onion_addr_2);
+ } else {
+ tor_asprintf(&ret, "MasterOnionAddress JUNKJUNKJUNK.onion\n"
+ "UnknownOption BLAH\n");
+ }
+ goto done;
+ }
+
+ done:
+ return ret;
+}
+
+static void
+test_parse_config_file(void *arg)
+{
+ int ret;
+ char *conf = NULL;
+ const ed25519_public_key_t *pkey;
+
+ (void) arg;
+
+ hs_init();
+
+ MOCK(read_file_to_str, mock_read_file_to_str);
+
+#define fmt_conf \
+ "HiddenServiceDir %s\n" \
+ "HiddenServicePort 22\n" \
+ "HiddenServiceOnionBalanceInstance 1\n"
+ tor_asprintf(&conf, fmt_conf, get_fname("hs3"));
+#undef fmt_conf
+
+ /* Build the OB frontend onion addresses. */
+ ed25519_keypair_generate(&onion_addr_kp_1, 0);
+ hs_build_address(&onion_addr_kp_1.pubkey, HS_VERSION_THREE, onion_addr_1);
+ ed25519_keypair_generate(&onion_addr_kp_2, 0);
+ hs_build_address(&onion_addr_kp_2.pubkey, HS_VERSION_THREE, onion_addr_2);
+
+ ret = helper_tor_config(conf);
+ tor_free(conf);
+ tt_int_op(ret, OP_EQ, 0);
+
+ /* Load the keys for the service. After that, the v3 service should be
+ * registered in the global map and we'll be able to access it. */
+ tt_int_op(get_hs_service_staging_list_size(), OP_EQ, 1);
+ hs_service_load_all_keys();
+ tt_int_op(get_hs_service_map_size(), OP_EQ, 1);
+ const hs_service_t *s = get_first_service();
+ tt_assert(s);
+ tt_assert(s->config.ob_master_pubkeys);
+ tt_assert(hs_ob_service_is_instance(s));
+ tt_assert(smartlist_len(s->config.ob_master_pubkeys) == 2);
+
+ /* Test the public keys we've added. */
+ pkey = smartlist_get(s->config.ob_master_pubkeys, 0);
+ tt_mem_op(&onion_addr_kp_1.pubkey, OP_EQ, pkey, ED25519_PUBKEY_LEN);
+ pkey = smartlist_get(s->config.ob_master_pubkeys, 1);
+ tt_mem_op(&onion_addr_kp_2.pubkey, OP_EQ, pkey, ED25519_PUBKEY_LEN);
+
+ done:
+ hs_free_all();
+
+ UNMOCK(read_file_to_str);
+}
+
+static void
+test_parse_config_file_bad(void *arg)
+{
+ int ret;
+ char *conf = NULL;
+
+ (void) arg;
+
+ hs_init();
+
+ MOCK(read_file_to_str, mock_read_file_to_str);
+
+ /* Indicate mock_read_file_to_str() to use the bad config. */
+ config_is_good = false;
+
+#define fmt_conf \
+ "HiddenServiceDir %s\n" \
+ "HiddenServicePort 22\n" \
+ "HiddenServiceOnionBalanceInstance 1\n"
+ tor_asprintf(&conf, fmt_conf, get_fname("hs3"));
+#undef fmt_conf
+
+ setup_full_capture_of_logs(LOG_INFO);
+ ret = helper_tor_config(conf);
+ tor_free(conf);
+ tt_int_op(ret, OP_EQ, -1);
+ expect_log_msg_containing("OnionBalance: MasterOnionAddress "
+ "JUNKJUNKJUNK.onion is invalid");
+ expect_log_msg_containing("Found unrecognized option \'UnknownOption\'; "
+ "saving it.");
+ teardown_capture_of_logs();
+
+ done:
+ hs_free_all();
+
+ UNMOCK(read_file_to_str);
+}
+
+static void
+test_get_subcredentials(void *arg)
+{
+ int ret;
+ hs_service_t *service = NULL;
+ hs_service_config_t config;
+ hs_subcredential_t *subcreds = NULL;
+
+ (void) arg;
+
+ MOCK(networkstatus_get_live_consensus,
+ mock_networkstatus_get_live_consensus);
+
+ /* Setup consensus with proper time so we can compute the time period. */
+ 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);
+
+ config.ob_master_pubkeys = smartlist_new();
+ tt_assert(config.ob_master_pubkeys);
+
+ /* Set up an instance */
+ service = tor_malloc_zero(sizeof(hs_service_t));
+ service->config = config;
+ /* Setup the service descriptors */
+ service->desc_current = service_descriptor_new();
+ service->desc_next = service_descriptor_new();
+
+ /* First try to compute subcredentials but with no OB keys. Make sure that
+ * subcreds get NULLed. To do this check we first poison subcreds. */
+ subcreds = (void*)999;
+ tt_ptr_op(subcreds, OP_NE, NULL);
+ size_t num = compute_subcredentials(service, &subcreds);
+ tt_ptr_op(subcreds, OP_EQ, NULL);
+
+ /* Generate a keypair to add to the OB keys list. */
+ ed25519_keypair_generate(&onion_addr_kp_1, 0);
+ smartlist_add(config.ob_master_pubkeys, &onion_addr_kp_1.pubkey);
+
+ /* Set up the instance subcredentials */
+ char current_subcred[SUBCRED_LEN];
+ char next_subcred[SUBCRED_LEN];
+ memset(current_subcred, 'C', SUBCRED_LEN);
+ memset(next_subcred, 'N', SUBCRED_LEN);
+ memcpy(service->desc_current->desc->subcredential.subcred, current_subcred,
+ SUBCRED_LEN);
+ memcpy(service->desc_next->desc->subcredential.subcred, next_subcred,
+ SUBCRED_LEN);
+
+ /* See that subcreds are computed properly */
+ num = compute_subcredentials(service, &subcreds);
+ /* 5 subcredentials: 3 for the frontend, 2 for the instance */
+ tt_uint_op(num, OP_EQ, 5);
+ tt_ptr_op(subcreds, OP_NE, NULL);
+
+ /* Validate the subcredentials we just got. We'll build them oursevles with
+ * the right time period steps and compare. */
+ const uint64_t tp = hs_get_time_period_num(0);
+ const int steps[3] = {0, -1, 1};
+
+ unsigned int i;
+ for (i = 0; i < 3; i++) {
+ hs_subcredential_t subcredential;
+ ed25519_public_key_t blinded_pubkey;
+ hs_build_blinded_pubkey(&onion_addr_kp_1.pubkey, NULL, 0, tp + steps[i],
+ &blinded_pubkey);
+ hs_get_subcredential(&onion_addr_kp_1.pubkey, &blinded_pubkey,
+ &subcredential);
+ tt_mem_op(subcreds[i].subcred, OP_EQ, subcredential.subcred,
+ SUBCRED_LEN);
+ }
+
+ tt_mem_op(subcreds[i++].subcred, OP_EQ, current_subcred, SUBCRED_LEN);
+ tt_mem_op(subcreds[i++].subcred, OP_EQ, next_subcred, SUBCRED_LEN);
+
+ done:
+ tor_free(subcreds);
+
+ smartlist_free(config.ob_master_pubkeys);
+ if (service) {
+ memset(&service->config, 0, sizeof(hs_service_config_t));
+ hs_service_free(service);
+ }
+
+ UNMOCK(networkstatus_get_live_consensus);
+}
+
+struct testcase_t hs_ob_tests[] = {
+ { "parse_config_file", test_parse_config_file, TT_FORK,
+ NULL, NULL },
+ { "parse_config_file_bad", test_parse_config_file_bad, TT_FORK,
+ NULL, NULL },
+
+ { "get_subcredentials", test_get_subcredentials, TT_FORK,
+ NULL, NULL },
+
+ END_OF_TESTCASES
+};
diff --git a/src/test/test_hs_service.c b/src/test/test_hs_service.c
index 49c8d29d27..8b94bb6cf1 100644
--- a/src/test/test_hs_service.c
+++ b/src/test/test_hs_service.c
@@ -44,13 +44,15 @@
#include "core/or/versions.h"
#include "feature/dirauth/dirvote.h"
#include "feature/dirauth/shared_random_state.h"
-#include "feature/dircommon/voting_schedule.h"
+#include "feature/dirauth/voting_schedule.h"
#include "feature/hs/hs_circuit.h"
#include "feature/hs/hs_circuitmap.h"
#include "feature/hs/hs_client.h"
#include "feature/hs/hs_common.h"
#include "feature/hs/hs_config.h"
#include "feature/hs/hs_ident.h"
+#include "feature/hs/hs_ob.h"
+#include "feature/hs/hs_cell.h"
#include "feature/hs/hs_intropoint.h"
#include "feature/hs/hs_service.h"
#include "feature/nodelist/networkstatus.h"
@@ -88,6 +90,14 @@ mock_networkstatus_get_reasonably_live_consensus(time_t now, int flavor)
return &mock_ns;
}
+static networkstatus_t *
+mock_networkstatus_get_reasonably_live_consensus_null(time_t now, int flavor)
+{
+ (void) now;
+ (void) flavor;
+ return NULL;
+}
+
static or_state_t *dummy_state = NULL;
/* Mock function to get fake or state (used for rev counters) */
@@ -110,6 +120,9 @@ mock_circuit_mark_for_close(circuit_t *circ, int reason, int line,
return;
}
+static size_t relay_payload_len;
+static char relay_payload[RELAY_PAYLOAD_SIZE];
+
static int
mock_relay_send_command_from_edge(streamid_t stream_id, circuit_t *circ,
uint8_t relay_command, const char *payload,
@@ -125,6 +138,24 @@ mock_relay_send_command_from_edge(streamid_t stream_id, circuit_t *circ,
(void) cpath_layer;
(void) filename;
(void) lineno;
+
+ memcpy(relay_payload, payload, payload_len);
+ relay_payload_len = payload_len;
+
+ return 0;
+}
+
+static unsigned int num_intro_points = 0;
+static unsigned int
+mock_count_desc_circuit_established(const hs_service_descriptor_t *desc)
+{
+ (void) desc;
+ return num_intro_points;
+}
+
+static int
+mock_router_have_minimum_dir_info_false(void)
+{
return 0;
}
@@ -1161,7 +1192,7 @@ test_closing_intro_circs(void *arg)
/** Test sending and receiving introduce2 cells */
static void
-test_introduce2(void *arg)
+test_bad_introduce2(void *arg)
{
int ret;
int flags = CIRCLAUNCH_NEED_UPTIME | CIRCLAUNCH_IS_INTERNAL;
@@ -1357,7 +1388,7 @@ test_rotate_descriptors(void *arg)
ret = parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC",
&mock_ns.fresh_until);
tt_int_op(ret, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), mock_ns.valid_after);
+ dirauth_sched_recalculate_timing(get_options(), mock_ns.valid_after);
update_approx_time(mock_ns.valid_after+1);
now = mock_ns.valid_after+1;
@@ -1398,7 +1429,7 @@ test_rotate_descriptors(void *arg)
ret = parse_rfc1123_time("Sat, 27 Oct 1985 02:00:00 UTC",
&mock_ns.fresh_until);
tt_int_op(ret, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), mock_ns.valid_after);
+ dirauth_sched_recalculate_timing(get_options(), mock_ns.valid_after);
update_approx_time(mock_ns.valid_after+1);
now = mock_ns.valid_after+1;
@@ -1466,7 +1497,7 @@ test_build_update_descriptors(void *arg)
ret = parse_rfc1123_time("Sat, 26 Oct 1985 04:00:00 UTC",
&mock_ns.fresh_until);
tt_int_op(ret, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), mock_ns.valid_after);
+ dirauth_sched_recalculate_timing(get_options(), mock_ns.valid_after);
update_approx_time(mock_ns.valid_after+1);
@@ -1697,7 +1728,7 @@ test_build_descriptors(void *arg)
ret = parse_rfc1123_time("Sat, 26 Oct 1985 04:00:00 UTC",
&mock_ns.fresh_until);
tt_int_op(ret, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), mock_ns.valid_after);
+ dirauth_sched_recalculate_timing(get_options(), mock_ns.valid_after);
/* Generate a valid number of fake auth clients when a client authorization
* is disabled. */
@@ -1798,7 +1829,7 @@ test_upload_descriptors(void *arg)
ret = parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC",
&mock_ns.fresh_until);
tt_int_op(ret, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), mock_ns.valid_after);
+ dirauth_sched_recalculate_timing(get_options(), mock_ns.valid_after);
update_approx_time(mock_ns.valid_after+1);
now = mock_ns.valid_after+1;
@@ -2170,6 +2201,490 @@ test_export_client_circuit_id(void *arg)
tor_free(cp2);
}
+static smartlist_t *
+mock_node_get_link_specifier_smartlist(const node_t *node, bool direct_conn)
+{
+ (void) node;
+ (void) direct_conn;
+
+ smartlist_t *lspecs = smartlist_new();
+ link_specifier_t *ls_legacy = link_specifier_new();
+ smartlist_add(lspecs, ls_legacy);
+
+ return lspecs;
+}
+
+static node_t *fake_node = NULL;
+
+static const node_t *
+mock_build_state_get_exit_node(cpath_build_state_t *state)
+{
+ (void) state;
+
+ if (!fake_node) {
+ curve25519_secret_key_t seckey;
+ curve25519_secret_key_generate(&seckey, 0);
+
+ fake_node = tor_malloc_zero(sizeof(node_t));
+ fake_node->ri = tor_malloc_zero(sizeof(routerinfo_t));
+ fake_node->ri->onion_curve25519_pkey =
+ tor_malloc_zero(sizeof(curve25519_public_key_t));
+ curve25519_public_key_generate(fake_node->ri->onion_curve25519_pkey,
+ &seckey);
+ }
+
+ return fake_node;
+}
+
+static void
+mock_launch_rendezvous_point_circuit(const hs_service_t *service,
+ const hs_service_intro_point_t *ip,
+ const hs_cell_introduce2_data_t *data)
+{
+ (void) service;
+ (void) ip;
+ (void) data;
+ return;
+}
+
+/**
+ * Test that INTRO2 cells are handled well by onion services in the normal
+ * case and also when onionbalance is enabled.
+ */
+static void
+test_intro2_handling(void *arg)
+{
+ (void)arg;
+
+ MOCK(build_state_get_exit_node, mock_build_state_get_exit_node);
+ MOCK(relay_send_command_from_edge_, mock_relay_send_command_from_edge);
+ MOCK(node_get_link_specifier_smartlist,
+ mock_node_get_link_specifier_smartlist);
+ MOCK(launch_rendezvous_point_circuit, mock_launch_rendezvous_point_circuit);
+
+ memset(relay_payload, 0, sizeof(relay_payload));
+
+ int retval;
+ time_t now = 0101010101;
+ update_approx_time(now);
+
+ /** OK this is the play:
+ *
+ * In Act I, we have a standalone onion service X (without onionbalance
+ * enabled). We test that X can properly handle INTRO2 cells sent by a
+ * client Alice.
+ *
+ * In Act II, we create an onionbalance setup with frontend being Z which
+ * includes instances X and Y. We then setup onionbalance on X and test that
+ * Alice who addresses Z can communicate with X through INTRO2 cells.
+ *
+ * In Act III, we test that Alice can also communicate with X
+ * directly even tho onionbalance is enabled.
+ *
+ * And finally in Act IV, we check various cases where the INTRO2 cell
+ * should not go through because the subcredentials don't line up
+ * (e.g. Alice sends INTRO2 to X using Y's subcredential).
+ */
+
+ /** Let's start with some setup! Create the instances and the frontend
+ service, create Alice, etc: */
+
+ /* Create instance X */
+ hs_service_t x_service;
+ memset(&x_service, 0, sizeof(hs_service_t));
+ /* Disable onionbalance */
+ x_service.config.ob_master_pubkeys = NULL;
+ x_service.state.replay_cache_rend_cookie = replaycache_new(0,0);
+
+ /* Create subcredential for x: */
+ ed25519_keypair_t x_identity_keypair;
+ hs_subcredential_t x_subcred;
+ ed25519_keypair_generate(&x_identity_keypair, 0);
+ hs_helper_get_subcred_from_identity_keypair(&x_identity_keypair,
+ &x_subcred);
+
+ /* Create the x instance's intro point */
+ hs_service_intro_point_t *x_ip = NULL;
+ {
+ curve25519_secret_key_t seckey;
+ curve25519_public_key_t pkey;
+ curve25519_secret_key_generate(&seckey, 0);
+ curve25519_public_key_generate(&pkey, &seckey);
+
+ node_t intro_node;
+ memset(&intro_node, 0, sizeof(intro_node));
+ routerinfo_t ri;
+ memset(&ri, 0, sizeof(routerinfo_t));
+ ri.onion_curve25519_pkey = &pkey;
+ intro_node.ri = &ri;
+
+ x_ip = service_intro_point_new(&intro_node);
+ }
+
+ /* Create z frontend's subcredential */
+ ed25519_keypair_t z_identity_keypair;
+ hs_subcredential_t z_subcred;
+ ed25519_keypair_generate(&z_identity_keypair, 0);
+ hs_helper_get_subcred_from_identity_keypair(&z_identity_keypair,
+ &z_subcred);
+
+ /* Create y instance's subcredential */
+ ed25519_keypair_t y_identity_keypair;
+ hs_subcredential_t y_subcred;
+ ed25519_keypair_generate(&y_identity_keypair, 0);
+ hs_helper_get_subcred_from_identity_keypair(&y_identity_keypair,
+ &y_subcred);
+
+ /* Create Alice's intro point */
+ hs_desc_intro_point_t *alice_ip;
+ ed25519_keypair_t signing_kp;
+ ed25519_keypair_generate(&signing_kp, 0);
+ alice_ip = hs_helper_build_intro_point(&signing_kp, now, "1.2.3.4", 0,
+ &x_ip->auth_key_kp,
+ &x_ip->enc_key_kp);
+
+ /* Create Alice's intro and rend circuits */
+ origin_circuit_t *intro_circ = origin_circuit_new();
+ intro_circ->cpath = tor_malloc_zero(sizeof(crypt_path_t));
+ intro_circ->cpath->prev = intro_circ->cpath;
+ intro_circ->hs_ident = tor_malloc_zero(sizeof(*intro_circ->hs_ident));
+ origin_circuit_t rend_circ;
+ rend_circ.hs_ident = tor_malloc_zero(sizeof(*rend_circ.hs_ident));
+ curve25519_keypair_generate(&rend_circ.hs_ident->rendezvous_client_kp, 0);
+ memset(rend_circ.hs_ident->rendezvous_cookie, 'r', HS_REND_COOKIE_LEN);
+
+ /* ************************************************************ */
+
+ /* Act I:
+ *
+ * Where Alice connects to X without onionbalance in the picture */
+
+ /* Create INTRODUCE1 */
+ tt_assert(fast_mem_is_zero(relay_payload, sizeof(relay_payload)));
+ retval = hs_circ_send_introduce1(intro_circ, &rend_circ,
+ alice_ip, &x_subcred);
+
+ /* Check that the payload was written successfully */
+ tt_int_op(retval, OP_EQ, 0);
+ tt_assert(!fast_mem_is_zero(relay_payload, sizeof(relay_payload)));
+ tt_int_op(relay_payload_len, OP_NE, 0);
+
+ /* Handle the cell */
+ retval = hs_circ_handle_introduce2(&x_service,
+ intro_circ, x_ip,
+ &x_subcred,
+ (uint8_t*)relay_payload,relay_payload_len);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /* ************************************************************ */
+
+ /* Act II:
+ *
+ * We now create an onionbalance setup with Z being the frontend and X and Y
+ * being the backend instances. Make sure that Alice can talk with the
+ * backend instance X even tho she thinks she is talking to the frontend Z.
+ */
+
+ /* Now configure the X instance to do onionbalance with Z as the frontend */
+ x_service.config.ob_master_pubkeys = smartlist_new();
+ smartlist_add(x_service.config.ob_master_pubkeys,
+ &z_identity_keypair.pubkey);
+
+ /* Create descriptors for x and load next descriptor with the x's
+ * subcredential so that it can accept connections for itself. */
+ x_service.desc_current = service_descriptor_new();
+ memset(x_service.desc_current->desc->subcredential.subcred, 'C',SUBCRED_LEN);
+ x_service.desc_next = service_descriptor_new();
+ memcpy(&x_service.desc_next->desc->subcredential, &x_subcred, SUBCRED_LEN);
+
+ /* Refresh OB keys */
+ hs_ob_refresh_keys(&x_service);
+
+ /* Create INTRODUCE1 from Alice to X through Z */
+ memset(relay_payload, 0, sizeof(relay_payload));
+ retval = hs_circ_send_introduce1(intro_circ, &rend_circ,
+ alice_ip, &z_subcred);
+
+ /* Check that the payload was written successfully */
+ tt_int_op(retval, OP_EQ, 0);
+ tt_assert(!fast_mem_is_zero(relay_payload, sizeof(relay_payload)));
+ tt_int_op(relay_payload_len, OP_NE, 0);
+
+ /* Deliver INTRODUCE1 to X even tho it carries Z's subcredential */
+ replaycache_free(x_service.state.replay_cache_rend_cookie);
+ x_service.state.replay_cache_rend_cookie = replaycache_new(0, 0);
+
+ retval = hs_circ_handle_introduce2(&x_service,
+ intro_circ, x_ip,
+ &z_subcred,
+ (uint8_t*)relay_payload, relay_payload_len);
+ tt_int_op(retval, OP_EQ, 0);
+
+ replaycache_free(x_ip->replay_cache);
+ x_ip->replay_cache = replaycache_new(0, 0);
+
+ replaycache_free(x_service.state.replay_cache_rend_cookie);
+ x_service.state.replay_cache_rend_cookie = replaycache_new(0, 0);
+
+ /* ************************************************************ */
+
+ /* Act III:
+ *
+ * Now send a direct INTRODUCE cell from Alice to X using X's subcredential
+ * and check that it succeeds even with onionbalance enabled.
+ */
+
+ /* Refresh OB keys (just to check for memleaks) */
+ hs_ob_refresh_keys(&x_service);
+
+ /* Create INTRODUCE1 from Alice to X using X's subcred. */
+ memset(relay_payload, 0, sizeof(relay_payload));
+ retval = hs_circ_send_introduce1(intro_circ, &rend_circ,
+ alice_ip, &x_subcred);
+
+ /* Check that the payload was written successfully */
+ tt_int_op(retval, OP_EQ, 0);
+ tt_assert(!fast_mem_is_zero(relay_payload, sizeof(relay_payload)));
+ tt_int_op(relay_payload_len, OP_NE, 0);
+
+ /* Send INTRODUCE1 to X with X's subcredential (should succeed) */
+ replaycache_free(x_service.state.replay_cache_rend_cookie);
+ x_service.state.replay_cache_rend_cookie = replaycache_new(0, 0);
+
+ retval = hs_circ_handle_introduce2(&x_service,
+ intro_circ, x_ip,
+ &x_subcred,
+ (uint8_t*)relay_payload, relay_payload_len);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /* ************************************************************ */
+
+ /* Act IV:
+ *
+ * Test cases where the INTRO2 cell should not be able to decode.
+ */
+
+ /* Try sending the exact same INTRODUCE2 cell again and see that the intro
+ * point replay cache triggers: */
+ setup_full_capture_of_logs(LOG_WARN);
+ retval = hs_circ_handle_introduce2(&x_service,
+ intro_circ, x_ip,
+ &x_subcred,
+ (uint8_t*)relay_payload, relay_payload_len);
+ tt_int_op(retval, OP_EQ, -1);
+ expect_log_msg_containing("with the same ENCRYPTED section");
+ teardown_capture_of_logs();
+
+ /* Now cleanup the intro point replay cache but not the service replay cache
+ and see that this one triggers this time. */
+ replaycache_free(x_ip->replay_cache);
+ x_ip->replay_cache = replaycache_new(0, 0);
+ setup_full_capture_of_logs(LOG_INFO);
+ retval = hs_circ_handle_introduce2(&x_service,
+ intro_circ, x_ip,
+ &x_subcred,
+ (uint8_t*)relay_payload, relay_payload_len);
+ tt_int_op(retval, OP_EQ, -1);
+ expect_log_msg_containing("with same REND_COOKIE");
+ teardown_capture_of_logs();
+
+ /* Now just to make sure cleanup both replay caches and make sure that the
+ cell gets through */
+ replaycache_free(x_ip->replay_cache);
+ x_ip->replay_cache = replaycache_new(0, 0);
+ replaycache_free(x_service.state.replay_cache_rend_cookie);
+ x_service.state.replay_cache_rend_cookie = replaycache_new(0, 0);
+ retval = hs_circ_handle_introduce2(&x_service,
+ intro_circ, x_ip,
+ &x_subcred,
+ (uint8_t*)relay_payload, relay_payload_len);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /* As a final thing, create an INTRODUCE1 cell from Alice to X using Y's
+ * subcred (should fail since Y is just another instance and not the frontend
+ * service!) */
+ memset(relay_payload, 0, sizeof(relay_payload));
+ retval = hs_circ_send_introduce1(intro_circ, &rend_circ,
+ alice_ip, &y_subcred);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /* Check that the payload was written successfully */
+ tt_assert(!fast_mem_is_zero(relay_payload, sizeof(relay_payload)));
+ tt_int_op(relay_payload_len, OP_NE, 0);
+
+ retval = hs_circ_handle_introduce2(&x_service,
+ intro_circ, x_ip,
+ &y_subcred,
+ (uint8_t*)relay_payload, relay_payload_len);
+ tt_int_op(retval, OP_EQ, -1);
+
+ done:
+ /* Start cleaning up X */
+ replaycache_free(x_service.state.replay_cache_rend_cookie);
+ smartlist_free(x_service.config.ob_master_pubkeys);
+ tor_free(x_service.state.ob_subcreds);
+ service_descriptor_free(x_service.desc_current);
+ service_descriptor_free(x_service.desc_next);
+ service_intro_point_free(x_ip);
+
+ /* Clean up Alice */
+ hs_desc_intro_point_free(alice_ip);
+ tor_free(rend_circ.hs_ident);
+
+ if (fake_node) {
+ tor_free(fake_node->ri->onion_curve25519_pkey);
+ tor_free(fake_node->ri);
+ tor_free(fake_node);
+ }
+
+ UNMOCK(build_state_get_exit_node);
+ UNMOCK(relay_send_command_from_edge_);
+ UNMOCK(node_get_link_specifier_smartlist);
+ UNMOCK(launch_rendezvous_point_circuit);
+}
+
+static void
+test_cannot_upload_descriptors(void *arg)
+{
+ int ret;
+ time_t now;
+ hs_service_t *service;
+
+ (void) arg;
+
+ hs_init();
+ MOCK(get_or_state,
+ get_or_state_replacement);
+ MOCK(networkstatus_get_reasonably_live_consensus,
+ mock_networkstatus_get_reasonably_live_consensus);
+
+ dummy_state = or_state_new();
+
+ 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);
+ dirauth_sched_recalculate_timing(get_options(), mock_ns.valid_after);
+
+ update_approx_time(mock_ns.valid_after + 1);
+ now = mock_ns.valid_after + 1;
+
+ /* 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);
+
+ /* 1. Testing missing intro points reason. */
+ {
+ digest256map_t *cur = service->desc_current->intro_points.map;
+ digest256map_t *tmp = digest256map_new();
+ service->desc_current->intro_points.map = tmp;
+ service->desc_current->missing_intro_points = 1;
+ setup_full_capture_of_logs(LOG_INFO);
+ run_upload_descriptor_event(now);
+ digest256map_free(tmp, tor_free_);
+ service->desc_current->intro_points.map = cur;
+ expect_log_msg_containing(
+ "Service [scrubbed] can't upload its current descriptor: "
+ "Missing intro points");
+ teardown_capture_of_logs();
+ /* Reset. */
+ service->desc_current->missing_intro_points = 0;
+ }
+
+ /* 2. Testing non established intro points. */
+ {
+ setup_full_capture_of_logs(LOG_INFO);
+ run_upload_descriptor_event(now);
+ expect_log_msg_containing(
+ "Service [scrubbed] can't upload its current descriptor: "
+ "Intro circuits aren't yet all established (0/3).");
+ teardown_capture_of_logs();
+ }
+
+ /* We need to pass the established circuit tests and thus from now on, we
+ * MOCK this to return 3 intro points. */
+ MOCK(count_desc_circuit_established, mock_count_desc_circuit_established);
+ num_intro_points = 3;
+
+ /* 3. Testing non established intro points. */
+ {
+ service->desc_current->next_upload_time = now + 1000;
+ setup_full_capture_of_logs(LOG_INFO);
+ run_upload_descriptor_event(now);
+ expect_log_msg_containing(
+ "Service [scrubbed] can't upload its current descriptor: "
+ "Next upload time is");
+ teardown_capture_of_logs();
+ /* Reset. */
+ service->desc_current->next_upload_time = 0;
+ }
+
+ /* 4. Testing missing live consensus. */
+ {
+ MOCK(networkstatus_get_reasonably_live_consensus,
+ mock_networkstatus_get_reasonably_live_consensus_null);
+ setup_full_capture_of_logs(LOG_INFO);
+ run_upload_descriptor_event(now);
+ expect_log_msg_containing(
+ "Service [scrubbed] can't upload its current descriptor: "
+ "No reasonably live consensus");
+ teardown_capture_of_logs();
+ /* Reset. */
+ MOCK(networkstatus_get_reasonably_live_consensus,
+ mock_networkstatus_get_reasonably_live_consensus);
+ }
+
+ /* 5. Test missing minimum directory information. */
+ {
+ MOCK(router_have_minimum_dir_info,
+ mock_router_have_minimum_dir_info_false);
+ setup_full_capture_of_logs(LOG_INFO);
+ run_upload_descriptor_event(now);
+ expect_log_msg_containing(
+ "Service [scrubbed] can't upload its current descriptor: "
+ "Not enough directory information");
+ teardown_capture_of_logs();
+
+ /* Running it again shouldn't trigger anything due to rate limitation. */
+ setup_full_capture_of_logs(LOG_INFO);
+ run_upload_descriptor_event(now);
+ expect_no_log_entry();
+ teardown_capture_of_logs();
+ UNMOCK(router_have_minimum_dir_info);
+ }
+
+ /* Increase time and redo test (5) in order to test the rate limiting. */
+ update_approx_time(mock_ns.valid_after + 61);
+ {
+ MOCK(router_have_minimum_dir_info,
+ mock_router_have_minimum_dir_info_false);
+ setup_full_capture_of_logs(LOG_INFO);
+ run_upload_descriptor_event(now);
+ expect_log_msg_containing(
+ "Service [scrubbed] can't upload its current descriptor: "
+ "Not enough directory information");
+ teardown_capture_of_logs();
+ UNMOCK(router_have_minimum_dir_info);
+ }
+
+ done:
+ hs_free_all();
+ UNMOCK(count_desc_circuit_established);
+ UNMOCK(networkstatus_get_reasonably_live_consensus);
+ UNMOCK(get_or_state);
+}
+
struct testcase_t hs_service_tests[] = {
{ "e2e_rend_circuit_setup", test_e2e_rend_circuit_setup, TT_FORK,
NULL, NULL },
@@ -2195,7 +2710,7 @@ struct testcase_t hs_service_tests[] = {
NULL, NULL },
{ "rdv_circuit_opened", test_rdv_circuit_opened, TT_FORK,
NULL, NULL },
- { "introduce2", test_introduce2, TT_FORK,
+ { "bad_introduce2", test_bad_introduce2, TT_FORK,
NULL, NULL },
{ "service_event", test_service_event, TT_FORK,
NULL, NULL },
@@ -2207,12 +2722,15 @@ struct testcase_t hs_service_tests[] = {
NULL, NULL },
{ "upload_descriptors", test_upload_descriptors, TT_FORK,
NULL, NULL },
+ { "cannot_upload_descriptors", test_cannot_upload_descriptors, TT_FORK,
+ NULL, NULL },
{ "rendezvous1_parsing", test_rendezvous1_parsing, TT_FORK,
NULL, NULL },
{ "authorized_client_config_equal", test_authorized_client_config_equal,
TT_FORK, NULL, NULL },
{ "export_client_circuit_id", test_export_client_circuit_id, TT_FORK,
NULL, NULL },
+ { "intro2_handling", test_intro2_handling, TT_FORK, NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_link_handshake.c b/src/test/test_link_handshake.c
index 96542ce7ac..1566b349ed 100644
--- a/src/test/test_link_handshake.c
+++ b/src/test/test_link_handshake.c
@@ -18,6 +18,7 @@
#include "feature/relay/routerkeys.h"
#include "core/or/scheduler.h"
#include "feature/nodelist/torcert.h"
+#include "feature/relay/relay_handshake.h"
#include "core/or/or_connection_st.h"
#include "core/or/or_handshake_certs_st.h"
diff --git a/src/test/test_options.c b/src/test/test_options.c
index 9cd1d11d29..8e0d19f126 100644
--- a/src/test/test_options.c
+++ b/src/test/test_options.c
@@ -2362,7 +2362,7 @@ test_options_validate__rend(void *ignored)
expect_log_msg("UseEntryGuards is disabled, but you"
" have configured one or more hidden services on this Tor "
"instance. Your hidden services will be very easy to locate using"
- " a well-known attack -- see http://freehaven.net/anonbib/#hs-"
+ " a well-known attack -- see https://freehaven.net/anonbib/#hs-"
"attack06 for details.\n");
tor_free(msg);
@@ -2378,7 +2378,7 @@ test_options_validate__rend(void *ignored)
expect_no_log_msg("UseEntryGuards is disabled, but you"
" have configured one or more hidden services on this Tor "
"instance. Your hidden services will be very easy to locate using"
- " a well-known attack -- see http://freehaven.net/anonbib/#hs-"
+ " a well-known attack -- see https://freehaven.net/anonbib/#hs-"
"attack06 for details.\n");
free_options_test_data(tdata);
diff --git a/src/test/test_policy.c b/src/test/test_policy.c
index 762241249c..7949e90e9e 100644
--- a/src/test/test_policy.c
+++ b/src/test/test_policy.c
@@ -62,8 +62,8 @@ test_policy_summary_helper_family_flags(const char *policy_str,
short_policy_t *short_policy = NULL;
int success = 0;
- line.key = (char*)"foo";
- line.value = (char *)policy_str;
+ line.key = (char *) "foo";
+ line.value = (char *) policy_str;
line.next = NULL;
r = policies_parse_exit_policy(&line, &policy,
@@ -2124,20 +2124,6 @@ test_policies_fascist_firewall_allows_address(void *arg)
teardown_capture_of_logs(); \
STMT_END
-/** Mock the preferred address function to return zero (prefer IPv4). */
-static int
-mock_fascist_firewall_rand_prefer_ipv6_addr_use_ipv4(void)
-{
- return 0;
-}
-
-/** Mock the preferred address function to return one (prefer IPv6). */
-static int
-mock_fascist_firewall_rand_prefer_ipv6_addr_use_ipv6(void)
-{
- return 1;
-}
-
/** Run unit tests for fascist_firewall_choose_address */
static void
test_policies_fascist_firewall_choose_address(void *arg)
@@ -2536,42 +2522,6 @@ test_policies_fascist_firewall_choose_address(void *arg)
CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_DIR_CONNECTION, 1, 1,
ipv4_dir_ap);
- /* Test ClientAutoIPv6ORPort and pretend we prefer IPv4. */
- memset(&mock_options, 0, sizeof(or_options_t));
- mock_options.ClientAutoIPv6ORPort = 1;
- mock_options.ClientUseIPv4 = 1;
- mock_options.ClientUseIPv6 = 1;
- MOCK(fascist_firewall_rand_prefer_ipv6_addr,
- mock_fascist_firewall_rand_prefer_ipv6_addr_use_ipv4);
- /* Simulate the initialisation of fake_node.ipv6_preferred */
- fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(
- &mock_options);
-
- CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1,
- ipv4_or_ap);
- CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 1, 1,
- ipv4_or_ap);
-
- UNMOCK(fascist_firewall_rand_prefer_ipv6_addr);
-
- /* Test ClientAutoIPv6ORPort and pretend we prefer IPv6. */
- memset(&mock_options, 0, sizeof(or_options_t));
- mock_options.ClientAutoIPv6ORPort = 1;
- mock_options.ClientUseIPv4 = 1;
- mock_options.ClientUseIPv6 = 1;
- MOCK(fascist_firewall_rand_prefer_ipv6_addr,
- mock_fascist_firewall_rand_prefer_ipv6_addr_use_ipv6);
- /* Simulate the initialisation of fake_node.ipv6_preferred */
- fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(
- &mock_options);
-
- CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1,
- ipv6_or_ap);
- CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 1, 1,
- ipv6_or_ap);
-
- UNMOCK(fascist_firewall_rand_prefer_ipv6_addr);
-
/* Test firewall_choose_address_ls(). To do this, we make a fake link
* specifier. */
smartlist_t *lspecs = smartlist_new(),
diff --git a/src/test/test_prob_distr.c b/src/test/test_prob_distr.c
index c3d1c80d70..541a81df3a 100644
--- a/src/test/test_prob_distr.c
+++ b/src/test/test_prob_distr.c
@@ -893,7 +893,7 @@ test_uniform_interval(void *arg)
*
* NIST/SEMATECH e-Handbook of Statistical Methods, Section
* 1.3.6.7.4 `Critical Values of the Chi-Square Distribution',
- * <http://www.itl.nist.gov/div898/handbook/eda/section3/eda3674.htm>,
+ * <https://www.itl.nist.gov/div898/handbook/eda/section3/eda3674.htm>,
* retrieved 2018-10-28.
*/
@@ -1223,14 +1223,16 @@ test_stochastic_weibull_impl(double lambda, double k)
.k = k,
};
+// clang-format off
/*
* XXX Consider applying a Tiku-Singh test:
*
* M.L. Tiku and M. Singh, `Testing the two-parameter
* Weibull distribution', Communications in Statistics --
* Theory and Methods A10(9), 1981, 907--918.
- *https://www.tandfonline.com/doi/pdf/10.1080/03610928108828082?needAccess=true
+https://www.tandfonline.com/doi/pdf/10.1080/03610928108828082?needAccess=true
*/
+// clang-format on
return test_psi_dist_sample(&dist.base);
}
diff --git a/src/test/test_protover.c b/src/test/test_protover.c
index 7341631ccc..71f984a0ac 100644
--- a/src/test/test_protover.c
+++ b/src/test/test_protover.c
@@ -2,6 +2,7 @@
/* See LICENSE for licensing information */
#define PROTOVER_PRIVATE
+#define DIRVOTE_PRIVATE
#include "orconfig.h"
#include "test/test.h"
@@ -12,6 +13,8 @@
#include "core/or/connection_or.h"
#include "lib/tls/tortls.h"
+#include "feature/dirauth/dirvote.h"
+
static void
test_protover_parse(void *arg)
{
@@ -271,6 +274,7 @@ test_protover_all_supported(void *arg)
tt_assert(protover_all_supported("Fribble=", &msg));
tt_ptr_op(msg, OP_EQ, NULL);
+#ifndef ALL_BUGS_ARE_FATAL
/* If we get a completely unparseable list, protover_all_supported should
* hit a fatal assertion for BUG(entries == NULL). */
tor_capture_bugs_(1);
@@ -282,9 +286,10 @@ test_protover_all_supported(void *arg)
tor_capture_bugs_(1);
tt_assert(protover_all_supported("Sleen=1-4294967295", &msg));
tor_end_capture_bugs_();
+#endif /* !defined(ALL_BUGS_ARE_FATAL) */
/* Protocol name too long */
-#ifndef HAVE_RUST // XXXXXX ?????
+#if !defined(HAVE_RUST) && !defined(ALL_BUGS_ARE_FATAL)
tor_capture_bugs_(1);
tt_assert(protover_all_supported(
"DoSaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
@@ -292,7 +297,7 @@ test_protover_all_supported(void *arg)
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"aaaaaaaaaaaa=1-65536", &msg));
tor_end_capture_bugs_();
-#endif /* !defined(HAVE_RUST) */
+#endif /* !defined(HAVE_RUST) && !defined(ALL_BUGS_ARE_FATAL) */
done:
tor_end_capture_bugs_();
@@ -587,6 +592,43 @@ test_protover_vote_roundtrip(void *args)
tor_free(result);
}
+static void
+test_protover_vote_roundtrip_ours(void *args)
+{
+ (void) args;
+ const char *examples[] = {
+ protover_get_supported_protocols(),
+ DIRVOTE_RECOMMEND_RELAY_PROTO,
+ DIRVOTE_RECOMMEND_CLIENT_PROTO,
+ DIRVOTE_REQUIRE_RELAY_PROTO,
+ DIRVOTE_REQUIRE_CLIENT_PROTO,
+ };
+ unsigned u;
+ smartlist_t *votes = smartlist_new();
+ char *result = NULL;
+
+ for (u = 0; u < ARRAY_LENGTH(examples); ++u) {
+ tt_assert(examples[u]);
+ const char *input = examples[u];
+ const char *expected_output = examples[u];
+
+ smartlist_add(votes, (void*)input);
+ result = protover_compute_vote(votes, 1);
+ if (expected_output != NULL) {
+ tt_str_op(result, OP_EQ, expected_output);
+ } else {
+ tt_str_op(result, OP_EQ, "");
+ }
+
+ smartlist_clear(votes);
+ tor_free(result);
+ }
+
+ done:
+ smartlist_free(votes);
+ tor_free(result);
+}
+
#define PV_TEST(name, flags) \
{ #name, test_protover_ ##name, (flags), NULL, NULL }
@@ -600,5 +642,6 @@ struct testcase_t protover_tests[] = {
PV_TEST(supports_version, 0),
PV_TEST(supported_protocols, 0),
PV_TEST(vote_roundtrip, 0),
+ PV_TEST(vote_roundtrip_ours, 0),
END_OF_TESTCASES
};
diff --git a/src/test/test_pt.c b/src/test/test_pt.c
index 26eaf7b7e7..893fec3674 100644
--- a/src/test/test_pt.c
+++ b/src/test/test_pt.c
@@ -579,8 +579,10 @@ test_get_pt_proxy_uri(void *arg)
tor_free(uri);
}
+#ifndef COCCI
#define PT_LEGACY(name) \
- { #name, test_pt_ ## name , 0, NULL, NULL }
+ { (#name), test_pt_ ## name , 0, NULL, NULL }
+#endif
struct testcase_t pt_tests[] = {
PT_LEGACY(parsing),
diff --git a/src/test/test_shared_random.c b/src/test/test_shared_random.c
index 8cb2238248..9e49e835c9 100644
--- a/src/test/test_shared_random.c
+++ b/src/test/test_shared_random.c
@@ -21,7 +21,7 @@
#include "feature/nodelist/dirlist.h"
#include "feature/dirparse/authcert_parse.h"
#include "feature/hs_common/shared_random_client.h"
-#include "feature/dircommon/voting_schedule.h"
+#include "feature/dirauth/voting_schedule.h"
#include "feature/dirclient/dir_server_st.h"
#include "feature/nodelist/networkstatus_st.h"
@@ -204,7 +204,7 @@ test_get_state_valid_until_time(void *arg)
retval = parse_rfc1123_time("Mon, 20 Apr 2015 00:00:01 UTC",
&current_time);
tt_int_op(retval, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), current_time);
+ dirauth_sched_recalculate_timing(get_options(), current_time);
valid_until_time = get_state_valid_until_time(current_time);
/* Compare it with the correct result */
@@ -216,7 +216,7 @@ 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, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), current_time);
+ dirauth_sched_recalculate_timing(get_options(), current_time);
valid_until_time = get_state_valid_until_time(current_time);
format_iso_time(tbuf, valid_until_time);
@@ -227,7 +227,7 @@ 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, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), current_time);
+ dirauth_sched_recalculate_timing(get_options(), current_time);
valid_until_time = get_state_valid_until_time(current_time);
format_iso_time(tbuf, valid_until_time);
@@ -238,7 +238,7 @@ 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, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), current_time);
+ dirauth_sched_recalculate_timing(get_options(), current_time);
valid_until_time = get_state_valid_until_time(current_time);
format_iso_time(tbuf, valid_until_time);
@@ -278,7 +278,7 @@ test_get_start_time_of_current_run(void *arg)
retval = parse_rfc1123_time("Mon, 20 Apr 2015 00:00:01 UTC",
&current_time);
tt_int_op(retval, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), current_time);
+ dirauth_sched_recalculate_timing(get_options(), current_time);
run_start_time = sr_state_get_start_time_of_current_protocol_run();
/* Compare it with the correct result */
@@ -290,7 +290,7 @@ test_get_start_time_of_current_run(void *arg)
retval = parse_rfc1123_time("Mon, 20 Apr 2015 23:59:59 UTC",
&current_time);
tt_int_op(retval, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), current_time);
+ dirauth_sched_recalculate_timing(get_options(), current_time);
run_start_time = sr_state_get_start_time_of_current_protocol_run();
/* Compare it with the correct result */
@@ -302,7 +302,7 @@ test_get_start_time_of_current_run(void *arg)
retval = parse_rfc1123_time("Mon, 20 Apr 2015 00:00:00 UTC",
&current_time);
tt_int_op(retval, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), current_time);
+ dirauth_sched_recalculate_timing(get_options(), current_time);
run_start_time = sr_state_get_start_time_of_current_protocol_run();
/* Compare it with the correct result */
@@ -332,7 +332,7 @@ test_get_start_time_of_current_run(void *arg)
&current_time);
tt_int_op(retval, OP_EQ, 0);
update_approx_time(current_time);
- voting_schedule_recalculate_timing(get_options(), current_time);
+ dirauth_sched_recalculate_timing(get_options(), current_time);
run_start_time = sr_state_get_start_time_of_current_protocol_run();
@@ -340,7 +340,7 @@ test_get_start_time_of_current_run(void *arg)
format_iso_time(tbuf, run_start_time);
tt_str_op("2015-04-19 00:00:00", OP_EQ, tbuf);
/* Check that voting_schedule.interval_starts is at 01:00 (see above) */
- time_t interval_starts = voting_schedule_get_next_valid_after_time();
+ time_t interval_starts = dirauth_sched_get_next_valid_after_time();
format_iso_time(tbuf, interval_starts);
tt_str_op("2015-04-20 01:00:00", OP_EQ, tbuf);
}
@@ -360,7 +360,7 @@ test_get_start_time_of_current_run(void *arg)
retval = parse_rfc1123_time("Mon, 20 Apr 2015 00:15:32 UTC",
&current_time);
tt_int_op(retval, OP_EQ, 0);
- voting_schedule_recalculate_timing(get_options(), current_time);
+ dirauth_sched_recalculate_timing(get_options(), current_time);
run_start_time = sr_state_get_start_time_of_current_protocol_run();
/* Compare it with the correct result */
@@ -392,13 +392,13 @@ test_get_start_time_functions(void *arg)
tt_int_op(retval, OP_EQ, 0);
time_t now = mock_consensus.valid_after;
- voting_schedule_recalculate_timing(get_options(), now);
+ dirauth_sched_recalculate_timing(get_options(), now);
time_t start_time_of_protocol_run =
sr_state_get_start_time_of_current_protocol_run();
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,
+ tt_int_op(dirauth_sched_get_cur_valid_after_time(), OP_EQ,
start_time_of_protocol_run);
done:
diff --git a/src/test/test_util.c b/src/test/test_util.c
index e7f4106d91..2aee07a26a 100644
--- a/src/test/test_util.c
+++ b/src/test/test_util.c
@@ -1898,6 +1898,56 @@ test_util_config_line_crlf(void *arg)
tor_free(k); tor_free(v);
}
+static void
+test_util_config_line_partition(void *arg)
+{
+ (void)arg;
+ config_line_t *lines = NULL, *orig, *rest = NULL;
+
+ config_line_append(&lines, "Header", "X");
+ config_line_append(&lines, "Item", "Y");
+ config_line_append(&lines, "Thing", "Z");
+
+ config_line_append(&lines, "HEADER", "X2");
+
+ config_line_append(&lines, "header", "X3");
+ config_line_append(&lines, "Item3", "Foob");
+
+ /* set up h2 and h3 to point to the places where we hope the headers will
+ be. */
+ config_line_t *h2 = lines->next->next->next;
+ config_line_t *h3 = h2->next;
+ tt_str_op(h2->key, OP_EQ, "HEADER");
+ tt_str_op(h3->key, OP_EQ, "header");
+
+ orig = lines;
+ rest = config_lines_partition(lines, "Header");
+ tt_ptr_op(lines, OP_EQ, orig);
+ tt_ptr_op(rest, OP_EQ, h2);
+ tt_str_op(lines->next->key, OP_EQ, "Item");
+ tt_str_op(lines->next->next->key, OP_EQ, "Thing");
+ tt_ptr_op(lines->next->next->next, OP_EQ, NULL);
+ config_free_lines(lines);
+
+ orig = lines = rest;
+ rest = config_lines_partition(lines, "Header");
+ tt_ptr_op(lines, OP_EQ, orig);
+ tt_ptr_op(rest, OP_EQ, h3);
+ tt_ptr_op(lines->next, OP_EQ, NULL);
+ config_free_lines(lines);
+
+ orig = lines = rest;
+ rest = config_lines_partition(lines, "Header");
+ tt_ptr_op(lines, OP_EQ, orig);
+ tt_ptr_op(rest, OP_EQ, NULL);
+ tt_str_op(lines->next->key, OP_EQ, "Item3");
+ tt_ptr_op(lines->next->next, OP_EQ, NULL);
+
+ done:
+ config_free_lines(lines);
+ config_free_lines(rest);
+}
+
#ifndef DISABLE_PWDB_TESTS
static void
test_util_expand_filename(void *arg)
@@ -4620,6 +4670,35 @@ test_util_di_ops(void *arg)
}
static void
+test_util_memcpy_iftrue_timei(void *arg)
+{
+ (void)arg;
+ char buf1[25];
+ char buf2[25];
+ char buf3[25];
+
+ for (int i = 0; i < 100; ++i) {
+ crypto_rand(buf1, sizeof(buf1));
+ crypto_rand(buf2, sizeof(buf2));
+ memcpy(buf3, buf1, sizeof(buf1));
+
+ /* We just copied buf1 into buf3. Now we're going to copy buf2 into buf2,
+ iff our coin flip comes up heads. */
+ bool coinflip = crypto_rand_int(2) == 0;
+
+ memcpy_if_true_timei(coinflip, buf3, buf2, sizeof(buf3));
+
+ if (coinflip) {
+ tt_mem_op(buf3, OP_EQ, buf2, sizeof(buf2));
+ } else {
+ tt_mem_op(buf3, OP_EQ, buf1, sizeof(buf1));
+ }
+ }
+ done:
+ ;
+}
+
+static void
test_util_di_map(void *arg)
{
(void)arg;
@@ -5620,7 +5699,7 @@ test_util_hostname_validation(void *arg)
tt_assert(string_is_valid_nonrfc_hostname("luck.y13."));
// We allow punycode TLDs. For examples, see
- // http://data.iana.org/TLD/tlds-alpha-by-domain.txt
+ // https://data.iana.org/TLD/tlds-alpha-by-domain.txt
tt_assert(string_is_valid_nonrfc_hostname("example.xn--l1acc"));
done:
@@ -6353,42 +6432,42 @@ test_util_map_anon_nofork(void *arg)
#ifndef COCCI
#define UTIL_LEGACY(name) \
- { #name, test_util_ ## name , 0, NULL, NULL }
+ { (#name), test_util_ ## name , 0, NULL, NULL }
#define UTIL_TEST(name, flags) \
- { #name, test_util_ ## name, flags, NULL, NULL }
+ { (#name), test_util_ ## name, flags, NULL, NULL }
#define COMPRESS(name, identifier) \
- { "compress/" #name, test_util_compress, 0, &compress_setup, \
+ { ("compress/" #name), test_util_compress, 0, &compress_setup, \
(char*)(identifier) }
#define COMPRESS_CONCAT(name, identifier) \
- { "compress_concat/" #name, test_util_decompress_concatenated, 0, \
+ { ("compress_concat/" #name), test_util_decompress_concatenated, 0, \
&compress_setup, \
(char*)(identifier) }
#define COMPRESS_JUNK(name, identifier) \
- { "compress_junk/" #name, test_util_decompress_junk, 0, \
+ { ("compress_junk/" #name), test_util_decompress_junk, 0, \
&compress_setup, \
(char*)(identifier) }
#define COMPRESS_DOS(name, identifier) \
- { "compress_dos/" #name, test_util_decompress_dos, 0, \
+ { ("compress_dos/" #name), test_util_decompress_dos, 0, \
&compress_setup, \
(char*)(identifier) }
-#endif /* !defined(COCCI) */
#ifdef _WIN32
#define UTIL_TEST_WIN_ONLY(n, f) UTIL_TEST(n, (f))
#else
-#define UTIL_TEST_WIN_ONLY(n, f) { #n, NULL, TT_SKIP, NULL, NULL }
+#define UTIL_TEST_WIN_ONLY(n, f) { (#n), NULL, TT_SKIP, NULL, NULL }
#endif
#ifdef DISABLE_PWDB_TESTS
-#define UTIL_TEST_PWDB(n, f) { #n, NULL, TT_SKIP, NULL, NULL }
+#define UTIL_TEST_PWDB(n, f) { (#n), NULL, TT_SKIP, NULL, NULL }
#else
#define UTIL_TEST_PWDB(n, f) UTIL_TEST(n, (f))
#endif
+#endif /* !defined(COCCI) */
struct testcase_t util_tests[] = {
UTIL_LEGACY(time),
@@ -6398,6 +6477,7 @@ struct testcase_t util_tests[] = {
UTIL_LEGACY(config_line_comment_character),
UTIL_LEGACY(config_line_escaped_content),
UTIL_LEGACY(config_line_crlf),
+ UTIL_TEST(config_line_partition, 0),
UTIL_TEST_PWDB(expand_filename, 0),
UTIL_LEGACY(escape_string_socks),
UTIL_LEGACY(string_is_key_value),
@@ -6434,6 +6514,7 @@ struct testcase_t util_tests[] = {
UTIL_LEGACY(path_is_relative),
UTIL_LEGACY(strtok),
UTIL_LEGACY(di_ops),
+ UTIL_TEST(memcpy_iftrue_timei, 0),
UTIL_TEST(di_map, 0),
UTIL_TEST(round_to_next_multiple_of, 0),
UTIL_TEST(laplace, 0),
diff --git a/src/test/test_util_process.c b/src/test/test_util_process.c
index 0e17e009f3..fc79fe9b1f 100644
--- a/src/test/test_util_process.c
+++ b/src/test/test_util_process.c
@@ -67,15 +67,16 @@ test_util_process_clear_waitpid_callback(void *ignored)
}
#endif /* !defined(_WIN32) */
+#ifndef COCCI
#ifndef _WIN32
-#define TEST(name) { #name, test_util_process_##name, 0, NULL, NULL }
+#define TEST(name) { (#name), test_util_process_##name, 0, NULL, NULL }
#else
-#define TEST(name) { #name, NULL, TT_SKIP, NULL, NULL }
+#define TEST(name) { (#name), NULL, TT_SKIP, NULL, NULL }
#endif
+#endif /* !defined(COCCI) */
struct testcase_t util_process_tests[] = {
TEST(set_waitpid_callback),
TEST(clear_waitpid_callback),
END_OF_TESTCASES
};
-
diff --git a/src/test/test_voting_schedule.c b/src/test/test_voting_schedule.c
index 54d1815a77..df64b79167 100644
--- a/src/test/test_voting_schedule.c
+++ b/src/test/test_voting_schedule.c
@@ -4,14 +4,15 @@
#include "orconfig.h"
#include "core/or/or.h"
-#include "feature/dircommon/voting_schedule.h"
+#include "feature/dirauth/voting_schedule.h"
+#include "feature/nodelist/networkstatus.h"
#include "test/test.h"
static void
test_voting_schedule_interval_start(void *arg)
{
-#define next_interval voting_schedule_get_start_of_next_interval
+#define next_interval voting_sched_get_start_of_interval_after
(void)arg;
char buf[ISO_TIME_LEN+1];
@@ -61,4 +62,3 @@ struct testcase_t voting_schedule_tests[] = {
VS(interval_start, 0),
END_OF_TESTCASES
};
-
diff --git a/src/test/testing_common.c b/src/test/testing_common.c
index d7c6edb646..d68dfa4047 100644
--- a/src/test/testing_common.c
+++ b/src/test/testing_common.c
@@ -273,7 +273,7 @@ main(int c, const char **v)
int loglevel = LOG_ERR;
int accel_crypto = 0;
- subsystems_init_upto(SUBSYS_LEVEL_LIBS);
+ subsystems_init();
options = options_new();