summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--changes/bug290185
-rw-r--r--changes/bug298053
-rw-r--r--changes/bug298235
-rw-r--r--changes/cid14441193
-rw-r--r--changes/ticket213774
-rw-r--r--changes/ticket295373
-rw-r--r--changes/ticket298067
-rw-r--r--configure.ac1
-rw-r--r--doc/tor.1.txt5
-rw-r--r--scripts/maint/practracker/exceptions.txt3
-rwxr-xr-xscripts/maint/practracker/practracker.py9
-rw-r--r--scripts/maint/practracker/problem.py31
-rw-r--r--scripts/maint/practracker/util.py3
-rw-r--r--src/feature/dirauth/bwauth.c8
-rw-r--r--src/feature/dircache/dircache.c42
-rw-r--r--src/feature/dircommon/consdiff.c2
-rw-r--r--src/feature/nodelist/torcert.c4
-rw-r--r--src/feature/nodelist/torcert.h2
-rw-r--r--src/feature/relay/router.c375
-rw-r--r--src/feature/relay/router.h23
-rw-r--r--src/feature/relay/routerkeys.c16
-rw-r--r--src/feature/relay/routerkeys.h4
-rw-r--r--src/lib/cc/torint.h9
-rw-r--r--src/lib/math/prob_distr.h97
-rw-r--r--src/test/include.am3
-rw-r--r--src/test/ptr_helpers.c50
-rw-r--r--src/test/ptr_helpers.h23
-rw-r--r--src/test/test.h1
-rw-r--r--src/test/test_dir.c1262
-rw-r--r--src/test/test_dir_handle_get.c106
-rw-r--r--src/test/test_ptr_slow.c106
-rw-r--r--src/test/test_router.c3
-rw-r--r--src/test/test_shared_random.c134
-rw-r--r--src/test/test_slow.c1
34 files changed, 1917 insertions, 436 deletions
diff --git a/changes/bug29018 b/changes/bug29018
new file mode 100644
index 0000000000..b006ae36a7
--- /dev/null
+++ b/changes/bug29018
@@ -0,0 +1,5 @@
+ o Minor bugfixes (stats):
+ - When ExtraInfoStatistics is 0, stop including bandwidth usage statistics,
+ GeoIPFile hashes, ServerTransportPlugin lines, and bridge statistics
+ by country in extra-info documents. Fixes bug 29018;
+ bugfix on 0.2.4.1-alpha.
diff --git a/changes/bug29805 b/changes/bug29805
new file mode 100644
index 0000000000..00c846e9af
--- /dev/null
+++ b/changes/bug29805
@@ -0,0 +1,3 @@
+ o Minor bugfixes (probability distributions):
+ - Refactor and improve parts of the probability distribution code that made
+ Coverity complain. Fixes bug 29805; bugfix on 0.4.0.1-alpha. \ No newline at end of file
diff --git a/changes/bug29823 b/changes/bug29823
new file mode 100644
index 0000000000..d856cf1fef
--- /dev/null
+++ b/changes/bug29823
@@ -0,0 +1,5 @@
+ o Minor bugfixes (unit tests):
+ - Split test_utils_general() to several smaller test functions in
+ test_utils_general(). This makes it easier to perform resource
+ deallocation on assert failure and fixes Coverity warnings CID 1444117
+ and CID 1444118. Fixes bug 29823; bugfix on 0.2.9.1-alpha.
diff --git a/changes/cid1444119 b/changes/cid1444119
new file mode 100644
index 0000000000..bb6854e66f
--- /dev/null
+++ b/changes/cid1444119
@@ -0,0 +1,3 @@
+ o Minor bugfixes (C correctness):
+ - Fix an unlikely memory leak in consensus_diff_apply(). Fixes bug 29824;
+ bugfix on 0.3.1.1-alpha. This is Coverity warning CID 1444119.
diff --git a/changes/ticket21377 b/changes/ticket21377
new file mode 100644
index 0000000000..2bf5149a0a
--- /dev/null
+++ b/changes/ticket21377
@@ -0,0 +1,4 @@
+ o Minor features (dircache):
+ - When a directory authority is using a bandwidth file to obtain the
+ bandwidth values that will be included in the next vote, serve this
+ bandwidth file at /tor/status-vote/next/bandwidth. Closes ticket 21377. \ No newline at end of file
diff --git a/changes/ticket29537 b/changes/ticket29537
new file mode 100644
index 0000000000..afe2308205
--- /dev/null
+++ b/changes/ticket29537
@@ -0,0 +1,3 @@
+ o Testing:
+ - Check that representative subsets of values of `int` and `unsigned int`
+ can be represented by `void *`. Resolves issue 29537.
diff --git a/changes/ticket29806 b/changes/ticket29806
new file mode 100644
index 0000000000..6afefd4c04
--- /dev/null
+++ b/changes/ticket29806
@@ -0,0 +1,7 @@
+ o Minor features (bandwidth authority):
+ - Make bandwidth authorities to ignore relays that are reported in the
+ bandwidth file with the key-value "vote=0".
+ This change allows to report the relays that were not measured due
+ some failure and diagnose the reasons without the bandwidth being included in the
+ bandwidth authorities vote.
+ Closes ticket 29806.
diff --git a/configure.ac b/configure.ac
index 78597e511d..0b80669f03 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1605,6 +1605,7 @@ AC_CHECK_MEMBERS([struct timeval.tv_sec], , ,
AC_CHECK_SIZEOF(char)
AC_CHECK_SIZEOF(short)
AC_CHECK_SIZEOF(int)
+AC_CHECK_SIZEOF(unsigned int)
AC_CHECK_SIZEOF(long)
AC_CHECK_SIZEOF(long long)
AC_CHECK_SIZEOF(__int64)
diff --git a/doc/tor.1.txt b/doc/tor.1.txt
index ee91976066..ac79ed231b 100644
--- a/doc/tor.1.txt
+++ b/doc/tor.1.txt
@@ -2313,7 +2313,8 @@ is non-zero):
When this option is enabled and BridgeRelay is also enabled, and we have
GeoIP data, Tor keeps a per-country count of how many client
addresses have contacted it so that it can help the bridge authority guess
- which countries have blocked access to it. (Default: 1)
+ which countries have blocked access to it. If ExtraInfoStatistics is
+ enabled, it will be published as part of extra-info document. (Default: 1)
[[ServerDNSRandomizeCase]] **ServerDNSRandomizeCase** **0**|**1**::
When this option is set, Tor sets the case of each character randomly in
@@ -2395,6 +2396,8 @@ is non-zero):
[[ExtraInfoStatistics]] **ExtraInfoStatistics** **0**|**1**::
When this option is enabled, Tor includes previously gathered statistics in
its extra-info documents that it uploads to the directory authorities.
+ Disabling this option also disables bandwidth usage statistics, GeoIPFile
+ hashes, and ServerTransportPlugin lists in the extra-info file.
(Default: 1)
[[ExtendAllowPrivateAddresses]] **ExtendAllowPrivateAddresses** **0**|**1**::
diff --git a/scripts/maint/practracker/exceptions.txt b/scripts/maint/practracker/exceptions.txt
index a6726ef570..baccbef255 100644
--- a/scripts/maint/practracker/exceptions.txt
+++ b/scripts/maint/practracker/exceptions.txt
@@ -132,11 +132,12 @@ problem function-size /src/feature/dircache/dircache.c:handle_get_current_consen
problem function-size /src/feature/dircache/dircache.c:directory_handle_command_post() 120
problem function-size /src/feature/hibernate/hibernate.c:accounting_parse_options() 109
problem function-size /src/feature/relay/routerkeys.c:load_ed_keys() 294
-problem file-size /src/feature/relay/router.c 3221
+problem file-size /src/feature/relay/router.c 3412
problem include-count /src/feature/relay/router.c 56
problem function-size /src/feature/relay/router.c:init_keys() 252
problem function-size /src/feature/relay/router.c:get_my_declared_family() 114
problem function-size /src/feature/relay/router.c:router_build_fresh_descriptor() 190
+problem function-size /src/feature/relay/router.c:router_build_fresh_unsigned_routerinfo() 140
problem function-size /src/feature/relay/router.c:router_dump_router_to_string() 375
problem function-size /src/feature/relay/router.c:extrainfo_dump_to_string() 208
problem function-size /src/feature/relay/dns.c:dns_resolve_impl() 134
diff --git a/scripts/maint/practracker/practracker.py b/scripts/maint/practracker/practracker.py
index a6e6d0b607..3274bd15f7 100755
--- a/scripts/maint/practracker/practracker.py
+++ b/scripts/maint/practracker/practracker.py
@@ -46,6 +46,13 @@ TOR_TOPDIR = None
#######################################################
+if sys.version_info[0] <= 2:
+ def open_file(fname):
+ return open(fname, 'r')
+else:
+ def open_file(fname):
+ return open(fname, 'r', encoding='utf-8')
+
def consider_file_size(fname, f):
"""Consider file size issues for 'f' and return True if a new issue was found"""
file_size = metrics.get_file_len(f)
@@ -85,7 +92,7 @@ def consider_all_metrics(files_list):
"""Consider metrics for all files, and return True if new issues were found"""
found_new_issues = False
for fname in files_list:
- with open(fname, 'r') as f:
+ with open_file(fname) as f:
found_new_issues |= consider_metrics_for_file(fname, f)
return found_new_issues
diff --git a/scripts/maint/practracker/problem.py b/scripts/maint/practracker/problem.py
index ab3d55057e..d5ebedd17f 100644
--- a/scripts/maint/practracker/problem.py
+++ b/scripts/maint/practracker/problem.py
@@ -10,6 +10,7 @@ get worse.
from __future__ import print_function
import os.path
+import re
import sys
class ProblemVault(object):
@@ -30,8 +31,15 @@ class ProblemVault(object):
def register_exceptions(self, exception_file):
# Register exceptions
- for line in exception_file:
- problem = get_old_problem_from_exception_str(line)
+ for lineno, line in enumerate(exception_file, 1):
+ try:
+ problem = get_old_problem_from_exception_str(line)
+ except ValueError as v:
+ print("Exception file line {} not recognized: {}"
+ .format(lineno,v),
+ file=sys.stderr)
+ continue
+
if problem is None:
continue
@@ -122,11 +130,20 @@ class FunctionSizeProblem(Problem):
def __init__(self, problem_location, metric_value):
super(FunctionSizeProblem, self).__init__("function-size", problem_location, metric_value)
+comment_re = re.compile(r'#.*$')
+
def get_old_problem_from_exception_str(exception_str):
- try:
- _, problem_type, problem_location, metric_value = exception_str.split(" ")
- except ValueError:
+ orig_str = exception_str
+ exception_str = comment_re.sub("", exception_str)
+ fields = exception_str.split()
+ if len(fields) == 0:
+ # empty line or comment
return None
+ elif len(fields) == 4:
+ # valid line
+ _, problem_type, problem_location, metric_value = fields
+ else:
+ raise ValueError("Misformatted line {!r}".format(orig_str))
if problem_type == "file-size":
return FileSizeProblem(problem_location, metric_value)
@@ -135,6 +152,4 @@ def get_old_problem_from_exception_str(exception_str):
elif problem_type == "function-size":
return FunctionSizeProblem(problem_location, metric_value)
else:
-# print("Unknown exception line '{}'".format(exception_str))
- return None
-
+ raise ValueError("Unknown exception type {!r}".format(orig_str))
diff --git a/scripts/maint/practracker/util.py b/scripts/maint/practracker/util.py
index 63de72d5a3..b0ca73b997 100644
--- a/scripts/maint/practracker/util.py
+++ b/scripts/maint/practracker/util.py
@@ -11,6 +11,8 @@ def get_tor_c_files(tor_topdir):
files_list = []
for root, directories, filenames in os.walk(tor_topdir):
+ directories.sort()
+ filenames.sort()
for filename in filenames:
# We only care about .c files
if not filename.endswith(".c"):
@@ -24,4 +26,3 @@ def get_tor_c_files(tor_topdir):
files_list.append(full_path)
return files_list
-
diff --git a/src/feature/dirauth/bwauth.c b/src/feature/dirauth/bwauth.c
index 7d7dea4dfa..1cfd8119df 100644
--- a/src/feature/dirauth/bwauth.c
+++ b/src/feature/dirauth/bwauth.c
@@ -384,7 +384,13 @@ measured_bw_line_parse(measured_bw_line_t *out, const char *orig_line,
}
do {
- if (strcmpstart(cp, "bw=") == 0) {
+ // If the line contains vote=0, ignore it.
+ if (strcmpstart(cp, "vote=0") == 0) {
+ log_debug(LD_DIRSERV, "Ignoring bandwidth file line that contains "
+ "vote=0: %s",escaped(orig_line));
+ tor_free(line);
+ return -1;
+ } else if (strcmpstart(cp, "bw=") == 0) {
int parse_ok = 0;
char *endptr;
if (got_bw) {
diff --git a/src/feature/dircache/dircache.c b/src/feature/dircache/dircache.c
index ee6e4f7a81..a8649054a9 100644
--- a/src/feature/dircache/dircache.c
+++ b/src/feature/dircache/dircache.c
@@ -49,7 +49,8 @@
#define ROUTERDESC_BY_DIGEST_CACHE_LIFETIME (48*60*60)
#define ROBOTS_CACHE_LIFETIME (24*60*60)
#define MICRODESC_CACHE_LIFETIME (48*60*60)
-
+/* Bandwidth files change every hour. */
+#define BANDWIDTH_CACHE_LIFETIME (30*60)
/** Parse an HTTP request string <b>headers</b> of the form
* \verbatim
* "\%s [http[s]://]\%s HTTP/1..."
@@ -351,12 +352,15 @@ static int handle_get_robots(dir_connection_t *conn,
const get_handler_args_t *args);
static int handle_get_networkstatus_bridges(dir_connection_t *conn,
const get_handler_args_t *args);
+static int handle_get_next_bandwidth(dir_connection_t *conn,
+ const get_handler_args_t *args);
/** Table for handling GET requests. */
static const url_table_ent_t url_table[] = {
{ "/tor/", 0, handle_get_frontpage },
{ "/tor/status-vote/current/consensus", 1, handle_get_current_consensus },
{ "/tor/status-vote/current/", 1, handle_get_status_vote },
+ { "/tor/status-vote/next/bandwidth", 0, handle_get_next_bandwidth },
{ "/tor/status-vote/next/", 1, handle_get_status_vote },
{ "/tor/micro/d/", 1, handle_get_microdesc },
{ "/tor/server/", 1, handle_get_descriptor },
@@ -1453,6 +1457,42 @@ handle_get_networkstatus_bridges(dir_connection_t *conn,
return 0;
}
+/** Helper function for GET the bandwidth file used for the next vote */
+static int
+handle_get_next_bandwidth(dir_connection_t *conn,
+ const get_handler_args_t *args)
+{
+ log_debug(LD_DIR, "Getting next bandwidth.");
+ const or_options_t *options = get_options();
+ const compress_method_t compress_method =
+ find_best_compression_method(args->compression_supported, 1);
+
+ if (options->V3BandwidthsFile) {
+ char *bandwidth = read_file_to_str(options->V3BandwidthsFile,
+ RFTS_IGNORE_MISSING, NULL);
+ if (bandwidth != NULL) {
+ ssize_t len = strlen(bandwidth);
+ write_http_response_header(conn, compress_method != NO_METHOD ? -1 : len,
+ compress_method, BANDWIDTH_CACHE_LIFETIME);
+ if (compress_method != NO_METHOD) {
+ conn->compress_state = tor_compress_new(1, compress_method,
+ choose_compression_level(len/2));
+ log_debug(LD_DIR, "Compressing bandwidth file.");
+ connection_buf_add_compress(bandwidth, len, conn, 0);
+ /* Flush the compression state. */
+ connection_buf_add_compress("", 0, conn, 1);
+ } else {
+ log_debug(LD_DIR, "Not compressing bandwidth file.");
+ connection_buf_add(bandwidth, len, TO_CONN(conn));
+ }
+ tor_free(bandwidth);
+ return 0;
+ }
+ }
+ write_short_http_response(conn, 404, "Not found");
+ return 0;
+}
+
/** Helper function for GET robots.txt or /tor/robots.txt */
static int
handle_get_robots(dir_connection_t *conn, const get_handler_args_t *args)
diff --git a/src/feature/dircommon/consdiff.c b/src/feature/dircommon/consdiff.c
index 698f548013..8e93953f73 100644
--- a/src/feature/dircommon/consdiff.c
+++ b/src/feature/dircommon/consdiff.c
@@ -1389,7 +1389,7 @@ consensus_diff_apply(const char *consensus,
r1 = consensus_compute_digest_as_signed(consensus, consensus_len, &d1);
if (BUG(r1 < 0))
- return NULL; // LCOV_EXCL_LINE
+ goto done;
lines1 = smartlist_new();
lines2 = smartlist_new();
diff --git a/src/feature/nodelist/torcert.c b/src/feature/nodelist/torcert.c
index b0197e9f13..56f1a8ac9f 100644
--- a/src/feature/nodelist/torcert.c
+++ b/src/feature/nodelist/torcert.c
@@ -290,8 +290,8 @@ tor_cert_describe_signature_status(const tor_cert_t *cert)
}
/** Return a new copy of <b>cert</b> */
-tor_cert_t *
-tor_cert_dup(const tor_cert_t *cert)
+MOCK_IMPL(tor_cert_t *,
+tor_cert_dup,(const tor_cert_t *cert))
{
tor_cert_t *newcert = tor_memdup(cert, sizeof(tor_cert_t));
if (cert->encoded)
diff --git a/src/feature/nodelist/torcert.h b/src/feature/nodelist/torcert.h
index 492275b514..03d5bdca93 100644
--- a/src/feature/nodelist/torcert.h
+++ b/src/feature/nodelist/torcert.h
@@ -71,7 +71,7 @@ int tor_cert_checksig(tor_cert_t *cert,
const ed25519_public_key_t *pubkey, time_t now);
const char *tor_cert_describe_signature_status(const tor_cert_t *cert);
-tor_cert_t *tor_cert_dup(const tor_cert_t *cert);
+MOCK_DECL(tor_cert_t *,tor_cert_dup,(const tor_cert_t *cert));
int tor_cert_eq(const tor_cert_t *cert1, const tor_cert_t *cert2);
int tor_cert_opt_eq(const tor_cert_t *cert1, const tor_cert_t *cert2);
diff --git a/src/feature/relay/router.c b/src/feature/relay/router.c
index fcc84730bd..e5cf72ad18 100644
--- a/src/feature/relay/router.c
+++ b/src/feature/relay/router.c
@@ -152,6 +152,8 @@ routerinfo_err_to_string(int err)
return "Cannot generate descriptor";
case TOR_ROUTERINFO_ERROR_DESC_REBUILDING:
return "Descriptor still rebuilding - not ready yet";
+ case TOR_ROUTERINFO_ERROR_INTERNAL_BUG:
+ return "Internal bug, see logs for details";
}
log_warn(LD_BUG, "unknown routerinfo error %d - shouldn't happen", err);
@@ -194,8 +196,8 @@ set_onion_key(crypto_pk_t *k)
/** Return the current onion key. Requires that the onion key has been
* loaded or generated. */
-crypto_pk_t *
-get_onion_key(void)
+MOCK_IMPL(crypto_pk_t *,
+get_onion_key,(void))
{
tor_assert(onionkey);
return onionkey;
@@ -269,11 +271,12 @@ expire_old_onion_keys(void)
/** Return the current secret onion key for the ntor handshake. Must only
* be called from the main thread. */
-static const curve25519_keypair_t *
-get_current_curve25519_keypair(void)
+MOCK_IMPL(STATIC const struct curve25519_keypair_t *,
+get_current_curve25519_keypair,(void))
{
return &curve25519_onion_key;
}
+
/** Return a map from KEYID (the key itself) to keypairs for use in the ntor
* handshake. Must only be called from the main thread. */
di_digest256_map_t *
@@ -374,8 +377,8 @@ assert_identity_keys_ok(void)
/** Returns the current server identity key; requires that the key has
* been set, and that we are running as a Tor server.
*/
-crypto_pk_t *
-get_server_identity_key(void)
+MOCK_IMPL(crypto_pk_t *,
+get_server_identity_key,(void))
{
tor_assert(server_identitykey);
tor_assert(server_mode(get_options()));
@@ -1941,26 +1944,33 @@ get_my_declared_family(const or_options_t *options)
return result;
}
-/** Build a fresh routerinfo, signed server descriptor, and extra-info document
- * for this OR. Set r to the generated routerinfo, e to the generated
- * extra-info document. Return 0 on success, -1 on temporary error. Failure to
- * generate an extra-info document is not an error and is indicated by setting
- * e to NULL. Caller is responsible for freeing generated documents if 0 is
- * returned.
+/** Allocate a fresh, unsigned routerinfo for this OR, without any of the
+ * fields that depend on the corresponding extrainfo.
+ *
+ * On success, set ri_out to the new routerinfo, and return 0.
+ * Caller is responsible for freeing the generated routerinfo.
+ *
+ * Returns a negative value and sets ri_out to NULL on temporary error.
*/
-int
-router_build_fresh_descriptor(routerinfo_t **r, extrainfo_t **e)
+MOCK_IMPL(STATIC int,
+router_build_fresh_unsigned_routerinfo,(routerinfo_t **ri_out))
{
- routerinfo_t *ri;
- extrainfo_t *ei;
+ routerinfo_t *ri = NULL;
uint32_t addr;
char platform[256];
int hibernating = we_are_hibernating();
const or_options_t *options = get_options();
+ int result = TOR_ROUTERINFO_ERROR_INTERNAL_BUG;
+
+ if (BUG(!ri_out)) {
+ result = TOR_ROUTERINFO_ERROR_INTERNAL_BUG;
+ goto err;
+ }
if (router_pick_published_address(options, &addr, 0) < 0) {
log_warn(LD_CONFIG, "Don't know my address while generating descriptor");
- return TOR_ROUTERINFO_ERROR_NO_EXT_ADDR;
+ result = TOR_ROUTERINFO_ERROR_NO_EXT_ADDR;
+ goto err;
}
/* Log a message if the address in the descriptor doesn't match the ORPort
@@ -2017,8 +2027,8 @@ router_build_fresh_descriptor(routerinfo_t **r, extrainfo_t **e)
ri->identity_pkey = crypto_pk_dup_key(get_server_identity_key());
if (BUG(crypto_pk_get_digest(ri->identity_pkey,
ri->cache_info.identity_digest) < 0)) {
- routerinfo_free(ri);
- return TOR_ROUTERINFO_ERROR_DIGEST_FAILED;
+ result = TOR_ROUTERINFO_ERROR_DIGEST_FAILED;
+ goto err;
}
ri->cache_info.signing_key_cert =
tor_cert_dup(get_master_signing_key_cert());
@@ -2057,85 +2067,258 @@ router_build_fresh_descriptor(routerinfo_t **r, extrainfo_t **e)
ri->declared_family = get_my_declared_family(options);
+ if (options->BridgeRelay) {
+ ri->purpose = ROUTER_PURPOSE_BRIDGE;
+ /* Bridges shouldn't be able to send their descriptors unencrypted,
+ anyway, since they don't have a DirPort, and always connect to the
+ bridge authority anonymously. But just in case they somehow think of
+ sending them on an unencrypted connection, don't allow them to try. */
+ ri->cache_info.send_unencrypted = 0;
+ } else {
+ ri->purpose = ROUTER_PURPOSE_GENERAL;
+ ri->cache_info.send_unencrypted = 1;
+ }
+
+ goto done;
+
+ err:
+ routerinfo_free(ri);
+ *ri_out = NULL;
+ return result;
+
+ done:
+ *ri_out = ri;
+ return 0;
+}
+
+/** Allocate and return a fresh, unsigned extrainfo for this OR, based on the
+ * routerinfo ri.
+ *
+ * Uses options->Nickname to set the nickname, and options->BridgeRelay to set
+ * ei->cache_info.send_unencrypted.
+ *
+ * If ri is NULL, logs a BUG() warning and returns NULL.
+ * Caller is responsible for freeing the generated extrainfo.
+ */
+static extrainfo_t *
+router_build_fresh_unsigned_extrainfo(const routerinfo_t *ri)
+{
+ extrainfo_t *ei = NULL;
+ const or_options_t *options = get_options();
+
+ if (BUG(!ri))
+ return NULL;
+
/* Now generate the extrainfo. */
ei = tor_malloc_zero(sizeof(extrainfo_t));
ei->cache_info.is_extrainfo = 1;
- strlcpy(ei->nickname, get_options()->Nickname, sizeof(ei->nickname));
+ strlcpy(ei->nickname, options->Nickname, sizeof(ei->nickname));
ei->cache_info.published_on = ri->cache_info.published_on;
ei->cache_info.signing_key_cert =
tor_cert_dup(get_master_signing_key_cert());
memcpy(ei->cache_info.identity_digest, ri->cache_info.identity_digest,
DIGEST_LEN);
+
+ if (options->BridgeRelay) {
+ /* See note in router_build_fresh_routerinfo(). */
+ ei->cache_info.send_unencrypted = 0;
+ } else {
+ ei->cache_info.send_unencrypted = 1;
+ }
+
+ return ei;
+}
+
+/** Dump the extrainfo descriptor body for ei, sign it, and add the body and
+ * signature to ei->cache_info. Note that the extrainfo body is determined by
+ * ei, and some additional config and statistics state: see
+ * extrainfo_dump_to_string() for details.
+ *
+ * Return 0 on success, -1 on temporary error.
+ * If ei is NULL, logs a BUG() warning and returns -1.
+ * On error, ei->cache_info is not modified.
+ */
+static int
+router_dump_and_sign_extrainfo_descriptor_body(extrainfo_t *ei)
+{
+ if (BUG(!ei))
+ return -1;
+
if (extrainfo_dump_to_string(&ei->cache_info.signed_descriptor_body,
ei, get_server_identity_key(),
get_master_signing_keypair()) < 0) {
log_warn(LD_BUG, "Couldn't generate extra-info descriptor.");
- extrainfo_free(ei);
- ei = NULL;
- } else {
- ei->cache_info.signed_descriptor_len =
- strlen(ei->cache_info.signed_descriptor_body);
- router_get_extrainfo_hash(ei->cache_info.signed_descriptor_body,
- ei->cache_info.signed_descriptor_len,
- ei->cache_info.signed_descriptor_digest);
- crypto_digest256((char*) ei->digest256,
- ei->cache_info.signed_descriptor_body,
- ei->cache_info.signed_descriptor_len,
- DIGEST_SHA256);
+ return -1;
}
- /* Now finish the router descriptor. */
- if (ei) {
- memcpy(ri->cache_info.extra_info_digest,
- ei->cache_info.signed_descriptor_digest,
- DIGEST_LEN);
- memcpy(ri->cache_info.extra_info_digest256,
- ei->digest256,
- DIGEST256_LEN);
- } else {
- /* ri was allocated with tor_malloc_zero, so there is no need to
- * zero ri->cache_info.extra_info_digest here. */
+ ei->cache_info.signed_descriptor_len =
+ strlen(ei->cache_info.signed_descriptor_body);
+
+ router_get_extrainfo_hash(ei->cache_info.signed_descriptor_body,
+ ei->cache_info.signed_descriptor_len,
+ ei->cache_info.signed_descriptor_digest);
+ crypto_digest256((char*) ei->digest256,
+ ei->cache_info.signed_descriptor_body,
+ ei->cache_info.signed_descriptor_len,
+ DIGEST_SHA256);
+
+ return 0;
+}
+
+/** Allocate and return a fresh, signed extrainfo for this OR, based on the
+ * routerinfo ri.
+ *
+ * If ri is NULL, logs a BUG() warning and returns NULL.
+ * Caller is responsible for freeing the generated extrainfo.
+ */
+STATIC extrainfo_t *
+router_build_fresh_signed_extrainfo(const routerinfo_t *ri)
+{
+ int result = -1;
+ extrainfo_t *ei = NULL;
+
+ if (BUG(!ri))
+ return NULL;
+
+ ei = router_build_fresh_unsigned_extrainfo(ri);
+ /* router_build_fresh_unsigned_extrainfo() should not fail. */
+ if (BUG(!ei))
+ goto err;
+
+ result = router_dump_and_sign_extrainfo_descriptor_body(ei);
+ if (result < 0)
+ goto err;
+
+ goto done;
+
+ err:
+ extrainfo_free(ei);
+ return NULL;
+
+ done:
+ return ei;
+}
+
+/** Set the fields in ri that depend on ei.
+ *
+ * If ei is NULL, logs a BUG() warning and zeroes the relevant fields.
+ */
+STATIC void
+router_update_routerinfo_from_extrainfo(routerinfo_t *ri,
+ const extrainfo_t *ei)
+{
+ if (BUG(!ei)) {
+ /* Just to be safe, zero ri->cache_info.extra_info_digest here. */
+ memset(ri->cache_info.extra_info_digest, 0, DIGEST_LEN);
+ memset(ri->cache_info.extra_info_digest256, 0, DIGEST256_LEN);
+ return;
}
+
+ /* Now finish the router descriptor. */
+ memcpy(ri->cache_info.extra_info_digest,
+ ei->cache_info.signed_descriptor_digest,
+ DIGEST_LEN);
+ memcpy(ri->cache_info.extra_info_digest256,
+ ei->digest256,
+ DIGEST256_LEN);
+}
+
+/** Dump the descriptor body for ri, sign it, and add the body and signature to
+ * ri->cache_info. Note that the descriptor body is determined by ri, and some
+ * additional config and state: see router_dump_router_to_string() for details.
+ *
+ * Return 0 on success, and a negative value on temporary error.
+ * If ri is NULL, logs a BUG() warning and returns a negative value.
+ * On error, ri->cache_info is not modified.
+ */
+STATIC int
+router_dump_and_sign_routerinfo_descriptor_body(routerinfo_t *ri)
+{
+ if (BUG(!ri))
+ return TOR_ROUTERINFO_ERROR_INTERNAL_BUG;
+
if (! (ri->cache_info.signed_descriptor_body =
router_dump_router_to_string(ri, get_server_identity_key(),
get_onion_key(),
get_current_curve25519_keypair(),
get_master_signing_keypair())) ) {
log_warn(LD_BUG, "Couldn't generate router descriptor.");
- routerinfo_free(ri);
- extrainfo_free(ei);
return TOR_ROUTERINFO_ERROR_CANNOT_GENERATE;
}
+
ri->cache_info.signed_descriptor_len =
strlen(ri->cache_info.signed_descriptor_body);
- ri->purpose =
- options->BridgeRelay ? ROUTER_PURPOSE_BRIDGE : ROUTER_PURPOSE_GENERAL;
- if (options->BridgeRelay) {
- /* Bridges shouldn't be able to send their descriptors unencrypted,
- anyway, since they don't have a DirPort, and always connect to the
- bridge authority anonymously. But just in case they somehow think of
- sending them on an unencrypted connection, don't allow them to try. */
- ri->cache_info.send_unencrypted = 0;
- if (ei)
- ei->cache_info.send_unencrypted = 0;
- } else {
- ri->cache_info.send_unencrypted = 1;
- if (ei)
- ei->cache_info.send_unencrypted = 1;
- }
-
router_get_router_hash(ri->cache_info.signed_descriptor_body,
strlen(ri->cache_info.signed_descriptor_body),
ri->cache_info.signed_descriptor_digest);
+ return 0;
+}
+
+/** Build a fresh routerinfo, signed server descriptor, and signed extrainfo
+ * document for this OR.
+ *
+ * Set r to the generated routerinfo, e to the generated extrainfo document.
+ * Failure to generate an extra-info document is not an error and is indicated
+ * by setting e to NULL.
+ * Return 0 on success, and a negative value on temporary error.
+ * Caller is responsible for freeing generated documents on success.
+ */
+int
+router_build_fresh_descriptor(routerinfo_t **r, extrainfo_t **e)
+{
+ int result = TOR_ROUTERINFO_ERROR_INTERNAL_BUG;
+ routerinfo_t *ri = NULL;
+ extrainfo_t *ei = NULL;
+
+ if (BUG(!r))
+ goto err;
+
+ if (BUG(!e))
+ goto err;
+
+ result = router_build_fresh_unsigned_routerinfo(&ri);
+ if (result < 0) {
+ goto err;
+ }
+ /* If ri is NULL, then result should be negative. So this check should be
+ * unreachable. */
+ if (BUG(!ri)) {
+ result = TOR_ROUTERINFO_ERROR_INTERNAL_BUG;
+ goto err;
+ }
+
+ ei = router_build_fresh_signed_extrainfo(ri);
+
+ /* Failing to create an ei is not an error. */
+ if (ei) {
+ router_update_routerinfo_from_extrainfo(ri, ei);
+ }
+
+ result = router_dump_and_sign_routerinfo_descriptor_body(ri);
+ if (result < 0)
+ goto err;
+
if (ei) {
- tor_assert(!
- routerinfo_incompatible_with_extrainfo(ri->identity_pkey, ei,
- &ri->cache_info, NULL));
+ if (BUG(routerinfo_incompatible_with_extrainfo(ri->identity_pkey, ei,
+ &ri->cache_info, NULL))) {
+ result = TOR_ROUTERINFO_ERROR_INTERNAL_BUG;
+ goto err;
+ }
}
+ goto done;
+
+ err:
+ routerinfo_free(ri);
+ extrainfo_free(ei);
+ *r = NULL;
+ *e = NULL;
+ return result;
+
+ done:
*r = ri;
*e = ei;
return 0;
@@ -2478,6 +2661,10 @@ get_platform_str(char *platform, size_t len)
/** OR only: Given a routerinfo for this router, and an identity key to sign
* with, encode the routerinfo as a signed server descriptor and return a new
* string encoding the result, or NULL on failure.
+ *
+ * In addition to the fields in router, this function calls
+ * onion_key_lifetime(), get_options(), and we_are_hibernating(), and uses the
+ * results to populate some fields in the descriptor.
*/
char *
router_dump_router_to_string(routerinfo_t *router,
@@ -2930,9 +3117,14 @@ load_stats_file(const char *filename, const char *end_line, time_t now,
return r;
}
-/** Write the contents of <b>extrainfo</b> and aggregated statistics to
- * *<b>s_out</b>, signing them with <b>ident_key</b>. Return 0 on
- * success, negative on failure. */
+/** Write the contents of <b>extrainfo</b>, to * *<b>s_out</b>, signing them
+ * with <b>ident_key</b>.
+ *
+ * If ExtraInfoStatistics is 1, also write aggregated statistics and related
+ * configuration data before signing. Most statistics also have an option that
+ * enables or disables that particular statistic.
+ *
+ * Return 0 on success, negative on failure. */
int
extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo,
crypto_pk_t *ident_key,
@@ -2942,7 +3134,6 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo,
char identity[HEX_DIGEST_LEN+1];
char published[ISO_TIME_LEN+1];
char digest[DIGEST_LEN];
- char *bandwidth_usage;
int result;
static int write_stats_to_extrainfo = 1;
char sig[DIROBJ_MAX_SIG_LEN+1];
@@ -2957,7 +3148,6 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo,
base16_encode(identity, sizeof(identity),
extrainfo->cache_info.identity_digest, DIGEST_LEN);
format_iso_time(published, extrainfo->cache_info.published_on);
- bandwidth_usage = rep_hist_get_bandwidth_lines();
if (emit_ed_sigs) {
if (!extrainfo->cache_info.signing_key_cert->signing_key_included ||
!ed25519_pubkey_eq(&extrainfo->cache_info.signing_key_cert->signed_key,
@@ -2983,21 +3173,25 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo,
ed_cert_line = tor_strdup("");
}
- tor_asprintf(&pre, "extra-info %s %s\n%spublished %s\n%s",
+ tor_asprintf(&pre, "extra-info %s %s\n%spublished %s\n",
extrainfo->nickname, identity,
ed_cert_line,
- published, bandwidth_usage);
+ published);
smartlist_add(chunks, pre);
- if (geoip_is_loaded(AF_INET))
- smartlist_add_asprintf(chunks, "geoip-db-digest %s\n",
- geoip_db_digest(AF_INET));
- if (geoip_is_loaded(AF_INET6))
- smartlist_add_asprintf(chunks, "geoip6-db-digest %s\n",
- geoip_db_digest(AF_INET6));
-
if (options->ExtraInfoStatistics && write_stats_to_extrainfo) {
log_info(LD_GENERAL, "Adding stats to extra-info descriptor.");
+ /* Bandwidth usage stats don't have their own option */
+ {
+ contents = rep_hist_get_bandwidth_lines();
+ smartlist_add(chunks, contents);
+ }
+ if (geoip_is_loaded(AF_INET))
+ smartlist_add_asprintf(chunks, "geoip-db-digest %s\n",
+ geoip_db_digest(AF_INET));
+ if (geoip_is_loaded(AF_INET6))
+ smartlist_add_asprintf(chunks, "geoip6-db-digest %s\n",
+ geoip_db_digest(AF_INET6));
if (options->DirReqStatistics &&
load_stats_file("stats"PATH_SEPARATOR"dirreq-stats",
"dirreq-stats-end", now, &contents) > 0) {
@@ -3033,19 +3227,17 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo,
if (contents)
smartlist_add(chunks, contents);
}
- }
-
- /* Add information about the pluggable transports we support. */
- if (options->ServerTransportPlugin) {
- char *pluggable_transports = pt_get_extra_info_descriptor_string();
- if (pluggable_transports)
- smartlist_add(chunks, pluggable_transports);
- }
-
- if (should_record_bridge_info(options) && write_stats_to_extrainfo) {
- const char *bridge_stats = geoip_get_bridge_stats_extrainfo(now);
- if (bridge_stats) {
- smartlist_add_strdup(chunks, bridge_stats);
+ /* Add information about the pluggable transports we support. */
+ if (options->ServerTransportPlugin) {
+ char *pluggable_transports = pt_get_extra_info_descriptor_string();
+ if (pluggable_transports)
+ smartlist_add(chunks, pluggable_transports);
+ }
+ if (should_record_bridge_info(options)) {
+ const char *bridge_stats = geoip_get_bridge_stats_extrainfo(now);
+ if (bridge_stats) {
+ smartlist_add_strdup(chunks, bridge_stats);
+ }
}
}
@@ -3139,7 +3331,6 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo,
tor_free(s_dup);
tor_free(ed_cert_line);
extrainfo_free(ei_tmp);
- tor_free(bandwidth_usage);
return result;
}
diff --git a/src/feature/relay/router.h b/src/feature/relay/router.h
index 60bc857ceb..55b9ef9e68 100644
--- a/src/feature/relay/router.h
+++ b/src/feature/relay/router.h
@@ -23,11 +23,12 @@ struct ed25519_keypair_t;
#define TOR_ROUTERINFO_ERROR_DIGEST_FAILED (-4)
#define TOR_ROUTERINFO_ERROR_CANNOT_GENERATE (-5)
#define TOR_ROUTERINFO_ERROR_DESC_REBUILDING (-6)
+#define TOR_ROUTERINFO_ERROR_INTERNAL_BUG (-7)
-crypto_pk_t *get_onion_key(void);
+MOCK_DECL(crypto_pk_t *,get_onion_key,(void));
time_t get_onion_key_set_at(void);
void set_server_identity_key(crypto_pk_t *k);
-crypto_pk_t *get_server_identity_key(void);
+MOCK_DECL(crypto_pk_t *,get_server_identity_key,(void));
int server_identity_key_is_set(void);
void set_client_identity_key(crypto_pk_t *k);
crypto_pk_t *get_tlsclient_identity_key(void);
@@ -114,7 +115,7 @@ void router_reset_reachability(void);
void router_free_all(void);
#ifdef ROUTER_PRIVATE
-/* Used only by router.c and test.c */
+/* Used only by router.c and the unit tests */
STATIC void get_platform_str(char *platform, size_t len);
STATIC int router_write_fingerprint(int hashed);
STATIC smartlist_t *get_my_declared_family(const or_options_t *options);
@@ -123,8 +124,18 @@ STATIC smartlist_t *get_my_declared_family(const or_options_t *options);
extern time_t desc_clean_since;
extern const char *desc_dirty_reason;
void set_server_identity_key_digest_testing(const uint8_t *digest);
-#endif
-
-#endif
+MOCK_DECL(STATIC const struct curve25519_keypair_t *,
+ get_current_curve25519_keypair,(void));
+
+MOCK_DECL(STATIC int,
+ router_build_fresh_unsigned_routerinfo,(routerinfo_t **ri_out));
+STATIC extrainfo_t *router_build_fresh_signed_extrainfo(
+ const routerinfo_t *ri);
+STATIC void router_update_routerinfo_from_extrainfo(routerinfo_t *ri,
+ const extrainfo_t *ei);
+STATIC int router_dump_and_sign_routerinfo_descriptor_body(routerinfo_t *ri);
+#endif /* defined(TOR_UNIT_TESTS) */
+
+#endif /* defined(ROUTER_PRIVATE) */
#endif /* !defined(TOR_ROUTER_H) */
diff --git a/src/feature/relay/routerkeys.c b/src/feature/relay/routerkeys.c
index 876f908d41..d965777ad6 100644
--- a/src/feature/relay/routerkeys.c
+++ b/src/feature/relay/routerkeys.c
@@ -631,14 +631,14 @@ get_master_identity_keypair(void)
}
#endif /* defined(TOR_UNIT_TESTS) */
-const ed25519_keypair_t *
-get_master_signing_keypair(void)
+MOCK_IMPL(const ed25519_keypair_t *,
+get_master_signing_keypair,(void))
{
return master_signing_key;
}
-const struct tor_cert_st *
-get_master_signing_key_cert(void)
+MOCK_IMPL(const struct tor_cert_st *,
+get_master_signing_key_cert,(void))
{
return signing_key_cert;
}
@@ -706,6 +706,8 @@ make_tap_onion_key_crosscert(const crypto_pk_t *onion_key,
*len_out = 0;
if (crypto_pk_get_digest(rsa_id_key, (char*)signed_data) < 0) {
+ log_info(LD_OR, "crypto_pk_get_digest failed in "
+ "make_tap_onion_key_crosscert!");
return NULL;
}
memcpy(signed_data + DIGEST_LEN, master_id_key->pubkey, ED25519_PUBKEY_LEN);
@@ -713,8 +715,12 @@ make_tap_onion_key_crosscert(const crypto_pk_t *onion_key,
int r = crypto_pk_private_sign(onion_key,
(char*)signature, sizeof(signature),
(const char*)signed_data, sizeof(signed_data));
- if (r < 0)
+ if (r < 0) {
+ /* It's probably missing the private key */
+ log_info(LD_OR, "crypto_pk_private_sign failed in "
+ "make_tap_onion_key_crosscert!");
return NULL;
+ }
*len_out = r;
diff --git a/src/feature/relay/routerkeys.h b/src/feature/relay/routerkeys.h
index 0badd34191..cde07b52c3 100644
--- a/src/feature/relay/routerkeys.h
+++ b/src/feature/relay/routerkeys.h
@@ -7,8 +7,8 @@
#include "lib/crypt_ops/crypto_ed25519.h"
const ed25519_public_key_t *get_master_identity_key(void);
-const ed25519_keypair_t *get_master_signing_keypair(void);
-const struct tor_cert_st *get_master_signing_key_cert(void);
+MOCK_DECL(const ed25519_keypair_t *, get_master_signing_keypair,(void));
+MOCK_DECL(const struct tor_cert_st *, get_master_signing_key_cert,(void));
const ed25519_keypair_t *get_current_auth_keypair(void);
const struct tor_cert_st *get_current_link_cert_cert(void);
diff --git a/src/lib/cc/torint.h b/src/lib/cc/torint.h
index c9b2d329f2..9a66aada18 100644
--- a/src/lib/cc/torint.h
+++ b/src/lib/cc/torint.h
@@ -125,4 +125,13 @@ typedef int32_t ssize_t;
/** Any size_t larger than this amount is likely to be an underflow. */
#define SIZE_T_CEILING ((size_t)(SSIZE_MAX-16))
+#if SIZEOF_INT > SIZEOF_VOID_P
+#error "sizeof(int) > sizeof(void *) - Tor cannot be built on this platform!"
+#endif
+
+#if SIZEOF_UNSIGNED_INT > SIZEOF_VOID_P
+#error "sizeof(unsigned int) > sizeof(void *) - Tor cannot be built on this \
+platform!"
+#endif
+
#endif /* !defined(TOR_TORINT_H) */
diff --git a/src/lib/math/prob_distr.h b/src/lib/math/prob_distr.h
index 66acb796fd..2eb935e4a8 100644
--- a/src/lib/math/prob_distr.h
+++ b/src/lib/math/prob_distr.h
@@ -19,10 +19,100 @@ struct dist {
const struct dist_ops *ops;
};
+/**
+ * Untyped initializer element for struct dist using the specified
+ * struct dist_ops pointer. Don't actually use this directly -- use
+ * the type-specific macro built out of DIST_BASE_TYPED below -- but if
+ * you did use this directly, it would be something like:
+ *
+ * struct weibull mydist = {
+ * DIST_BASE(&weibull_ops),
+ * .lambda = ...,
+ * .k = ...,
+ * };
+ *
+ * Note there is NO COMPILER FEEDBACK if you accidentally do something
+ * like
+ *
+ * struct geometric mydist = {
+ * DIST_BASE(&weibull_ops),
+ * ...
+ * };
+ */
#define DIST_BASE(OPS) { .ops = (OPS) }
+
+/** A compile-time type-checking macro for use with DIST_BASE_TYPED.
+ *
+ * This macro works by checking that &OBJ is a pointer type that is the same
+ * type (except for qualifiers) as (const TYPE *)&OBJ. It's a C constraint
+ * violation (which requires a diagnostic) if two pointers are different types
+ * and are subtracted. The sizeof() forces compile-time evaluation, and the
+ * multiplication by zero is to discard the result of the sizeof() from the
+ * expression.
+ *
+ * We define this conditionally to suppress false positives from
+ * Coverity, which gets confused by the sizeof business.
+ */
+#ifdef __COVERITY___
+#define TYPE_CHECK_OBJ(OPS, OBJ, TYPE) 0
+#else
+#define TYPE_CHECK_OBJ(OPS, OBJ, TYPE) \
+ (0*sizeof(&(OBJ) - (const TYPE *)&(OBJ)))
+#endif
+
+/**
+* Typed initializer element for struct dist using the specified struct
+* dist_ops pointer. Don't actually use this directly -- use a
+* type-specific macro built out of it -- but if you did use this
+* directly, it would be something like:
+*
+* struct weibull mydist = {
+* DIST_BASE_TYPED(&weibull_ops, mydist, struct weibull),
+* .lambda = ...,
+* .k = ...,
+* };
+*
+* If you want to define a distribution type, define a canonical set of
+* operations and define a type-specific initializer element like so:
+*
+* struct foo {
+* struct dist base;
+* int omega;
+* double tau;
+* double phi;
+* };
+*
+* struct dist_ops foo_ops = ...;
+*
+* #define FOO(OBJ) DIST_BASE_TYPED(&foo_ops, OBJ, struct foo)
+*
+* Then users can do:
+*
+* struct foo mydist = {
+* FOO(mydist),
+* .omega = ...,
+* .tau = ...,
+* .phi = ...,
+* };
+*
+* If you accidentally write
+*
+* struct bar mydist = {
+* FOO(mydist),
+* ...
+* };
+*
+* then the compiler will report a type mismatch in the sizeof
+* expression, which otherwise evaporates at runtime.
+*/
#define DIST_BASE_TYPED(OPS, OBJ, TYPE) \
- DIST_BASE((OPS) + 0*sizeof(&(OBJ) - (const TYPE *)&(OBJ)))
+ DIST_BASE((OPS) + TYPE_CHECK_OBJ(OPS,OBJ,TYPE))
+/**
+ * Generic operations on distributions. These simply defer to the
+ * corresponding dist_ops function. In the parlance of C++, these call
+ * virtual member functions.
+ */
const char *dist_name(const struct dist *);
double dist_sample(const struct dist *);
double dist_cdf(const struct dist *, double x);
@@ -30,6 +120,11 @@ double dist_sf(const struct dist *, double x);
double dist_icdf(const struct dist *, double p);
double dist_isf(const struct dist *, double p);
+/**
+ * Set of operations on a potentially parametric family of
+ * distributions. In the parlance of C++, this would be called a
+ * `vtable' and the members are virtual member functions.
+ */
struct dist_ops {
const char *name;
double (*sample)(const struct dist *);
diff --git a/src/test/include.am b/src/test/include.am
index d585c2a38a..700107d6ce 100644
--- a/src/test/include.am
+++ b/src/test/include.am
@@ -211,6 +211,8 @@ src_test_test_slow_SOURCES += \
src/test/test_crypto_slow.c \
src/test/test_process_slow.c \
src/test/test_prob_distr.c \
+ src/test/ptr_helpers.c \
+ src/test/test_ptr_slow.c \
src/test/testing_common.c \
src/test/testing_rsakeys.c \
src/ext/tinytest.c
@@ -314,6 +316,7 @@ noinst_HEADERS+= \
src/test/log_test_helpers.h \
src/test/rend_test_helpers.h \
src/test/test.h \
+ src/test/ptr_helpers.h \
src/test/test_helpers.h \
src/test/test_dir_common.h \
src/test/test_connection.h \
diff --git a/src/test/ptr_helpers.c b/src/test/ptr_helpers.c
new file mode 100644
index 0000000000..296238feeb
--- /dev/null
+++ b/src/test/ptr_helpers.c
@@ -0,0 +1,50 @@
+/* Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "ptr_helpers.h"
+
+/**
+ * Cast <b> (inptr_t value) to a void pointer.
+ */
+void *
+cast_intptr_to_voidstar(intptr_t x)
+{
+ void *r = (void *)x;
+
+ return r;
+}
+
+/**
+ * Cast x (void pointer) to inptr_t value.
+ */
+intptr_t
+cast_voidstar_to_intptr(void *x)
+{
+ intptr_t r = (intptr_t)x;
+
+ return r;
+}
+
+/**
+ * Cast x (uinptr_t value) to void pointer.
+ */
+void *
+cast_uintptr_to_voidstar(uintptr_t x)
+{
+ void *r = (void *)x;
+
+ return r;
+}
+
+/**
+ * Cast x (void pointer) to uinptr_t value.
+ */
+uintptr_t
+cast_voidstar_to_uintptr(void *x)
+{
+ uintptr_t r = (uintptr_t)x;
+
+ return r;
+}
diff --git a/src/test/ptr_helpers.h b/src/test/ptr_helpers.h
new file mode 100644
index 0000000000..67776b1006
--- /dev/null
+++ b/src/test/ptr_helpers.h
@@ -0,0 +1,23 @@
+/* Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_PTR_HELPERS_H
+#define TOR_PTR_HELPERS_H
+
+#include <stdint.h>
+
+void *
+cast_intptr_to_voidstar(intptr_t x);
+
+intptr_t
+cast_voidstar_to_intptr(void *x);
+
+void *
+cast_uintptr_to_voidstar(uintptr_t x);
+
+uintptr_t
+cast_voidstar_to_uintptr(void *x);
+
+#endif
diff --git a/src/test/test.h b/src/test/test.h
index 2564432985..9d9184e2aa 100644
--- a/src/test/test.h
+++ b/src/test/test.h
@@ -278,6 +278,7 @@ extern struct testcase_t x509_tests[];
extern struct testcase_t slow_crypto_tests[];
extern struct testcase_t slow_process_tests[];
+extern struct testcase_t slow_ptr_tests[];
extern struct testgroup_t testgroups[];
diff --git a/src/test/test_dir.c b/src/test/test_dir.c
index bb8c8970ea..6518977b6f 100644
--- a/src/test/test_dir.c
+++ b/src/test/test_dir.c
@@ -162,6 +162,269 @@ test_dir_nicknames(void *arg)
;
}
+/* Allocate and return a new routerinfo, with the fields set from the
+ * arguments to this function.
+ *
+ * Also sets:
+ * - random RSA identity and onion keys,
+ * - the platform field using get_platform_str(), and
+ * - supports_tunnelled_dir_requests to 1.
+ *
+ * If rsa_onion_keypair_out is not NULL, it is set to the onion keypair.
+ * The caller must free this keypair.
+ */
+static routerinfo_t *
+basic_routerinfo_new(const char *nickname, uint32_t ipv4_addr,
+ uint16_t or_port, uint16_t dir_port,
+ uint32_t bandwidthrate, uint32_t bandwidthburst,
+ uint32_t bandwidthcapacity,
+ time_t published_on,
+ crypto_pk_t **rsa_onion_keypair_out)
+{
+ char platform[256];
+
+ tor_assert(nickname);
+
+ crypto_pk_t *pk1 = NULL, *pk2 = NULL;
+ /* These keys are random: idx is ignored. */
+ pk1 = pk_generate(0);
+ pk2 = pk_generate(1);
+
+ tor_assert(pk1);
+ tor_assert(pk2);
+
+ get_platform_str(platform, sizeof(platform));
+
+ routerinfo_t *r1 = tor_malloc_zero(sizeof(routerinfo_t));
+
+ r1->nickname = tor_strdup(nickname);
+ r1->platform = tor_strdup(platform);
+
+ r1->addr = ipv4_addr;
+ r1->or_port = or_port;
+ r1->dir_port = dir_port;
+ r1->supports_tunnelled_dir_requests = 1;
+
+ router_set_rsa_onion_pkey(pk1, &r1->onion_pkey, &r1->onion_pkey_len);
+ r1->identity_pkey = pk2;
+
+ r1->bandwidthrate = bandwidthrate;
+ r1->bandwidthburst = bandwidthburst;
+ r1->bandwidthcapacity = bandwidthcapacity;
+
+ r1->cache_info.published_on = published_on;
+
+ if (rsa_onion_keypair_out) {
+ *rsa_onion_keypair_out = pk1;
+ } else {
+ crypto_pk_free(pk1);
+ }
+
+ return r1;
+}
+
+/* Allocate and return a new string containing a "router" line for r1. */
+static char *
+get_new_router_line(const routerinfo_t *r1)
+{
+ char *line = NULL;
+
+ tor_assert(r1);
+
+ tor_asprintf(&line,
+ "router %s %s %d 0 %d\n",
+ r1->nickname, fmt_addr32(r1->addr),
+ r1->or_port, r1->dir_port);
+ tor_assert(line);
+
+ return line;
+}
+
+/* Allocate and return a new string containing a "platform" line for the
+ * current Tor version and OS. */
+static char *
+get_new_platform_line(void)
+{
+ char *line = NULL;
+
+ tor_asprintf(&line,
+ "platform Tor %s on %s\n",
+ VERSION, get_uname());
+ tor_assert(line);
+
+ return line;
+}
+
+/* Allocate and return a new string containing a "published" line for r1.
+ * r1->cache_info.published_on must be between 0 and 59 seconds. */
+static char *
+get_new_published_line(const routerinfo_t *r1)
+{
+ char *line = NULL;
+
+ tor_assert(r1);
+
+ tor_assert(r1->cache_info.published_on >= 0);
+ tor_assert(r1->cache_info.published_on <= 59);
+
+ tor_asprintf(&line,
+ "published 1970-01-01 00:00:%02u\n",
+ (unsigned)r1->cache_info.published_on);
+ tor_assert(line);
+
+ return line;
+}
+
+/* Allocate and return a new string containing a "fingerprint" line for r1. */
+static char *
+get_new_fingerprint_line(const routerinfo_t *r1)
+{
+ char *line = NULL;
+ char fingerprint[FINGERPRINT_LEN+1];
+
+ tor_assert(r1);
+
+ tor_assert(!crypto_pk_get_fingerprint(r1->identity_pkey, fingerprint, 1));
+ tor_assert(strlen(fingerprint) > 0);
+
+ tor_asprintf(&line,
+ "fingerprint %s\n",
+ fingerprint);
+ tor_assert(line);
+
+ return line;
+}
+
+/* Allocate and return a new string containing an "uptime" line with uptime t.
+ *
+ * You should pass a hard-coded value to this function, because even if we made
+ * it reflect uptime, that still wouldn't make it right, because the two
+ * descriptors might be made on different seconds.
+ */
+static char *
+get_new_uptime_line(time_t t)
+{
+ char *line = NULL;
+
+ tor_asprintf(&line,
+ "uptime %u\n",
+ (unsigned)t);
+ tor_assert(line);
+
+ return line;
+}
+
+/* Allocate and return a new string containing an "bandwidth" line for r1.
+ */
+static char *
+get_new_bandwidth_line(const routerinfo_t *r1)
+{
+ char *line = NULL;
+
+ tor_assert(r1);
+
+ tor_asprintf(&line,
+ "bandwidth %u %u %u\n",
+ r1->bandwidthrate,
+ r1->bandwidthburst,
+ r1->bandwidthcapacity);
+ tor_assert(line);
+
+ return line;
+}
+
+/* Allocate and return a new string containing a key_name block for the
+ * RSA key pk1.
+ */
+static char *
+get_new_rsa_key_block(const char *key_name, crypto_pk_t *pk1)
+{
+ char *block = NULL;
+ char *pk1_str = NULL;
+ size_t pk1_str_len = 0;
+
+ tor_assert(key_name);
+ tor_assert(pk1);
+
+ tor_assert(!crypto_pk_write_public_key_to_string(pk1, &pk1_str,
+ &pk1_str_len));
+ tor_assert(pk1_str);
+ tor_assert(pk1_str_len);
+
+ tor_asprintf(&block,
+ "%s\n%s",
+ key_name,
+ pk1_str);
+ tor_free(pk1_str);
+
+ tor_assert(block);
+ return block;
+}
+
+/* Allocate and return a new string containing an "onion-key" block for the
+ * router r1.
+ */
+static char *
+get_new_onion_key_block(const routerinfo_t *r1)
+{
+ char *block = NULL;
+ tor_assert(r1);
+ crypto_pk_t *pk_tmp = router_get_rsa_onion_pkey(r1->onion_pkey,
+ r1->onion_pkey_len);
+ block = get_new_rsa_key_block("onion-key", pk_tmp);
+ crypto_pk_free(pk_tmp);
+ return block;
+}
+
+/* Allocate and return a new string containing an "signing-key" block for the
+ * router r1.
+ */
+static char *
+get_new_signing_key_block(const routerinfo_t *r1)
+{
+ tor_assert(r1);
+ return get_new_rsa_key_block("signing-key", r1->identity_pkey);
+}
+
+/* Allocate and return a new string containing an "ntor-onion-key" line for
+ * the curve25519 public key ntor_onion_pubkey.
+ */
+static char *
+get_new_ntor_onion_key_line(const curve25519_public_key_t *ntor_onion_pubkey)
+{
+ char *line = NULL;
+ char cert_buf[256];
+ int rv = 0;
+
+ tor_assert(ntor_onion_pubkey);
+
+ rv = base64_encode(cert_buf, sizeof(cert_buf),
+ (const char*)ntor_onion_pubkey->public_key, 32,
+ BASE64_ENCODE_MULTILINE);
+ tor_assert(rv > 0);
+ tor_assert(strlen(cert_buf) > 0);
+
+ tor_asprintf(&line,
+ "ntor-onion-key %s",
+ cert_buf);
+ tor_assert(line);
+
+ return line;
+}
+
+/* Allocate and return a new string containing a "bridge-distribution-request"
+ * line for options.
+ */
+static char *
+get_new_bridge_distribution_request_line(const or_options_t *options)
+{
+ if (options->BridgeRelay) {
+ return tor_strdup("bridge-distribution-request any\n");
+ } else {
+ return tor_strdup("");
+ }
+}
+
static smartlist_t *mocked_configured_ports = NULL;
/** Returns mocked_configured_ports */
@@ -171,71 +434,510 @@ mock_get_configured_ports(void)
return mocked_configured_ports;
}
-/** Run unit tests for router descriptor generation logic. */
+static tor_cert_t *
+mock_tor_cert_dup_null(const tor_cert_t *cert)
+{
+ (void)cert;
+ return NULL;
+}
+
+static crypto_pk_t *mocked_server_identitykey = NULL;
+
+/* Returns mocked_server_identitykey with no checks. */
+static crypto_pk_t *
+mock_get_server_identity_key(void)
+{
+ return mocked_server_identitykey;
+}
+
+static crypto_pk_t *mocked_onionkey = NULL;
+
+/* Returns mocked_onionkey with no checks. */
+static crypto_pk_t *
+mock_get_onion_key(void)
+{
+ return mocked_onionkey;
+}
+
+static routerinfo_t *mocked_routerinfo = NULL;
+
+/* Returns 0 and sets ri_out to mocked_routerinfo.
+ * ri_out must not be NULL. There are no other checks. */
+static int
+mock_router_build_fresh_unsigned_routerinfo(routerinfo_t **ri_out)
+{
+ tor_assert(ri_out);
+ *ri_out = mocked_routerinfo;
+ return 0;
+}
+
+static ed25519_keypair_t *mocked_master_signing_key = NULL;
+
+/* Returns mocked_master_signing_key with no checks. */
+static const ed25519_keypair_t *
+mock_get_master_signing_keypair(void)
+{
+ return mocked_master_signing_key;
+}
+
+static struct tor_cert_st *mocked_signing_key_cert = NULL;
+
+/* Returns mocked_signing_key_cert with no checks. */
+static const struct tor_cert_st *
+mock_get_master_signing_key_cert(void)
+{
+ return mocked_signing_key_cert;
+}
+
+static curve25519_keypair_t *mocked_curve25519_onion_key = NULL;
+
+/* Returns mocked_curve25519_onion_key with no checks. */
+static const curve25519_keypair_t *
+mock_get_current_curve25519_keypair(void)
+{
+ return mocked_curve25519_onion_key;
+}
+
+/* Unmock get_configured_ports() and free mocked_configured_ports. */
+static void
+cleanup_mock_configured_ports(void)
+{
+ UNMOCK(get_configured_ports);
+
+ if (mocked_configured_ports) {
+ SMARTLIST_FOREACH(mocked_configured_ports, port_cfg_t *, p, tor_free(p));
+ smartlist_free(mocked_configured_ports);
+ }
+}
+
+/* Mock get_configured_ports() with a list containing or_port and dir_port.
+ * If a port is 0, don't set it.
+ * Only sets the minimal data required for the tests to pass. */
+static void
+setup_mock_configured_ports(uint16_t or_port, uint16_t dir_port)
+{
+ cleanup_mock_configured_ports();
+
+ /* Fake just enough of an ORPort and DirPort to get by */
+ MOCK(get_configured_ports, mock_get_configured_ports);
+ mocked_configured_ports = smartlist_new();
+
+ if (or_port) {
+ port_cfg_t *or_port_cfg = tor_malloc_zero(sizeof(*or_port_cfg));
+ or_port_cfg->type = CONN_TYPE_OR_LISTENER;
+ or_port_cfg->addr.family = AF_INET;
+ or_port_cfg->port = or_port;
+ smartlist_add(mocked_configured_ports, or_port_cfg);
+ }
+
+ if (dir_port) {
+ port_cfg_t *dir_port_cfg = tor_malloc_zero(sizeof(*dir_port_cfg));
+ dir_port_cfg->type = CONN_TYPE_DIR_LISTENER;
+ dir_port_cfg->addr.family = AF_INET;
+ dir_port_cfg->port = dir_port;
+ smartlist_add(mocked_configured_ports, dir_port_cfg);
+ }
+}
+
+/* Clean up the data structures and unmock the functions needed for generating
+ * a fresh descriptor. */
+static void
+cleanup_mocks_for_fresh_descriptor(void)
+{
+ tor_free(get_options_mutable()->Nickname);
+
+ mocked_server_identitykey = NULL;
+ UNMOCK(get_server_identity_key);
+
+ crypto_pk_free(mocked_onionkey);
+ UNMOCK(get_onion_key);
+}
+
+/* Mock the data structures and functions needed for generating a fresh
+ * descriptor.
+ *
+ * Sets options->Nickname from r1->nickname.
+ * Mocks get_server_identity_key() with r1->identity_pkey.
+ *
+ * If rsa_onion_keypair is not NULL, it is used to mock get_onion_key().
+ * Otherwise, the public key in r1->onion_pkey is used to mock get_onion_key().
+ */
+static void
+setup_mocks_for_fresh_descriptor(const routerinfo_t *r1,
+ crypto_pk_t *rsa_onion_keypair)
+{
+ cleanup_mocks_for_fresh_descriptor();
+
+ tor_assert(r1);
+
+ /* router_build_fresh_signed_extrainfo() requires options->Nickname */
+ get_options_mutable()->Nickname = tor_strdup(r1->nickname);
+
+ /* router_build_fresh_signed_extrainfo() requires get_server_identity_key().
+ * Use the same one as the call to router_dump_router_to_string() above.
+ */
+ mocked_server_identitykey = r1->identity_pkey;
+ MOCK(get_server_identity_key, mock_get_server_identity_key);
+
+ /* router_dump_and_sign_routerinfo_descriptor_body() requires
+ * get_onion_key(). Use the same one as r1.
+ */
+ if (rsa_onion_keypair) {
+ mocked_onionkey = crypto_pk_dup_key(rsa_onion_keypair);
+ } else {
+ mocked_onionkey = router_get_rsa_onion_pkey(r1->onion_pkey,
+ r1->onion_pkey_len);
+ }
+ MOCK(get_onion_key, mock_get_onion_key);
+}
+
+/* Set options based on arg.
+ *
+ * b: BridgeRelay 1
+ * e: ExtraInfoStatistics 1
+ * s: sets all the individual statistics options to 1
+ *
+ * Always sets AssumeReachable to 1.
+ *
+ * Does not set ServerTransportPlugin, because it's parsed before use.
+ *
+ * Does not set BridgeRecordUsageByCountry, because the tests don't have access
+ * to a GeoIPFile or GeoIPv6File. */
static void
-test_dir_formats(void *arg)
+setup_dir_formats_options(const char *arg, or_options_t *options)
+{
+ /* Skip reachability checks for DirPort, ORPort, and tunnelled-dir-server */
+ options->AssumeReachable = 1;
+
+ if (strchr(arg, 'b')) {
+ options->BridgeRelay = 1;
+ }
+
+ if (strchr(arg, 'e')) {
+ options->ExtraInfoStatistics = 1;
+ }
+
+ if (strchr(arg, 's')) {
+ options->DirReqStatistics = 1;
+ options->HiddenServiceStatistics = 1;
+ options->EntryStatistics = 1;
+ options->CellStatistics = 1;
+ options->ExitPortStatistics = 1;
+ options->ConnDirectionStatistics = 1;
+ options->PaddingStatistics = 1;
+ }
+}
+
+/* Check that routerinfos r1 and rp1 are consistent.
+ * Only performs some basic checks.
+ */
+#define CHECK_ROUTERINFO_CONSISTENCY(r1, rp1) \
+STMT_BEGIN \
+ tt_assert(r1); \
+ tt_assert(rp1); \
+\
+ tt_int_op(rp1->addr,OP_EQ, r1->addr); \
+ tt_int_op(rp1->or_port,OP_EQ, r1->or_port); \
+ tt_int_op(rp1->dir_port,OP_EQ, r1->dir_port); \
+ tt_int_op(rp1->bandwidthrate,OP_EQ, r1->bandwidthrate); \
+ tt_int_op(rp1->bandwidthburst,OP_EQ, r1->bandwidthburst); \
+ tt_int_op(rp1->bandwidthcapacity,OP_EQ, r1->bandwidthcapacity); \
+ crypto_pk_t *rp1_onion_pkey = router_get_rsa_onion_pkey(rp1->onion_pkey, \
+ rp1->onion_pkey_len); \
+ crypto_pk_t *r1_onion_pkey = router_get_rsa_onion_pkey(r1->onion_pkey, \
+ r1->onion_pkey_len); \
+ tt_int_op(crypto_pk_cmp_keys(rp1_onion_pkey, r1_onion_pkey), OP_EQ, 0); \
+ crypto_pk_free(rp1_onion_pkey); \
+ crypto_pk_free(r1_onion_pkey); \
+ tt_int_op(crypto_pk_cmp_keys(rp1->identity_pkey, r1->identity_pkey), \
+ OP_EQ, 0); \
+ tt_int_op(rp1->supports_tunnelled_dir_requests, OP_EQ, \
+ r1->supports_tunnelled_dir_requests); \
+STMT_END
+
+/* Check that routerinfo r1 and extrainfo e1 are consistent.
+ * Only performs some basic checks.
+ */
+#define CHECK_EXTRAINFO_CONSISTENCY(r1, e1) \
+STMT_BEGIN \
+ tt_assert(r1); \
+ tt_assert(e1); \
+\
+ tt_str_op(e1->nickname, OP_EQ, r1->nickname); \
+STMT_END
+
+/** Run unit tests for router descriptor generation logic for a RSA-only
+ * router. Tor versions without ed25519 (0.2.6 and earlier) are no longer
+ * officially supported, but the authorities still accept their descriptors.
+ */
+static void
+test_dir_formats_rsa(void *arg)
{
char *buf = NULL;
- char buf2[8192];
- char platform[256];
- char fingerprint[FINGERPRINT_LEN+1];
- char *pk1_str = NULL, *pk2_str = NULL, *cp;
- size_t pk1_str_len, pk2_str_len;
- routerinfo_t *r1=NULL, *r2=NULL;
- crypto_pk_t *pk1 = NULL, *pk2 = NULL;
- routerinfo_t *rp1 = NULL, *rp2 = NULL;
- addr_policy_t *ex1, *ex2;
- routerlist_t *dir1 = NULL, *dir2 = NULL;
+ char *buf2 = NULL;
+ char *cp = NULL;
+
uint8_t *rsa_cc = NULL;
- or_options_t *options = get_options_mutable();
- const addr_policy_t *p;
- time_t now = time(NULL);
- port_cfg_t orport, dirport;
- char cert_buf[256];
- (void)arg;
- pk1 = pk_generate(0);
- pk2 = pk_generate(1);
+ routerinfo_t *r1 = NULL;
+ extrainfo_t *e1 = NULL;
+ routerinfo_t *rp1 = NULL;
+ extrainfo_t *ep1 = NULL;
- tt_assert(pk1 && pk2);
+ smartlist_t *chunks = NULL;
+ const char *msg = NULL;
+ int rv = -1;
+
+ or_options_t *options = get_options_mutable();
+ setup_dir_formats_options((const char *)arg, options);
hibernate_set_state_for_testing_(HIBERNATE_STATE_LIVE);
- get_platform_str(platform, sizeof(platform));
- r1 = tor_malloc_zero(sizeof(routerinfo_t));
- r1->addr = 0xc0a80001u; /* 192.168.0.1 */
- r1->cache_info.published_on = 0;
- r1->or_port = 9000;
- r1->dir_port = 9003;
- r1->supports_tunnelled_dir_requests = 1;
- tor_addr_parse(&r1->ipv6_addr, "1:2:3:4::");
- r1->ipv6_orport = 9999;
- router_set_rsa_onion_pkey(pk1, &r1->onion_pkey, &r1->onion_pkey_len);
- /* Fake just enough of an ntor key to get by */
+ /* r1 is a minimal, RSA-only descriptor, with DirPort and IPv6 */
+ r1 = basic_routerinfo_new("Magri", 0xc0a80001u /* 192.168.0.1 */,
+ 9000, 9003,
+ 1000, 5000, 10000,
+ 0,
+ NULL);
+
+ /* Fake just enough of an ntor key to get by */
curve25519_keypair_t r1_onion_keypair;
curve25519_keypair_generate(&r1_onion_keypair, 0);
r1->onion_curve25519_pkey = tor_memdup(&r1_onion_keypair.pubkey,
sizeof(curve25519_public_key_t));
- r1->identity_pkey = crypto_pk_dup_key(pk2);
- r1->bandwidthrate = 1000;
- r1->bandwidthburst = 5000;
- r1->bandwidthcapacity = 10000;
+
+ /* Now add IPv6 */
+ tor_addr_parse(&r1->ipv6_addr, "1:2:3:4::");
+ r1->ipv6_orport = 9999;
+
r1->exit_policy = NULL;
- r1->nickname = tor_strdup("Magri");
- r1->platform = tor_strdup(platform);
- ex1 = tor_malloc_zero(sizeof(addr_policy_t));
- ex2 = tor_malloc_zero(sizeof(addr_policy_t));
- ex1->policy_type = ADDR_POLICY_ACCEPT;
- tor_addr_from_ipv4h(&ex1->addr, 0);
- ex1->maskbits = 0;
- ex1->prt_min = ex1->prt_max = 80;
- ex2->policy_type = ADDR_POLICY_REJECT;
- tor_addr_from_ipv4h(&ex2->addr, 18<<24);
- ex2->maskbits = 8;
- ex2->prt_min = ex2->prt_max = 24;
- r2 = tor_malloc_zero(sizeof(routerinfo_t));
- r2->addr = 0x0a030201u; /* 10.3.2.1 */
+ /* XXXX+++ router_dump_to_string should really take this from ri. */
+ options->ContactInfo = tor_strdup("Magri White "
+ "<magri@elsewhere.example.com>");
+
+ setup_mock_configured_ports(r1->or_port, r1->dir_port);
+
+ buf = router_dump_router_to_string(r1, r1->identity_pkey, NULL, NULL, NULL);
+ tt_assert(buf);
+
+ tor_free(options->ContactInfo);
+ cleanup_mock_configured_ports();
+
+ /* Synthesise a router descriptor, without the signature */
+ chunks = smartlist_new();
+
+ smartlist_add(chunks, get_new_router_line(r1));
+ smartlist_add_strdup(chunks, "or-address [1:2:3:4::]:9999\n");
+
+ smartlist_add(chunks, get_new_platform_line());
+ smartlist_add(chunks, get_new_published_line(r1));
+ smartlist_add(chunks, get_new_fingerprint_line(r1));
+
+ smartlist_add(chunks, get_new_uptime_line(0));
+ smartlist_add(chunks, get_new_bandwidth_line(r1));
+
+ smartlist_add(chunks, get_new_onion_key_block(r1));
+ smartlist_add(chunks, get_new_signing_key_block(r1));
+
+ smartlist_add_strdup(chunks, "hidden-service-dir\n");
+
+ smartlist_add_strdup(chunks, "contact Magri White "
+ "<magri@elsewhere.example.com>\n");
+
+ smartlist_add(chunks, get_new_bridge_distribution_request_line(options));
+ smartlist_add(chunks, get_new_ntor_onion_key_line(&r1_onion_keypair.pubkey));
+ smartlist_add_strdup(chunks, "reject *:*\n");
+ smartlist_add_strdup(chunks, "tunnelled-dir-server\n");
+
+ smartlist_add_strdup(chunks, "router-signature\n");
+
+ size_t len_out = 0;
+ buf2 = smartlist_join_strings(chunks, "", 0, &len_out);
+ SMARTLIST_FOREACH(chunks, char *, s, tor_free(s));
+ smartlist_free(chunks);
+
+ tt_assert(len_out > 0);
+
+ buf[strlen(buf2)] = '\0'; /* Don't compare the sig; it's never the same
+ * twice */
+
+ tt_str_op(buf,OP_EQ, buf2);
+ tor_free(buf);
+
+ setup_mock_configured_ports(r1->or_port, r1->dir_port);
+
+ buf = router_dump_router_to_string(r1, r1->identity_pkey, NULL, NULL, NULL);
+ tt_assert(buf);
+
+ cleanup_mock_configured_ports();
+
+ /* Now, try to parse buf */
+ cp = buf;
+ rp1 = router_parse_entry_from_string((const char*)cp,NULL,1,0,NULL,NULL);
+
+ CHECK_ROUTERINFO_CONSISTENCY(r1, rp1);
+
+ tt_assert(rp1->policy_is_reject_star);
+
+ tor_free(buf);
+ routerinfo_free(rp1);
+
+ /* Test extrainfo creation.
+ * We avoid calling router_build_fresh_unsigned_routerinfo(), because it's
+ * too complex. Instead, we re-use the manually-created routerinfos.
+ */
+
+ /* Set up standard mocks and data */
+ setup_mocks_for_fresh_descriptor(r1, NULL);
+
+ /* router_build_fresh_signed_extrainfo() passes the result of
+ * get_master_signing_key_cert() directly to tor_cert_dup(), which fails on
+ * NULL. But we want a NULL ei->cache_info.signing_key_cert to test the
+ * non-ed key path.
+ */
+ MOCK(tor_cert_dup, mock_tor_cert_dup_null);
+
+ /* Fake just enough of an ORPort and DirPort to get by */
+ setup_mock_configured_ports(r1->or_port, r1->dir_port);
+
+ /* Test some of the low-level static functions. */
+ e1 = router_build_fresh_signed_extrainfo(r1);
+ tt_assert(e1);
+ router_update_routerinfo_from_extrainfo(r1, e1);
+ rv = router_dump_and_sign_routerinfo_descriptor_body(r1);
+ tt_assert(rv == 0);
+ msg = "";
+ rv = routerinfo_incompatible_with_extrainfo(r1->identity_pkey, e1,
+ &r1->cache_info, &msg);
+ /* If they are incompatible, fail and show the msg string */
+ tt_str_op(msg, OP_EQ, "");
+ tt_assert(rv == 0);
+
+ /* Now cleanup */
+ cleanup_mocks_for_fresh_descriptor();
+
+ UNMOCK(tor_cert_dup);
+
+ cleanup_mock_configured_ports();
+
+ CHECK_EXTRAINFO_CONSISTENCY(r1, e1);
+
+ /* Test that the signed ri is parseable */
+ tt_assert(r1->cache_info.signed_descriptor_body);
+ cp = r1->cache_info.signed_descriptor_body;
+ rp1 = router_parse_entry_from_string((const char*)cp,NULL,1,0,NULL,NULL);
+
+ CHECK_ROUTERINFO_CONSISTENCY(r1, rp1);
+
+ tt_assert(rp1->policy_is_reject_star);
+
+ routerinfo_free(rp1);
+
+ /* Test that the signed ei is parseable */
+ tt_assert(e1->cache_info.signed_descriptor_body);
+ cp = e1->cache_info.signed_descriptor_body;
+ ep1 = extrainfo_parse_entry_from_string((const char*)cp,NULL,1,NULL,NULL);
+
+ CHECK_EXTRAINFO_CONSISTENCY(r1, ep1);
+
+ /* In future tests, we could check the actual extrainfo statistics. */
+
+ extrainfo_free(ep1);
+
+ done:
+ dirserv_free_fingerprint_list();
+
+ tor_free(options->ContactInfo);
+ tor_free(options->Nickname);
+
+ cleanup_mock_configured_ports();
+ cleanup_mocks_for_fresh_descriptor();
+
+ if (chunks) {
+ SMARTLIST_FOREACH(chunks, char *, s, tor_free(s));
+ smartlist_free(chunks);
+ }
+
+ routerinfo_free(r1);
+ routerinfo_free(rp1);
+
+ extrainfo_free(e1);
+ extrainfo_free(ep1);
+
+ tor_free(rsa_cc);
+
+ tor_free(buf);
+ tor_free(buf2);
+}
+
+/* Check that the exit policy in rp2 is as expected. */
+#define CHECK_PARSED_EXIT_POLICY(rp2) \
+STMT_BEGIN \
+ tt_int_op(smartlist_len(rp2->exit_policy),OP_EQ, 2); \
+ \
+ p = smartlist_get(rp2->exit_policy, 0); \
+ tt_int_op(p->policy_type,OP_EQ, ADDR_POLICY_ACCEPT); \
+ tt_assert(tor_addr_is_null(&p->addr)); \
+ tt_int_op(p->maskbits,OP_EQ, 0); \
+ tt_int_op(p->prt_min,OP_EQ, 80); \
+ tt_int_op(p->prt_max,OP_EQ, 80); \
+ \
+ p = smartlist_get(rp2->exit_policy, 1); \
+ tt_int_op(p->policy_type,OP_EQ, ADDR_POLICY_REJECT); \
+ tt_assert(tor_addr_eq(&p->addr, &ex2->addr)); \
+ tt_int_op(p->maskbits,OP_EQ, 8); \
+ tt_int_op(p->prt_min,OP_EQ, 24); \
+ tt_int_op(p->prt_max,OP_EQ, 24); \
+STMT_END
+
+/** Run unit tests for router descriptor generation logic for a RSA + ed25519
+ * router.
+ */
+static void
+test_dir_formats_rsa_ed25519(void *arg)
+{
+ char *buf = NULL;
+ char *buf2 = NULL;
+ char *cp = NULL;
+
+ crypto_pk_t *r2_onion_pkey = NULL;
+ char cert_buf[256];
+ uint8_t *rsa_cc = NULL;
+ time_t now = time(NULL);
+
+ routerinfo_t *r2 = NULL;
+ extrainfo_t *e2 = NULL;
+ routerinfo_t *r2_out = NULL;
+ routerinfo_t *rp2 = NULL;
+ extrainfo_t *ep2 = NULL;
+ addr_policy_t *ex1, *ex2;
+ const addr_policy_t *p;
+
+ smartlist_t *chunks = NULL;
+ int rv = -1;
+
+ or_options_t *options = get_options_mutable();
+ setup_dir_formats_options((const char *)arg, options);
+
+ hibernate_set_state_for_testing_(HIBERNATE_STATE_LIVE);
+
+ /* r2 is a RSA + ed25519 descriptor, with an exit policy, but no DirPort or
+ * IPv6 */
+ r2 = basic_routerinfo_new("Fred", 0x0a030201u /* 10.3.2.1 */,
+ 9005, 0,
+ 3000, 3000, 3000,
+ 5,
+ &r2_onion_pkey);
+
+ /* Fake just enough of an ntor key to get by */
+ curve25519_keypair_t r2_onion_keypair;
+ curve25519_keypair_generate(&r2_onion_keypair, 0);
+ r2->onion_curve25519_pkey = tor_memdup(&r2_onion_keypair.pubkey,
+ sizeof(curve25519_public_key_t));
+
+ /* Now add relay ed25519 keys
+ * We can't use init_mock_ed_keys() here, because the keys are seeded */
ed25519_keypair_t kp1, kp2;
ed25519_secret_key_from_seed(&kp1.seckey,
(const uint8_t*)"YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY");
@@ -248,157 +950,80 @@ test_dir_formats(void *arg)
&kp2.pubkey,
now, 86400,
CERT_FLAG_INCLUDE_SIGNING_KEY);
- r2->platform = tor_strdup(platform);
- r2->cache_info.published_on = 5;
- r2->or_port = 9005;
- r2->dir_port = 0;
- r2->supports_tunnelled_dir_requests = 1;
- router_set_rsa_onion_pkey(pk2, &r2->onion_pkey, &r2->onion_pkey_len);
- curve25519_keypair_t r2_onion_keypair;
- curve25519_keypair_generate(&r2_onion_keypair, 0);
- r2->onion_curve25519_pkey = tor_memdup(&r2_onion_keypair.pubkey,
- sizeof(curve25519_public_key_t));
- r2->identity_pkey = crypto_pk_dup_key(pk1);
- r2->bandwidthrate = r2->bandwidthburst = r2->bandwidthcapacity = 3000;
+
+ /* Now add an exit policy */
+ ex1 = tor_malloc_zero(sizeof(addr_policy_t));
+ ex2 = tor_malloc_zero(sizeof(addr_policy_t));
+ ex1->policy_type = ADDR_POLICY_ACCEPT;
+ tor_addr_from_ipv4h(&ex1->addr, 0);
+ ex1->maskbits = 0;
+ ex1->prt_min = ex1->prt_max = 80;
+ ex2->policy_type = ADDR_POLICY_REJECT;
+ tor_addr_from_ipv4h(&ex2->addr, 18<<24);
+ ex2->maskbits = 8;
+ ex2->prt_min = ex2->prt_max = 24;
+
r2->exit_policy = smartlist_new();
smartlist_add(r2->exit_policy, ex1);
smartlist_add(r2->exit_policy, ex2);
- r2->nickname = tor_strdup("Fred");
-
- tt_assert(!crypto_pk_write_public_key_to_string(pk1, &pk1_str,
- &pk1_str_len));
- tt_assert(!crypto_pk_write_public_key_to_string(pk2 , &pk2_str,
- &pk2_str_len));
-
- /* XXXX+++ router_dump_to_string should really take this from ri.*/
- options->ContactInfo = tor_strdup("Magri White "
- "<magri@elsewhere.example.com>");
- /* Skip reachability checks for DirPort and tunnelled-dir-server */
- options->AssumeReachable = 1;
-
- /* Fake just enough of an ORPort and DirPort to get by */
- MOCK(get_configured_ports, mock_get_configured_ports);
- mocked_configured_ports = smartlist_new();
-
- memset(&orport, 0, sizeof(orport));
- orport.type = CONN_TYPE_OR_LISTENER;
- orport.addr.family = AF_INET;
- orport.port = 9000;
- smartlist_add(mocked_configured_ports, &orport);
-
- memset(&dirport, 0, sizeof(dirport));
- dirport.type = CONN_TYPE_DIR_LISTENER;
- dirport.addr.family = AF_INET;
- dirport.port = 9003;
- smartlist_add(mocked_configured_ports, &dirport);
- buf = router_dump_router_to_string(r1, pk2, NULL, NULL, NULL);
-
- UNMOCK(get_configured_ports);
- smartlist_free(mocked_configured_ports);
- mocked_configured_ports = NULL;
+ /* Fake just enough of an ORPort to get by */
+ setup_mock_configured_ports(r2->or_port, 0);
- tor_free(options->ContactInfo);
+ buf = router_dump_router_to_string(r2,
+ r2->identity_pkey, r2_onion_pkey,
+ &r2_onion_keypair, &kp2);
tt_assert(buf);
- strlcpy(buf2, "router Magri 192.168.0.1 9000 0 9003\n"
- "or-address [1:2:3:4::]:9999\n"
- "platform Tor "VERSION" on ", sizeof(buf2));
- strlcat(buf2, get_uname(), sizeof(buf2));
- strlcat(buf2, "\n"
- "published 1970-01-01 00:00:00\n"
- "fingerprint ", sizeof(buf2));
- tt_assert(!crypto_pk_get_fingerprint(pk2, fingerprint, 1));
- strlcat(buf2, fingerprint, sizeof(buf2));
- strlcat(buf2, "\nuptime 0\n"
- /* XXX the "0" above is hard-coded, but even if we made it reflect
- * uptime, that still wouldn't make it right, because the two
- * descriptors might be made on different seconds... hm. */
- "bandwidth 1000 5000 10000\n"
- "onion-key\n", sizeof(buf2));
- strlcat(buf2, pk1_str, sizeof(buf2));
- strlcat(buf2, "signing-key\n", sizeof(buf2));
- strlcat(buf2, pk2_str, sizeof(buf2));
- strlcat(buf2, "hidden-service-dir\n", sizeof(buf2));
- strlcat(buf2, "contact Magri White <magri@elsewhere.example.com>\n",
- sizeof(buf2));
- strlcat(buf2, "ntor-onion-key ", sizeof(buf2));
- base64_encode(cert_buf, sizeof(cert_buf),
- (const char*)r1_onion_keypair.pubkey.public_key, 32,
- BASE64_ENCODE_MULTILINE);
- strlcat(buf2, cert_buf, sizeof(buf2));
- strlcat(buf2, "reject *:*\n", sizeof(buf2));
- strlcat(buf2, "tunnelled-dir-server\nrouter-signature\n", sizeof(buf2));
- buf[strlen(buf2)] = '\0'; /* Don't compare the sig; it's never the same
- * twice */
+ cleanup_mock_configured_ports();
- tt_str_op(buf,OP_EQ, buf2);
- tor_free(buf);
+ chunks = smartlist_new();
- buf = router_dump_router_to_string(r1, pk2, NULL, NULL, NULL);
- tt_assert(buf);
- cp = buf;
- rp1 = router_parse_entry_from_string((const char*)cp,NULL,1,0,NULL,NULL);
- tt_assert(rp1);
- tt_int_op(rp1->addr,OP_EQ, r1->addr);
- tt_int_op(rp1->or_port,OP_EQ, r1->or_port);
- tt_int_op(rp1->dir_port,OP_EQ, r1->dir_port);
- tt_int_op(rp1->bandwidthrate,OP_EQ, r1->bandwidthrate);
- tt_int_op(rp1->bandwidthburst,OP_EQ, r1->bandwidthburst);
- tt_int_op(rp1->bandwidthcapacity,OP_EQ, r1->bandwidthcapacity);
- crypto_pk_t *onion_pkey = router_get_rsa_onion_pkey(rp1->onion_pkey,
- rp1->onion_pkey_len);
- tt_int_op(crypto_pk_cmp_keys(onion_pkey, pk1), OP_EQ, 0);
- crypto_pk_free(onion_pkey);
- tt_int_op(crypto_pk_cmp_keys(rp1->identity_pkey, pk2), OP_EQ, 0);
- tt_assert(rp1->supports_tunnelled_dir_requests);
- //tt_assert(rp1->exit_policy == NULL);
- tor_free(buf);
+ /* Synthesise a router descriptor, without the signatures */
+ smartlist_add(chunks, get_new_router_line(r2));
- strlcpy(buf2,
- "router Fred 10.3.2.1 9005 0 0\n"
- "identity-ed25519\n"
- "-----BEGIN ED25519 CERT-----\n", sizeof(buf2));
+ smartlist_add_strdup(chunks,
+ "identity-ed25519\n"
+ "-----BEGIN ED25519 CERT-----\n");
base64_encode(cert_buf, sizeof(cert_buf),
(const char*)r2->cache_info.signing_key_cert->encoded,
r2->cache_info.signing_key_cert->encoded_len,
BASE64_ENCODE_MULTILINE);
- strlcat(buf2, cert_buf, sizeof(buf2));
- strlcat(buf2, "-----END ED25519 CERT-----\n", sizeof(buf2));
- strlcat(buf2, "master-key-ed25519 ", sizeof(buf2));
+ smartlist_add_strdup(chunks, cert_buf);
+ smartlist_add_strdup(chunks, "-----END ED25519 CERT-----\n");
+
+ smartlist_add_strdup(chunks, "master-key-ed25519 ");
{
char k[ED25519_BASE64_LEN+1];
tt_int_op(ed25519_public_to_base64(k,
&r2->cache_info.signing_key_cert->signing_key),
OP_GE, 0);
- strlcat(buf2, k, sizeof(buf2));
- strlcat(buf2, "\n", sizeof(buf2));
+ smartlist_add_strdup(chunks, k);
+ smartlist_add_strdup(chunks, "\n");
}
- strlcat(buf2, "platform Tor "VERSION" on ", sizeof(buf2));
- strlcat(buf2, get_uname(), sizeof(buf2));
- strlcat(buf2, "\n"
- "published 1970-01-01 00:00:05\n"
- "fingerprint ", sizeof(buf2));
- tt_assert(!crypto_pk_get_fingerprint(pk1, fingerprint, 1));
- strlcat(buf2, fingerprint, sizeof(buf2));
- strlcat(buf2, "\nuptime 0\n"
- "bandwidth 3000 3000 3000\n", sizeof(buf2));
- strlcat(buf2, "onion-key\n", sizeof(buf2));
- strlcat(buf2, pk2_str, sizeof(buf2));
- strlcat(buf2, "signing-key\n", sizeof(buf2));
- strlcat(buf2, pk1_str, sizeof(buf2));
+
+ smartlist_add(chunks, get_new_platform_line());
+ smartlist_add(chunks, get_new_published_line(r2));
+ smartlist_add(chunks, get_new_fingerprint_line(r2));
+
+ smartlist_add(chunks, get_new_uptime_line(0));
+ smartlist_add(chunks, get_new_bandwidth_line(r2));
+
+ smartlist_add(chunks, get_new_onion_key_block(r2));
+ smartlist_add(chunks, get_new_signing_key_block(r2));
+
int rsa_cc_len;
- rsa_cc = make_tap_onion_key_crosscert(pk2,
+ rsa_cc = make_tap_onion_key_crosscert(r2_onion_pkey,
&kp1.pubkey,
- pk1,
+ r2->identity_pkey,
&rsa_cc_len);
tt_assert(rsa_cc);
base64_encode(cert_buf, sizeof(cert_buf), (char*)rsa_cc, rsa_cc_len,
BASE64_ENCODE_MULTILINE);
- strlcat(buf2, "onion-key-crosscert\n"
- "-----BEGIN CROSSCERT-----\n", sizeof(buf2));
- strlcat(buf2, cert_buf, sizeof(buf2));
- strlcat(buf2, "-----END CROSSCERT-----\n", sizeof(buf2));
+ smartlist_add_strdup(chunks, "onion-key-crosscert\n"
+ "-----BEGIN CROSSCERT-----\n");
+ smartlist_add_strdup(chunks, cert_buf);
+ smartlist_add_strdup(chunks, "-----END CROSSCERT-----\n");
int ntor_cc_sign;
{
tor_cert_t *ntor_cc = NULL;
@@ -413,112 +1038,165 @@ test_dir_formats(void *arg)
BASE64_ENCODE_MULTILINE);
tor_cert_free(ntor_cc);
}
- tor_snprintf(buf2+strlen(buf2), sizeof(buf2)-strlen(buf2),
+ smartlist_add_asprintf(chunks,
"ntor-onion-key-crosscert %d\n"
"-----BEGIN ED25519 CERT-----\n"
"%s"
"-----END ED25519 CERT-----\n", ntor_cc_sign, cert_buf);
- strlcat(buf2, "hidden-service-dir\n", sizeof(buf2));
- strlcat(buf2, "ntor-onion-key ", sizeof(buf2));
- base64_encode(cert_buf, sizeof(cert_buf),
- (const char*)r2_onion_keypair.pubkey.public_key, 32,
- BASE64_ENCODE_MULTILINE);
- strlcat(buf2, cert_buf, sizeof(buf2));
- strlcat(buf2, "accept *:80\nreject 18.0.0.0/8:24\n", sizeof(buf2));
- strlcat(buf2, "tunnelled-dir-server\n", sizeof(buf2));
- strlcat(buf2, "router-sig-ed25519 ", sizeof(buf2));
+ smartlist_add_strdup(chunks, "hidden-service-dir\n");
- /* Fake just enough of an ORPort to get by */
- MOCK(get_configured_ports, mock_get_configured_ports);
- mocked_configured_ports = smartlist_new();
+ smartlist_add(chunks, get_new_bridge_distribution_request_line(options));
+ smartlist_add(chunks, get_new_ntor_onion_key_line(&r2_onion_keypair.pubkey));
+ smartlist_add_strdup(chunks, "accept *:80\nreject 18.0.0.0/8:24\n");
+ smartlist_add_strdup(chunks, "tunnelled-dir-server\n");
- memset(&orport, 0, sizeof(orport));
- orport.type = CONN_TYPE_OR_LISTENER;
- orport.addr.family = AF_INET;
- orport.port = 9005;
- smartlist_add(mocked_configured_ports, &orport);
+ smartlist_add_strdup(chunks, "router-sig-ed25519 ");
- buf = router_dump_router_to_string(r2, pk1, pk2, &r2_onion_keypair, &kp2);
- tt_assert(buf);
- buf[strlen(buf2)] = '\0'; /* Don't compare the sig; it's never the same
+ size_t len_out = 0;
+ buf2 = smartlist_join_strings(chunks, "", 0, &len_out);
+ SMARTLIST_FOREACH(chunks, char *, s, tor_free(s));
+ smartlist_free(chunks);
+
+ tt_assert(len_out > 0);
+
+ buf[strlen(buf2)] = '\0'; /* Don't compare either sig; they're never the same
* twice */
tt_str_op(buf, OP_EQ, buf2);
tor_free(buf);
- buf = router_dump_router_to_string(r2, pk1, NULL, NULL, NULL);
+ setup_mock_configured_ports(r2->or_port, 0);
- UNMOCK(get_configured_ports);
- smartlist_free(mocked_configured_ports);
- mocked_configured_ports = NULL;
+ buf = router_dump_router_to_string(r2, r2->identity_pkey, NULL, NULL, NULL);
+ tt_assert(buf);
- /* Reset for later */
+ cleanup_mock_configured_ports();
+
+ /* Now, try to parse buf */
cp = buf;
rp2 = router_parse_entry_from_string((const char*)cp,NULL,1,0,NULL,NULL);
- tt_assert(rp2);
- tt_int_op(rp2->addr,OP_EQ, r2->addr);
- tt_int_op(rp2->or_port,OP_EQ, r2->or_port);
- tt_int_op(rp2->dir_port,OP_EQ, r2->dir_port);
- tt_int_op(rp2->bandwidthrate,OP_EQ, r2->bandwidthrate);
- tt_int_op(rp2->bandwidthburst,OP_EQ, r2->bandwidthburst);
- tt_int_op(rp2->bandwidthcapacity,OP_EQ, r2->bandwidthcapacity);
+
+ CHECK_ROUTERINFO_CONSISTENCY(r2, rp2);
+
tt_mem_op(rp2->onion_curve25519_pkey->public_key,OP_EQ,
r2->onion_curve25519_pkey->public_key,
CURVE25519_PUBKEY_LEN);
- onion_pkey = router_get_rsa_onion_pkey(rp2->onion_pkey,
- rp2->onion_pkey_len);
- tt_int_op(crypto_pk_cmp_keys(onion_pkey, pk2), OP_EQ, 0);
- crypto_pk_free(onion_pkey);
- tt_int_op(crypto_pk_cmp_keys(rp2->identity_pkey, pk1), OP_EQ, 0);
- tt_assert(rp2->supports_tunnelled_dir_requests);
-
- tt_int_op(smartlist_len(rp2->exit_policy),OP_EQ, 2);
-
- p = smartlist_get(rp2->exit_policy, 0);
- tt_int_op(p->policy_type,OP_EQ, ADDR_POLICY_ACCEPT);
- tt_assert(tor_addr_is_null(&p->addr));
- tt_int_op(p->maskbits,OP_EQ, 0);
- tt_int_op(p->prt_min,OP_EQ, 80);
- tt_int_op(p->prt_max,OP_EQ, 80);
-
- p = smartlist_get(rp2->exit_policy, 1);
- tt_int_op(p->policy_type,OP_EQ, ADDR_POLICY_REJECT);
- tt_assert(tor_addr_eq(&p->addr, &ex2->addr));
- tt_int_op(p->maskbits,OP_EQ, 8);
- tt_int_op(p->prt_min,OP_EQ, 24);
- tt_int_op(p->prt_max,OP_EQ, 24);
-
-#if 0
- /* Okay, now for the directories. */
- {
- fingerprint_list = smartlist_new();
- crypto_pk_get_fingerprint(pk2, buf, 1);
- add_fingerprint_to_dir(buf, fingerprint_list, 0);
- crypto_pk_get_fingerprint(pk1, buf, 1);
- add_fingerprint_to_dir(buf, fingerprint_list, 0);
+
+ CHECK_PARSED_EXIT_POLICY(rp2);
+
+ tor_free(buf);
+ routerinfo_free(rp2);
+
+ /* Test extrainfo creation. */
+
+ /* Set up standard mocks and data */
+ setup_mocks_for_fresh_descriptor(r2, r2_onion_pkey);
+
+ /* router_build_fresh_descriptor() requires
+ * router_build_fresh_unsigned_routerinfo(), but the implementation is
+ * too complex. Instead, we re-use r2.
+ */
+ mocked_routerinfo = r2;
+ MOCK(router_build_fresh_unsigned_routerinfo,
+ mock_router_build_fresh_unsigned_routerinfo);
+
+ /* r2 uses ed25519, so we need to mock the ed key functions */
+ mocked_master_signing_key = &kp2;
+ MOCK(get_master_signing_keypair, mock_get_master_signing_keypair);
+
+ mocked_signing_key_cert = r2->cache_info.signing_key_cert;
+ MOCK(get_master_signing_key_cert, mock_get_master_signing_key_cert);
+
+ mocked_curve25519_onion_key = &r2_onion_keypair;
+ MOCK(get_current_curve25519_keypair, mock_get_current_curve25519_keypair);
+
+ /* Fake just enough of an ORPort to get by */
+ setup_mock_configured_ports(r2->or_port, 0);
+
+ /* Test the high-level interface. */
+ rv = router_build_fresh_descriptor(&r2_out, &e2);
+ if (rv < 0) {
+ /* router_build_fresh_descriptor() frees r2 on failure. */
+ r2 = NULL;
+ /* Get rid of an alias to rp2 */
+ r2_out = NULL;
}
+ tt_assert(rv == 0);
+ tt_assert(r2_out);
+ tt_assert(e2);
+ /* Guaranteed by mock_router_build_fresh_unsigned_routerinfo() */
+ tt_ptr_op(r2_out, OP_EQ, r2);
+ /* Get rid of an alias to r2 */
+ r2_out = NULL;
+
+ /* Now cleanup */
+ cleanup_mocks_for_fresh_descriptor();
+
+ mocked_routerinfo = NULL;
+ UNMOCK(router_build_fresh_unsigned_routerinfo);
+ mocked_master_signing_key = NULL;
+ UNMOCK(get_master_signing_keypair);
+ mocked_signing_key_cert = NULL;
+ UNMOCK(get_master_signing_key_cert);
+ mocked_curve25519_onion_key = NULL;
+ UNMOCK(get_current_curve25519_keypair);
+
+ cleanup_mock_configured_ports();
+
+ CHECK_EXTRAINFO_CONSISTENCY(r2, e2);
+
+ /* Test that the signed ri is parseable */
+ tt_assert(r2->cache_info.signed_descriptor_body);
+ cp = r2->cache_info.signed_descriptor_body;
+ rp2 = router_parse_entry_from_string((const char*)cp,NULL,1,0,NULL,NULL);
-#endif /* 0 */
- dirserv_free_fingerprint_list();
+ CHECK_ROUTERINFO_CONSISTENCY(r2, rp2);
+
+ tt_mem_op(rp2->onion_curve25519_pkey->public_key,OP_EQ,
+ r2->onion_curve25519_pkey->public_key,
+ CURVE25519_PUBKEY_LEN);
+
+ CHECK_PARSED_EXIT_POLICY(rp2);
+
+ routerinfo_free(rp2);
+
+ /* Test that the signed ei is parseable */
+ tt_assert(e2->cache_info.signed_descriptor_body);
+ cp = e2->cache_info.signed_descriptor_body;
+ ep2 = extrainfo_parse_entry_from_string((const char*)cp,NULL,1,NULL,NULL);
+
+ CHECK_EXTRAINFO_CONSISTENCY(r2, ep2);
+
+ /* In future tests, we could check the actual extrainfo statistics. */
+
+ extrainfo_free(ep2);
done:
- if (r1)
- routerinfo_free(r1);
- if (r2)
- routerinfo_free(r2);
- if (rp2)
- routerinfo_free(rp2);
+ dirserv_free_fingerprint_list();
+
+ tor_free(options->Nickname);
+
+ cleanup_mock_configured_ports();
+ cleanup_mocks_for_fresh_descriptor();
+
+ if (chunks) {
+ SMARTLIST_FOREACH(chunks, char *, s, tor_free(s));
+ smartlist_free(chunks);
+ }
+
+ routerinfo_free(r2);
+ routerinfo_free(r2_out);
+ routerinfo_free(rp2);
+
+ extrainfo_free(e2);
+ extrainfo_free(ep2);
tor_free(rsa_cc);
+ crypto_pk_free(r2_onion_pkey);
+
tor_free(buf);
- tor_free(pk1_str);
- tor_free(pk2_str);
- if (pk1) crypto_pk_free(pk1);
- if (pk2) crypto_pk_free(pk2);
- if (rp1) routerinfo_free(rp1);
- tor_free(dir1); /* XXXX And more !*/
- tor_free(dir2); /* And more !*/
+ tor_free(buf2);
}
#include "failing_routerdescs.inc"
@@ -1582,6 +2260,19 @@ test_dir_measured_bw_kb(void *arg)
/* check whether node_id can be at the end and something in the
* in the middle of bw and node_id */
"bw=1024 foo=bar node_id=$557365204145532d32353620696e73746561642e\n",
+
+ /* Test that a line with vote=1 will pass. */
+ "node_id=$557365204145532d32353620696e73746561642e bw=1024 vote=1\n",
+ /* Test that a line with unmeasured=1 will pass. */
+ "node_id=$557365204145532d32353620696e73746561642e bw=1024 unmeasured=1\n",
+ /* Test that a line with vote=1 and unmeasured=1 will pass. */
+ "node_id=$557365204145532d32353620696e73746561642e bw=1024 vote=1"
+ "unmeasured=1\n",
+ /* Test that a line with unmeasured=0 will pass. */
+ "node_id=$557365204145532d32353620696e73746561642e bw=1024 unmeasured=0\n",
+ /* Test that a line with vote=1 and unmeasured=0 will pass. */
+ "node_id=$557365204145532d32353620696e73746561642e bw=1024 vote=1"
+ "unmeasured=0\n",
"end"
};
const char *lines_fail[] = {
@@ -1615,6 +2306,12 @@ test_dir_measured_bw_kb(void *arg)
"node_id=$55736520414552d32353620696e73746561642e bw=1024\n",
"node_id=557365204145532d32353620696e73746561642e bw=1024\n",
"node_id= $557365204145532d32353620696e73746561642e bw=0.23\n",
+
+ /* Test that a line with vote=0 will fail too, so that it is ignored. */
+ "node_id=$557365204145532d32353620696e73746561642e bw=1024 vote=0\n",
+ /* Test that a line with vote=0 will fail even if unmeasured=0. */
+ "node_id=$557365204145532d32353620696e73746561642e bw=1024 vote=0 "
+ "unmeasured=0\n",
"end"
};
@@ -2029,6 +2726,46 @@ test_dir_dirserv_read_measured_bandwidths(void *arg)
smartlist_free(bw_file_headers);
tor_free(bw_file_headers_str);
+ /* Test v1.x.x bandwidth line with vote=0.
+ * It will be ignored it and logged it at debug level. */
+ const char *relay_lines_ignore =
+ "node_id=$68A483E05A2ABDCA6DA5A3EF8DB5177638A27F80 bw=1024 vote=0\n"
+ "node_id=$68A483E05A2ABDCA6DA5A3EF8DB5177638A27F80 bw=1024 vote=0"
+ "unmeasured=1\n"
+ "node_id=$68A483E05A2ABDCA6DA5A3EF8DB5177638A27F80 bw=1024 vote=0"
+ "unmeasured=0\n";
+
+ /* Create the bandwidth file */
+ tor_asprintf(&content, "%ld\n%s", (long)timestamp, relay_lines_ignore);
+ write_str_to_file(fname, content, 0);
+ tor_free(content);
+
+ /* Read the bandwidth file */
+ setup_full_capture_of_logs(LOG_DEBUG);
+ tt_int_op(0, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL, NULL,
+ NULL));
+ expect_log_msg_containing("Ignoring bandwidth file line");
+ teardown_capture_of_logs();
+
+ /* Test v1.x.x bandwidth line with "vote=1" or "unmeasured=1" or
+ * "unmeasured=0".
+ * They will not be ignored. */
+ /* Create the bandwidth file */
+ const char *relay_lines_vote =
+ "node_id=$68A483E05A2ABDCA6DA5A3EF8DB5177638A27F80 bw=1024 vote=1\n"
+ "node_id=$68A483E05A2ABDCA6DA5A3EF8DB5177638A27F80 bw=1024 unmeasured=0\n"
+ "node_id=$68A483E05A2ABDCA6DA5A3EF8DB5177638A27F80 bw=1024 unmeasured=1\n";
+ tor_asprintf(&content, "%ld\n%s", (long)timestamp, relay_lines_vote);
+ write_str_to_file(fname, content, 0);
+ tor_free(content);
+
+ /* Read the bandwidth file */
+ setup_full_capture_of_logs(LOG_DEBUG);
+ tt_int_op(0, OP_EQ, dirserv_read_measured_bandwidths(fname, NULL, NULL,
+ NULL));
+ expect_log_msg_not_containing("Ignoring bandwidth file line");
+ teardown_capture_of_logs();
+
done:
unlink(fname);
tor_free(fname);
@@ -6487,7 +7224,22 @@ test_dir_format_versions_list(void *arg)
struct testcase_t dir_tests[] = {
DIR_LEGACY(nicknames),
- DIR_LEGACY(formats),
+ /* extrainfo without any stats */
+ DIR_ARG(formats_rsa, TT_FORK, ""),
+ DIR_ARG(formats_rsa_ed25519, TT_FORK, ""),
+ /* on a bridge */
+ DIR_ARG(formats_rsa, TT_FORK, "b"),
+ DIR_ARG(formats_rsa_ed25519, TT_FORK, "b"),
+ /* extrainfo with basic stats */
+ DIR_ARG(formats_rsa, TT_FORK, "e"),
+ DIR_ARG(formats_rsa_ed25519, TT_FORK, "e"),
+ DIR_ARG(formats_rsa, TT_FORK, "be"),
+ DIR_ARG(formats_rsa_ed25519, TT_FORK, "be"),
+ /* extrainfo with all stats */
+ DIR_ARG(formats_rsa, TT_FORK, "es"),
+ DIR_ARG(formats_rsa_ed25519, TT_FORK, "es"),
+ DIR_ARG(formats_rsa, TT_FORK, "bes"),
+ DIR_ARG(formats_rsa_ed25519, TT_FORK, "bes"),
DIR(routerinfo_parsing, 0),
DIR(extrainfo_parsing, 0),
DIR(parse_router_list, TT_FORK),
diff --git a/src/test/test_dir_handle_get.c b/src/test/test_dir_handle_get.c
index 841ac77916..c3a17e7309 100644
--- a/src/test/test_dir_handle_get.c
+++ b/src/test/test_dir_handle_get.c
@@ -2223,6 +2223,31 @@ test_dir_handle_get_status_vote_next_authority_not_found(void* data)
tor_free(header);
}
+static void
+test_dir_handle_get_status_vote_next_bandwidth_not_found(void* data)
+{
+ dir_connection_t *conn = NULL;
+ char *header = NULL;
+ (void) data;
+
+ 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/next/bandwdith"), NULL, 0));
+
+ fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE,
+ NULL, NULL, 1, 0);
+ tt_assert(header);
+ tt_str_op(NOT_FOUND, OP_EQ, header);
+
+ done:
+ UNMOCK(connection_write_to_buf_impl_);
+ connection_free_minimal(TO_CONN(conn));
+ tor_free(header);
+}
+
NS_DECL(const char*,
dirvote_get_pending_consensus, (consensus_flavor_t flav));
@@ -2463,6 +2488,85 @@ test_dir_handle_get_status_vote_next_authority(void* data)
}
static void
+test_dir_handle_get_status_vote_next_bandwidth(void* data)
+{
+ dir_connection_t *conn = NULL;
+ char *header = NULL, *body = NULL;
+ size_t body_used = 0;
+ (void) data;
+
+ const char *content =
+ "1541171221\n"
+ "node_id=$68A483E05A2ABDCA6DA5A3EF8DB5177638A27F80 "
+ "master_key_ed25519=YaqV4vbvPYKucElk297eVdNArDz9HtIwUoIeo0+cVIpQ "
+ "bw=760 nick=Test time=2018-05-08T16:13:26\n";
+
+ init_mock_options();
+ MOCK(get_options, mock_get_options);
+ mock_options->V3BandwidthsFile = tor_strdup(
+ get_fname_rnd("V3BandwidthsFile")
+ );
+
+ write_str_to_file(mock_options->V3BandwidthsFile, content, 0);
+
+ 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/next/bandwidth"), NULL, 0));
+
+ fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE,
+ &body, &body_used, strlen(content)+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: 167\r\n"));
+
+ /* Check cache lifetime */
+ char expbuf[RFC1123_TIME_LEN+1];
+ time_t now = time(NULL);
+ /* BANDWIDTH_CACHE_LIFETIME is defined in dircache.c. */
+ format_rfc1123_time(expbuf, (time_t)(now + 30*60));
+ char *expires = NULL;
+ /* Change to 'Cache-control: max-age=%d' if using http/1.1. */
+ tor_asprintf(&expires, "Expires: %s\r\n", expbuf);
+ tt_assert(strstr(header, expires));
+
+ tt_int_op(body_used, OP_EQ, strlen(body));
+ tt_str_op(content, OP_EQ, body);
+
+ tor_free(header);
+ tor_free(body);
+
+ /* Request the file using compression, the result should be the same. */
+ tt_int_op(0, OP_EQ, directory_handle_command_get(conn,
+ GET("/tor/status-vote/next/bandwidth.z"), NULL, 0));
+
+ fetch_from_buf_http(TO_CONN(conn)->outbuf, &header, MAX_HEADERS_SIZE,
+ &body, &body_used, strlen(content)+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-Encoding: deflate\r\n"));
+
+ /* Since using connection_write_to_buf_mock instead of mocking
+ * connection_buf_add_compress, the content is not actually compressed.
+ * If it would, the size and content would be different than the original.
+ */
+
+ done:
+ UNMOCK(get_options);
+ UNMOCK(connection_write_to_buf_impl_);
+ connection_free_minimal(TO_CONN(conn));
+ tor_free(header);
+ tor_free(body);
+ tor_free(expires);
+ or_options_free(mock_options);
+}
+
+static void
test_dir_handle_get_status_vote_current_authority(void* data)
{
dir_connection_t *conn = NULL;
@@ -2637,6 +2741,8 @@ struct testcase_t dir_handle_get_tests[] = {
DIR_HANDLE_CMD(status_vote_current_authority, 0),
DIR_HANDLE_CMD(status_vote_next_authority_not_found, 0),
DIR_HANDLE_CMD(status_vote_next_authority, 0),
+ DIR_HANDLE_CMD(status_vote_next_bandwidth_not_found, 0),
+ DIR_HANDLE_CMD(status_vote_next_bandwidth, 0),
DIR_HANDLE_CMD(status_vote_current_consensus_ns_not_enough_sigs, TT_FORK),
DIR_HANDLE_CMD(status_vote_current_consensus_ns_not_found, TT_FORK),
DIR_HANDLE_CMD(status_vote_current_consensus_too_old, TT_FORK),
diff --git a/src/test/test_ptr_slow.c b/src/test/test_ptr_slow.c
new file mode 100644
index 0000000000..76bdbf1891
--- /dev/null
+++ b/src/test/test_ptr_slow.c
@@ -0,0 +1,106 @@
+/* Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2019, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+#include "core/or/or.h"
+#include "test/test.h"
+#include "test/ptr_helpers.h"
+
+#include <stdint.h>
+#include <limits.h>
+
+/** Assert that <b>a</b> can be cast to void * and back. */
+static void
+assert_int_voidptr_roundtrip(int a)
+{
+ intptr_t ap = (intptr_t)a;
+ void *b = cast_intptr_to_voidstar(ap);
+ intptr_t c = cast_voidstar_to_intptr(b);
+ void *d = cast_intptr_to_voidstar(c);
+
+ tt_assert(ap == c);
+ tt_assert(b == d);
+
+ done:
+ return;
+}
+
+/** Test for possibility of casting `int` to `void *` and back. */
+static void
+test_int_voidstar_interop(void *arg)
+{
+ int a;
+ (void)arg;
+
+ for (a = -1024; a <= 1024; a++) {
+ assert_int_voidptr_roundtrip(a);
+ }
+
+ for (a = INT_MIN; a <= INT_MIN+1024; a++) {
+ assert_int_voidptr_roundtrip(a);
+ }
+
+ for (a = INT_MAX-1024; a < INT_MAX; a++) {
+ assert_int_voidptr_roundtrip(a);
+ }
+
+ a = 1;
+ for (unsigned long i = 0; i < sizeof(int) * 8; i++) {
+ assert_int_voidptr_roundtrip(a);
+ a = (a << 1);
+ }
+}
+
+/** Assert that <b>a</b> can be cast to void * and back. */
+static void
+assert_uint_voidptr_roundtrip(unsigned int a)
+{
+ uintptr_t ap = (uintptr_t)a;
+ void *b = cast_uintptr_to_voidstar(ap);
+ uintptr_t c = cast_voidstar_to_uintptr(b);
+ void *d = cast_uintptr_to_voidstar(c);
+
+ tt_assert(ap == c);
+ tt_assert(b == d);
+
+ done:
+ return;
+}
+
+/** Test for possibility of casting `int` to `void *` and back. */
+static void
+test_uint_voidstar_interop(void *arg)
+{
+ unsigned int a;
+ (void)arg;
+
+ for (a = 0; a <= 1024; a++) {
+ assert_uint_voidptr_roundtrip(a);
+ }
+
+ for (a = UINT_MAX-1024; a < UINT_MAX; a++) {
+ assert_uint_voidptr_roundtrip(a);
+ }
+
+ a = 1;
+ for (unsigned long i = 0; i < sizeof(int) * 8; i++) {
+ assert_uint_voidptr_roundtrip(a);
+ a = (a << 1);
+ }
+}
+
+struct testcase_t slow_ptr_tests[] = {
+ { .name = "int_voidstar_interop",
+ .fn = test_int_voidstar_interop,
+ .flags = 0,
+ .setup = NULL,
+ .setup_data = NULL },
+ { .name = "uint_voidstar_interop",
+ .fn = test_uint_voidstar_interop,
+ .flags = 0,
+ .setup = NULL,
+ .setup_data = NULL },
+ END_OF_TESTCASES
+};
diff --git a/src/test/test_router.c b/src/test/test_router.c
index ea0ee3e84c..5477ab51e9 100644
--- a/src/test/test_router.c
+++ b/src/test/test_router.c
@@ -100,6 +100,9 @@ test_router_dump_router_to_string_no_bridge_distribution_method(void *arg)
router = (routerinfo_t*)router_get_my_routerinfo();
tt_ptr_op(router, !=, NULL);
+ /* The real router_get_my_routerinfo() looks up onion_curve25519_pkey using
+ * get_current_curve25519_keypair(), but we don't initialise static data in
+ * this test. */
router->onion_curve25519_pkey = &ntor_keypair.pubkey;
/* Generate our server descriptor and ensure that the substring
diff --git a/src/test/test_shared_random.c b/src/test/test_shared_random.c
index 5fa7e80d07..480799383b 100644
--- a/src/test/test_shared_random.c
+++ b/src/test/test_shared_random.c
@@ -1081,70 +1081,85 @@ test_sr_get_majority_srv_from_votes(void *arg)
smartlist_free(votes);
}
-/* Test utils that don't depend on authority state */
+/* Testing sr_srv_dup(). */
static void
-test_utils_general(void *arg)
+test_sr_svr_dup(void *arg)
{
- (void) arg;
+ (void)arg;
- /* Testing sr_srv_dup(). */
- {
- sr_srv_t *srv = NULL, *dup_srv = NULL;
- const char *srv_value =
- "1BDB7C3E973936E4D13A49F37C859B3DC69C429334CF9412E3FEF6399C52D47A";
- srv = tor_malloc_zero(sizeof(*srv));
- srv->num_reveals = 42;
- memcpy(srv->value, srv_value, sizeof(srv->value));
- dup_srv = sr_srv_dup(srv);
- tt_assert(dup_srv);
- tt_u64_op(dup_srv->num_reveals, OP_EQ, srv->num_reveals);
- tt_mem_op(dup_srv->value, OP_EQ, srv->value, sizeof(srv->value));
- tor_free(srv);
- tor_free(dup_srv);
- }
+ sr_srv_t *srv = NULL, *dup_srv = NULL;
+ const char *srv_value =
+ "1BDB7C3E973936E4D13A49F37C859B3DC69C429334CF9412E3FEF6399C52D47A";
+ srv = tor_malloc_zero(sizeof(*srv));
+ srv->num_reveals = 42;
+ memcpy(srv->value, srv_value, sizeof(srv->value));
+ dup_srv = sr_srv_dup(srv);
+ tt_assert(dup_srv);
+ tt_u64_op(dup_srv->num_reveals, OP_EQ, srv->num_reveals);
+ tt_mem_op(dup_srv->value, OP_EQ, srv->value, sizeof(srv->value));
- /* Testing commitments_are_the_same(). Currently, the check is to test the
- * value of the encoded commit so let's make sure that actually works. */
- {
- /* Payload of 57 bytes that is the length of sr_commit_t->encoded_commit.
- * 56 bytes of payload and a NUL terminated byte at the end ('\x00')
- * which comes down to SR_COMMIT_BASE64_LEN + 1. */
- const char *payload =
- "\x5d\xb9\x60\xb6\xcc\x51\x68\x52\x31\xd9\x88\x88\x71\x71\xe0\x30"
- "\x59\x55\x7f\xcd\x61\xc0\x4b\x05\xb8\xcd\xc1\x48\xe9\xcd\x16\x1f"
- "\x70\x15\x0c\xfc\xd3\x1a\x75\xd0\x93\x6c\xc4\xe0\x5c\xbe\xe2\x18"
- "\xc7\xaf\x72\xb6\x7c\x9b\x52\x00";
- sr_commit_t commit1, commit2;
- memcpy(commit1.encoded_commit, payload, sizeof(commit1.encoded_commit));
- memcpy(commit2.encoded_commit, payload, sizeof(commit2.encoded_commit));
- tt_int_op(commitments_are_the_same(&commit1, &commit2), OP_EQ, 1);
- /* Let's corrupt one of them. */
- memset(commit1.encoded_commit, 'A', sizeof(commit1.encoded_commit));
- tt_int_op(commitments_are_the_same(&commit1, &commit2), OP_EQ, 0);
- }
+ done:
+ tor_free(srv);
+ tor_free(dup_srv);
+}
- /* Testing commit_is_authoritative(). */
- {
- crypto_pk_t *k = crypto_pk_new();
- char digest[DIGEST_LEN];
- sr_commit_t commit;
+/* Testing commitments_are_the_same(). Currently, the check is to test the
+ * value of the encoded commit so let's make sure that actually works. */
+static void
+test_commitments_are_the_same(void *arg)
+{
+ (void)arg;
- tt_assert(!crypto_pk_generate_key(k));
+ /* Payload of 57 bytes that is the length of sr_commit_t->encoded_commit.
+ * 56 bytes of payload and a NUL terminated byte at the end ('\x00')
+ * which comes down to SR_COMMIT_BASE64_LEN + 1. */
+ const char *payload =
+ "\x5d\xb9\x60\xb6\xcc\x51\x68\x52\x31\xd9\x88\x88\x71\x71\xe0\x30"
+ "\x59\x55\x7f\xcd\x61\xc0\x4b\x05\xb8\xcd\xc1\x48\xe9\xcd\x16\x1f"
+ "\x70\x15\x0c\xfc\xd3\x1a\x75\xd0\x93\x6c\xc4\xe0\x5c\xbe\xe2\x18"
+ "\xc7\xaf\x72\xb6\x7c\x9b\x52\x00";
+ sr_commit_t commit1, commit2;
+ memcpy(commit1.encoded_commit, payload, sizeof(commit1.encoded_commit));
+ memcpy(commit2.encoded_commit, payload, sizeof(commit2.encoded_commit));
+ tt_int_op(commitments_are_the_same(&commit1, &commit2), OP_EQ, 1);
+ /* Let's corrupt one of them. */
+ memset(commit1.encoded_commit, 'A', sizeof(commit1.encoded_commit));
+ tt_int_op(commitments_are_the_same(&commit1, &commit2), OP_EQ, 0);
- tt_int_op(0, OP_EQ, crypto_pk_get_digest(k, digest));
- memcpy(commit.rsa_identity, digest, sizeof(commit.rsa_identity));
- tt_int_op(commit_is_authoritative(&commit, digest), OP_EQ, 1);
- /* Change the pubkey. */
- memset(commit.rsa_identity, 0, sizeof(commit.rsa_identity));
- tt_int_op(commit_is_authoritative(&commit, digest), OP_EQ, 0);
- crypto_pk_free(k);
- }
+ done:
+ return;
+}
- /* Testing get_phase_str(). */
- {
- tt_str_op(get_phase_str(SR_PHASE_REVEAL), OP_EQ, "reveal");
- tt_str_op(get_phase_str(SR_PHASE_COMMIT), OP_EQ, "commit");
- }
+/* Testing commit_is_authoritative(). */
+static void
+test_commit_is_authoritative(void *arg)
+{
+ (void)arg;
+
+ crypto_pk_t *k = crypto_pk_new();
+ char digest[DIGEST_LEN];
+ sr_commit_t commit;
+
+ tt_assert(!crypto_pk_generate_key(k));
+
+ tt_int_op(0, OP_EQ, crypto_pk_get_digest(k, digest));
+ memcpy(commit.rsa_identity, digest, sizeof(commit.rsa_identity));
+ tt_int_op(commit_is_authoritative(&commit, digest), OP_EQ, 1);
+ /* Change the pubkey. */
+ memset(commit.rsa_identity, 0, sizeof(commit.rsa_identity));
+ tt_int_op(commit_is_authoritative(&commit, digest), OP_EQ, 0);
+
+ done:
+ crypto_pk_free(k);
+}
+
+static void
+test_get_phase_str(void *arg)
+{
+ (void)arg;
+
+ tt_str_op(get_phase_str(SR_PHASE_REVEAL), OP_EQ, "reveal");
+ tt_str_op(get_phase_str(SR_PHASE_COMMIT), OP_EQ, "commit");
done:
return;
@@ -1649,7 +1664,12 @@ struct testcase_t sr_tests[] = {
{ "sr_compute_srv", test_sr_compute_srv, TT_FORK, NULL, NULL },
{ "sr_get_majority_srv_from_votes", test_sr_get_majority_srv_from_votes,
TT_FORK, NULL, NULL },
- { "utils_general", test_utils_general, TT_FORK, NULL, NULL },
+ { "sr_svr_dup", test_sr_svr_dup, TT_FORK, NULL, NULL },
+ { "commitments_are_the_same", test_commitments_are_the_same, TT_FORK, NULL,
+ NULL },
+ { "commit_is_authoritative", test_commit_is_authoritative, TT_FORK, NULL,
+ NULL },
+ { "get_phase_str", test_get_phase_str, TT_FORK, NULL, NULL },
{ "utils_auth", test_utils_auth, TT_FORK, NULL, NULL },
{ "state_transition", test_state_transition, TT_FORK, NULL, NULL },
{ "state_update", test_state_update, TT_FORK,
diff --git a/src/test/test_slow.c b/src/test/test_slow.c
index c3e7edd408..d4d5b755a5 100644
--- a/src/test/test_slow.c
+++ b/src/test/test_slow.c
@@ -22,6 +22,7 @@ struct testgroup_t testgroups[] = {
{ "slow/crypto/", slow_crypto_tests },
{ "slow/process/", slow_process_tests },
{ "slow/prob_distr/", slow_stochastic_prob_distr_tests },
+ { "slow/ptr/", slow_ptr_tests },
END_OF_GROUPS
};