summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/address.c3
-rw-r--r--src/common/compat.c10
-rw-r--r--src/common/crypto.c40
-rw-r--r--src/common/sandbox.c5
-rw-r--r--src/common/timers.c14
-rw-r--r--src/common/timers.h2
-rw-r--r--src/common/util.c23
-rw-r--r--src/or/circuitbuild.c6
-rw-r--r--src/or/circuitbuild.h5
-rw-r--r--src/or/circuituse.c188
-rw-r--r--src/or/circuituse.h20
-rw-r--r--src/or/config.c36
-rw-r--r--src/or/connection.c11
-rw-r--r--src/or/connection_edge.c8
-rw-r--r--src/or/control.c4
-rw-r--r--src/or/directory.c6
-rw-r--r--src/or/dirserv.c12
-rw-r--r--src/or/hs_descriptor.c59
-rw-r--r--src/or/hs_descriptor.h1
-rw-r--r--src/or/include.am2
-rw-r--r--src/or/networkstatus.c42
-rw-r--r--src/or/networkstatus.h2
-rw-r--r--src/or/nodelist.c4
-rw-r--r--src/or/nodelist.h3
-rw-r--r--src/or/protover.c2
-rw-r--r--src/or/rendservice.c492
-rw-r--r--src/or/rendservice.h16
-rw-r--r--src/or/router.c39
-rw-r--r--src/or/router.h3
-rw-r--r--src/or/routerkeys.c22
-rw-r--r--src/or/routerlist.c20
-rw-r--r--src/or/routerparse.c8
-rw-r--r--src/or/shared_random.c6
-rw-r--r--src/or/torcert.c50
-rw-r--r--src/or/torcert.h2
-rw-r--r--src/or/transports.c2
-rw-r--r--src/test/include.am1
-rw-r--r--src/test/log_test_helpers.h17
-rw-r--r--src/test/test.c1
-rw-r--r--src/test/test.h1
-rw-r--r--src/test/test_address.c18
-rw-r--r--src/test/test_circuituse.c302
-rw-r--r--src/test/test_config.c4
-rw-r--r--src/test/test_dir.c7
-rw-r--r--src/test/test_helpers.c23
-rw-r--r--src/test/test_helpers.h2
-rw-r--r--src/test/test_hs.c133
-rw-r--r--src/test/test_hs_descriptor.c2
-rw-r--r--src/test/test_oom.c19
-rw-r--r--src/test/test_options.c30
-rw-r--r--src/test/test_util.c4
51 files changed, 1255 insertions, 477 deletions
diff --git a/src/common/address.c b/src/common/address.c
index 773e688554..fa6630ef92 100644
--- a/src/common/address.c
+++ b/src/common/address.c
@@ -2100,7 +2100,8 @@ get_interface_address,(int severity, uint32_t *addr))
}
/** Return true if we can tell that <b>name</b> is a canonical name for the
- * loopback address. */
+ * loopback address. Return true also for *.local hostnames, which are
+ * multicast DNS names for hosts on the local network. */
int
tor_addr_hostname_is_local(const char *name)
{
diff --git a/src/common/compat.c b/src/common/compat.c
index 8d6a491c42..ebf05f59e1 100644
--- a/src/common/compat.c
+++ b/src/common/compat.c
@@ -204,7 +204,15 @@ tor_rename(const char *path_old, const char *path_new)
sandbox_intern_string(path_new));
}
-#if defined(HAVE_SYS_MMAN_H) || defined(RUNNING_DOXYGEN)
+/* Some MinGW builds have sys/mman.h, but not the corresponding symbols.
+ * Other configs rename the symbols using macros (including getpagesize).
+ * So check for sys/mman.h and unistd.h, and a getpagesize declaration. */
+#if (defined(HAVE_SYS_MMAN_H) && defined(HAVE_UNISTD_H) && \
+ defined(HAVE_DECL_GETPAGESIZE))
+#define COMPAT_HAS_MMAN_AND_PAGESIZE
+#endif
+
+#if defined(COMPAT_HAS_MMAN_AND_PAGESIZE) || defined(RUNNING_DOXYGEN)
/** Try to create a memory mapping for <b>filename</b> and return it. On
* failure, return NULL. Sets errno properly, using ERANGE to mean
* "empty file". */
diff --git a/src/common/crypto.c b/src/common/crypto.c
index fff516cc8e..be42d36af6 100644
--- a/src/common/crypto.c
+++ b/src/common/crypto.c
@@ -1506,7 +1506,7 @@ crypto_pk_get_hashed_fingerprint(crypto_pk_t *pk, char *fp_out)
if (crypto_pk_get_digest(pk, digest)) {
return -1;
}
- if (crypto_digest(hashed_digest, digest, DIGEST_LEN)) {
+ if (crypto_digest(hashed_digest, digest, DIGEST_LEN) < 0) {
return -1;
}
base16_encode(fp_out, FINGERPRINT_LEN + 1, hashed_digest, DIGEST_LEN);
@@ -1700,19 +1700,21 @@ crypto_cipher_decrypt_with_iv(const char *key,
/** Compute the SHA1 digest of the <b>len</b> bytes on data stored in
* <b>m</b>. Write the DIGEST_LEN byte result into <b>digest</b>.
- * Return 0 on success, 1 on failure.
+ * Return 0 on success, -1 on failure.
*/
int
crypto_digest(char *digest, const char *m, size_t len)
{
tor_assert(m);
tor_assert(digest);
- return (SHA1((const unsigned char*)m,len,(unsigned char*)digest) == NULL);
+ if (SHA1((const unsigned char*)m,len,(unsigned char*)digest) == NULL)
+ return -1;
+ return 0;
}
/** Compute a 256-bit digest of <b>len</b> bytes in data stored in <b>m</b>,
* using the algorithm <b>algorithm</b>. Write the DIGEST_LEN256-byte result
- * into <b>digest</b>. Return 0 on success, 1 on failure. */
+ * into <b>digest</b>. Return 0 on success, -1 on failure. */
int
crypto_digest256(char *digest, const char *m, size_t len,
digest_algorithm_t algorithm)
@@ -1720,16 +1722,22 @@ crypto_digest256(char *digest, const char *m, size_t len,
tor_assert(m);
tor_assert(digest);
tor_assert(algorithm == DIGEST_SHA256 || algorithm == DIGEST_SHA3_256);
+
+ int ret = 0;
if (algorithm == DIGEST_SHA256)
- return (SHA256((const uint8_t*)m,len,(uint8_t*)digest) == NULL);
+ ret = (SHA256((const uint8_t*)m,len,(uint8_t*)digest) != NULL);
else
- return (sha3_256((uint8_t *)digest, DIGEST256_LEN,(const uint8_t *)m, len)
- == -1);
+ ret = (sha3_256((uint8_t *)digest, DIGEST256_LEN,(const uint8_t *)m, len)
+ > -1);
+
+ if (!ret)
+ return -1;
+ return 0;
}
/** Compute a 512-bit digest of <b>len</b> bytes in data stored in <b>m</b>,
* using the algorithm <b>algorithm</b>. Write the DIGEST_LEN512-byte result
- * into <b>digest</b>. Return 0 on success, 1 on failure. */
+ * into <b>digest</b>. Return 0 on success, -1 on failure. */
int
crypto_digest512(char *digest, const char *m, size_t len,
digest_algorithm_t algorithm)
@@ -1737,12 +1745,18 @@ crypto_digest512(char *digest, const char *m, size_t len,
tor_assert(m);
tor_assert(digest);
tor_assert(algorithm == DIGEST_SHA512 || algorithm == DIGEST_SHA3_512);
+
+ int ret = 0;
if (algorithm == DIGEST_SHA512)
- return (SHA512((const unsigned char*)m,len,(unsigned char*)digest)
- == NULL);
+ ret = (SHA512((const unsigned char*)m,len,(unsigned char*)digest)
+ != NULL);
else
- return (sha3_512((uint8_t*)digest, DIGEST512_LEN, (const uint8_t*)m, len)
- == -1);
+ ret = (sha3_512((uint8_t*)digest, DIGEST512_LEN, (const uint8_t*)m, len)
+ > -1);
+
+ if (!ret)
+ return -1;
+ return 0;
}
/** Set the common_digests_t in <b>ds_out</b> to contain every digest on the
@@ -2628,7 +2642,7 @@ crypto_expand_key_material_TAP(const uint8_t *key_in, size_t key_in_len,
for (cp = key_out, i=0; cp < key_out+key_out_len;
++i, cp += DIGEST_LEN) {
tmp[key_in_len] = i;
- if (crypto_digest((char*)digest, (const char *)tmp, key_in_len+1))
+ if (crypto_digest((char*)digest, (const char *)tmp, key_in_len+1) < 0)
goto exit;
memcpy(cp, digest, MIN(DIGEST_LEN, key_out_len-(cp-key_out)));
}
diff --git a/src/common/sandbox.c b/src/common/sandbox.c
index 24ba8a2997..ebc843e130 100644
--- a/src/common/sandbox.c
+++ b/src/common/sandbox.c
@@ -1579,13 +1579,14 @@ sandbox_add_addrinfo(const char *name)
void
sandbox_free_getaddrinfo_cache(void)
{
- cached_getaddrinfo_item_t **next, **item;
+ cached_getaddrinfo_item_t **next, **item, *this;
for (item = HT_START(getaddrinfo_cache, &getaddrinfo_cache);
item;
item = next) {
+ this = *item;
next = HT_NEXT_RMV(getaddrinfo_cache, &getaddrinfo_cache, item);
- cached_getaddrinfo_item_free(*item);
+ cached_getaddrinfo_item_free(this);
}
HT_CLEAR(getaddrinfo_cache, &getaddrinfo_cache);
diff --git a/src/common/timers.c b/src/common/timers.c
index 41b2008ac4..e1ad47b15b 100644
--- a/src/common/timers.c
+++ b/src/common/timers.c
@@ -255,6 +255,20 @@ timer_set_cb(tor_timer_t *t, timer_cb_fn_t cb, void *arg)
}
/**
+ * Set *<b>cb_out</b> (if provided) to this timer's callback function,
+ * and *<b>arg_out</b> (if provided) to this timer's callback argument.
+ */
+void
+timer_get_cb(const tor_timer_t *t,
+ timer_cb_fn_t *cb_out, void **arg_out)
+{
+ if (cb_out)
+ *cb_out = t->callback.cb;
+ if (arg_out)
+ *arg_out = t->callback.arg;
+}
+
+/**
* Schedule the timer t to fire at the current time plus a delay of
* <b>delay</b> microseconds. All times are relative to monotime_get().
*/
diff --git a/src/common/timers.h b/src/common/timers.h
index 5f918f8e15..c5246a3335 100644
--- a/src/common/timers.h
+++ b/src/common/timers.h
@@ -13,6 +13,8 @@ typedef void (*timer_cb_fn_t)(tor_timer_t *, void *,
const struct monotime_t *);
tor_timer_t *timer_new(timer_cb_fn_t cb, void *arg);
void timer_set_cb(tor_timer_t *t, timer_cb_fn_t cb, void *arg);
+void timer_get_cb(const tor_timer_t *t,
+ timer_cb_fn_t *cb_out, void **arg_out);
void timer_schedule(tor_timer_t *t, const struct timeval *delay);
void timer_disable(tor_timer_t *t);
void timer_free(tor_timer_t *t);
diff --git a/src/common/util.c b/src/common/util.c
index cb5f12821e..417aa89433 100644
--- a/src/common/util.c
+++ b/src/common/util.c
@@ -2270,10 +2270,14 @@ check_private_dir,(const char *dirname, cpd_check_t check,
* permissions on the directory will be checked again below.*/
fd = open(sandbox_intern_string(dirname), O_NOFOLLOW);
- if (fd == -1)
+ if (fd == -1) {
+ log_warn(LD_FS, "Could not reopen recently created directory %s: %s",
+ dirname,
+ strerror(errno));
return -1;
- else
+ } else {
close(fd);
+ }
} else if (!(check & CPD_CHECK)) {
log_warn(LD_FS, "Directory %s does not exist.", dirname);
@@ -2601,6 +2605,14 @@ finish_writing_to_file_impl(open_file_t *file_data, int abort_write)
if (file_data->rename_on_close) {
tor_assert(file_data->tempname && file_data->filename);
+ if (!abort_write) {
+ tor_assert(strcmp(file_data->filename, file_data->tempname));
+ if (replace_file(file_data->tempname, file_data->filename)) {
+ log_warn(LD_FS, "Error replacing \"%s\": %s", file_data->filename,
+ strerror(errno));
+ abort_write = r = -1;
+ }
+ }
if (abort_write) {
int res = unlink(file_data->tempname);
if (res != 0) {
@@ -2609,13 +2621,6 @@ finish_writing_to_file_impl(open_file_t *file_data, int abort_write)
file_data->tempname, strerror(errno));
r = -1;
}
- } else {
- tor_assert(strcmp(file_data->filename, file_data->tempname));
- if (replace_file(file_data->tempname, file_data->filename)) {
- log_warn(LD_FS, "Error replacing \"%s\": %s", file_data->filename,
- strerror(errno));
- r = -1;
- }
}
}
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c
index 96bd472dba..f60a8bfa89 100644
--- a/src/or/circuitbuild.c
+++ b/src/or/circuitbuild.c
@@ -1537,9 +1537,9 @@ circuit_get_unhandled_ports(time_t now)
* If we're returning 0, set need_uptime and need_capacity to
* indicate any requirements that the unhandled ports have.
*/
-int
-circuit_all_predicted_ports_handled(time_t now, int *need_uptime,
- int *need_capacity)
+MOCK_IMPL(int,
+circuit_all_predicted_ports_handled, (time_t now, int *need_uptime,
+ int *need_capacity))
{
int i, enough;
uint16_t *port;
diff --git a/src/or/circuitbuild.h b/src/or/circuitbuild.h
index f71c116eda..54d14bbc7f 100644
--- a/src/or/circuitbuild.h
+++ b/src/or/circuitbuild.h
@@ -40,8 +40,9 @@ int onionskin_answer(or_circuit_t *circ,
const struct created_cell_t *created_cell,
const char *keys,
const uint8_t *rend_circ_nonce);
-int circuit_all_predicted_ports_handled(time_t now, int *need_uptime,
- int *need_capacity);
+MOCK_DECL(int, circuit_all_predicted_ports_handled, (time_t now,
+ int *need_uptime,
+ int *need_capacity));
int circuit_append_new_exit(origin_circuit_t *circ, extend_info_t *info);
int circuit_extend_to_new_exit(origin_circuit_t *circ, extend_info_t *info);
diff --git a/src/or/circuituse.c b/src/or/circuituse.c
index eaecfd9dc0..04c5af92e8 100644
--- a/src/or/circuituse.c
+++ b/src/or/circuituse.c
@@ -1022,8 +1022,117 @@ circuit_stream_is_being_handled(entry_connection_t *conn,
/** Don't keep more than this many unused open circuits around. */
#define MAX_UNUSED_OPEN_CIRCUITS 14
-/** Figure out how many circuits we have open that are clean. Make
- * sure it's enough for all the upcoming behaviors we predict we'll have.
+/* Return true if a circuit is available for use, meaning that it is open,
+ * clean, usable for new multi-hop connections, and a general purpose origin
+ * circuit.
+ * Accept any kind of circuit, return false if the above conditions are not
+ * met. */
+STATIC int
+circuit_is_available_for_use(const circuit_t *circ)
+{
+ const origin_circuit_t *origin_circ;
+ cpath_build_state_t *build_state;
+
+ if (!CIRCUIT_IS_ORIGIN(circ))
+ return 0; /* We first filter out only origin circuits before doing the
+ following checks. */
+ if (circ->marked_for_close)
+ return 0; /* Don't mess with marked circs */
+ if (circ->timestamp_dirty)
+ return 0; /* Only count clean circs */
+ if (circ->purpose != CIRCUIT_PURPOSE_C_GENERAL)
+ return 0; /* We only pay attention to general purpose circuits.
+ General purpose circuits are always origin circuits. */
+
+ origin_circ = CONST_TO_ORIGIN_CIRCUIT(circ);
+ if (origin_circ->unusable_for_new_conns)
+ return 0;
+
+ build_state = origin_circ->build_state;
+ if (build_state->onehop_tunnel)
+ return 0;
+
+ return 1;
+}
+
+/* Return true if we need any more exit circuits.
+ * needs_uptime and needs_capacity are set only if we need more exit circuits.
+ * Check if we know of a port that's been requested recently and no circuit
+ * is currently available that can handle it. */
+STATIC int
+needs_exit_circuits(time_t now, int *needs_uptime, int *needs_capacity)
+{
+ return (!circuit_all_predicted_ports_handled(now, needs_uptime,
+ needs_capacity) &&
+ router_have_consensus_path() == CONSENSUS_PATH_EXIT);
+}
+
+/* Hidden services need at least this many internal circuits */
+#define SUFFICIENT_UPTIME_INTERNAL_HS_SERVERS 3
+
+/* Return true if we need any more hidden service server circuits.
+ * HS servers only need an internal circuit. */
+STATIC int
+needs_hs_server_circuits(int num_uptime_internal)
+{
+ return (num_rend_services() &&
+ num_uptime_internal < SUFFICIENT_UPTIME_INTERNAL_HS_SERVERS &&
+ router_have_consensus_path() != CONSENSUS_PATH_UNKNOWN);
+}
+
+/* We need at least this many internal circuits for hidden service clients */
+#define SUFFICIENT_INTERNAL_HS_CLIENTS 3
+
+/* We need at least this much uptime for internal circuits for hidden service
+ * clients */
+#define SUFFICIENT_UPTIME_INTERNAL_HS_CLIENTS 2
+
+/* Return true if we need any more hidden service client circuits.
+ * HS clients only need an internal circuit. */
+STATIC int
+needs_hs_client_circuits(time_t now, int *needs_uptime, int *needs_capacity,
+ int num_internal, int num_uptime_internal)
+{
+ int used_internal_recently = rep_hist_get_predicted_internal(now,
+ needs_uptime,
+ needs_capacity);
+ int requires_uptime = num_uptime_internal <
+ SUFFICIENT_UPTIME_INTERNAL_HS_CLIENTS &&
+ needs_uptime;
+
+ return (used_internal_recently &&
+ (requires_uptime || num_internal < SUFFICIENT_INTERNAL_HS_CLIENTS) &&
+ router_have_consensus_path() != CONSENSUS_PATH_UNKNOWN);
+}
+
+/* The minimum number of open slots we should keep in order to preemptively
+ * build circuits. */
+#define CBT_MIN_REMAINING_PREEMPTIVE_CIRCUITS 2
+
+/* Check to see if we need more circuits to have a good build timeout. However,
+ * leave a couple slots open so that we can still build circuits preemptively
+ * as needed. */
+#define CBT_MAX_UNUSED_OPEN_CIRCUITS (MAX_UNUSED_OPEN_CIRCUITS - \
+ CBT_MIN_REMAINING_PREEMPTIVE_CIRCUITS)
+
+/* Return true if we need more circuits for a good build timeout.
+ * XXXX make the assumption that build timeout streams should be
+ * created whenever we can build internal circuits. */
+STATIC int
+needs_circuits_for_build(int num)
+{
+ if (router_have_consensus_path() != CONSENSUS_PATH_UNKNOWN) {
+ if (num < CBT_MAX_UNUSED_OPEN_CIRCUITS &&
+ !circuit_build_times_disabled() &&
+ circuit_build_times_needs_circuits_now(get_circuit_build_times())) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/** Determine how many circuits we have open that are clean,
+ * Make sure it's enough for all the upcoming behaviors we predict we'll have.
* But put an upper bound on the total number of circuits.
*/
static void
@@ -1035,25 +1144,14 @@ circuit_predict_and_launch_new(void)
time_t now = time(NULL);
int flags = 0;
- /* First, count how many of each type of circuit we have already. */
+ /* Count how many of each type of circuit we currently have. */
SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
- cpath_build_state_t *build_state;
- origin_circuit_t *origin_circ;
- if (!CIRCUIT_IS_ORIGIN(circ))
- continue;
- if (circ->marked_for_close)
- continue; /* don't mess with marked circs */
- if (circ->timestamp_dirty)
- continue; /* only count clean circs */
- if (circ->purpose != CIRCUIT_PURPOSE_C_GENERAL)
- continue; /* only pay attention to general-purpose circs */
- origin_circ = TO_ORIGIN_CIRCUIT(circ);
- if (origin_circ->unusable_for_new_conns)
- continue;
- build_state = origin_circ->build_state;
- if (build_state->onehop_tunnel)
+ if (!circuit_is_available_for_use(circ))
continue;
+
num++;
+
+ cpath_build_state_t *build_state = TO_ORIGIN_CIRCUIT(circ)->build_state;
if (build_state->is_internal)
num_internal++;
if (build_state->need_uptime && build_state->is_internal)
@@ -1063,19 +1161,14 @@ circuit_predict_and_launch_new(void)
/* If that's enough, then stop now. */
if (num >= MAX_UNUSED_OPEN_CIRCUITS)
- return; /* we already have many, making more probably will hurt */
-
- /* Second, see if we need any more exit circuits. */
- /* check if we know of a port that's been requested recently
- * and no circuit is currently available that can handle it.
- * Exits (obviously) require an exit circuit. */
- if (!circuit_all_predicted_ports_handled(now, &port_needs_uptime,
- &port_needs_capacity)
- && router_have_consensus_path() == CONSENSUS_PATH_EXIT) {
+ return;
+
+ if (needs_exit_circuits(now, &port_needs_uptime, &port_needs_capacity)) {
if (port_needs_uptime)
flags |= CIRCLAUNCH_NEED_UPTIME;
if (port_needs_capacity)
flags |= CIRCLAUNCH_NEED_CAPACITY;
+
log_info(LD_CIRC,
"Have %d clean circs (%d internal), need another exit circ.",
num, num_internal);
@@ -1083,12 +1176,10 @@ circuit_predict_and_launch_new(void)
return;
}
- /* Third, see if we need any more hidden service (server) circuits.
- * HS servers only need an internal circuit. */
- if (num_rend_services() && num_uptime_internal < 3
- && router_have_consensus_path() != CONSENSUS_PATH_UNKNOWN) {
+ if (needs_hs_server_circuits(num_uptime_internal)) {
flags = (CIRCLAUNCH_NEED_CAPACITY | CIRCLAUNCH_NEED_UPTIME |
CIRCLAUNCH_IS_INTERNAL);
+
log_info(LD_CIRC,
"Have %d clean circs (%d internal), need another internal "
"circ for my hidden service.",
@@ -1097,18 +1188,16 @@ circuit_predict_and_launch_new(void)
return;
}
- /* Fourth, see if we need any more hidden service (client) circuits.
- * HS clients only need an internal circuit. */
- if (rep_hist_get_predicted_internal(now, &hidserv_needs_uptime,
- &hidserv_needs_capacity) &&
- ((num_uptime_internal<2 && hidserv_needs_uptime) ||
- num_internal<3)
- && router_have_consensus_path() != CONSENSUS_PATH_UNKNOWN) {
+ if (needs_hs_client_circuits(now, &hidserv_needs_uptime,
+ &hidserv_needs_capacity,
+ num_internal, num_uptime_internal))
+ {
if (hidserv_needs_uptime)
flags |= CIRCLAUNCH_NEED_UPTIME;
if (hidserv_needs_capacity)
flags |= CIRCLAUNCH_NEED_CAPACITY;
flags |= CIRCLAUNCH_IS_INTERNAL;
+
log_info(LD_CIRC,
"Have %d clean circs (%d uptime-internal, %d internal), need"
" another hidden service circ.",
@@ -1117,26 +1206,17 @@ circuit_predict_and_launch_new(void)
return;
}
- /* Finally, check to see if we still need more circuits to learn
- * a good build timeout. But if we're close to our max number we
- * want, don't do another -- we want to leave a few slots open so
- * we can still build circuits preemptively as needed.
- * XXXX make the assumption that build timeout streams should be
- * created whenever we can build internal circuits. */
- if (router_have_consensus_path() != CONSENSUS_PATH_UNKNOWN) {
- if (num < MAX_UNUSED_OPEN_CIRCUITS-2 &&
- ! circuit_build_times_disabled() &&
- circuit_build_times_needs_circuits_now(get_circuit_build_times())) {
- flags = CIRCLAUNCH_NEED_CAPACITY;
- /* if there are no exits in the consensus, make timeout
- * circuits internal */
- if (router_have_consensus_path() == CONSENSUS_PATH_INTERNAL)
- flags |= CIRCLAUNCH_IS_INTERNAL;
+ if (needs_circuits_for_build(num)) {
+ flags = CIRCLAUNCH_NEED_CAPACITY;
+ /* if there are no exits in the consensus, make timeout
+ * circuits internal */
+ if (router_have_consensus_path() == CONSENSUS_PATH_INTERNAL)
+ flags |= CIRCLAUNCH_IS_INTERNAL;
+
log_info(LD_CIRC,
"Have %d clean circs need another buildtime test circ.", num);
circuit_launch(CIRCUIT_PURPOSE_C_GENERAL, flags);
return;
- }
}
}
diff --git a/src/or/circuituse.h b/src/or/circuituse.h
index 5973978c45..d484be1986 100644
--- a/src/or/circuituse.h
+++ b/src/or/circuituse.h
@@ -59,5 +59,25 @@ int hostname_in_track_host_exits(const or_options_t *options,
const char *address);
void mark_circuit_unusable_for_new_conns(origin_circuit_t *circ);
+#ifdef TOR_UNIT_TESTS
+/* Used only by circuituse.c and test_circuituse.c */
+
+STATIC int circuit_is_available_for_use(const circuit_t *circ);
+
+STATIC int needs_exit_circuits(time_t now,
+ int *port_needs_uptime,
+ int *port_needs_capacity);
+STATIC int needs_hs_server_circuits(int num_uptime_internal);
+
+STATIC int needs_hs_client_circuits(time_t now,
+ int *needs_uptime,
+ int *needs_capacity,
+ int num_internal,
+ int num_uptime_internal);
+
+STATIC int needs_circuits_for_build(int num);
+
+#endif
+
#endif
diff --git a/src/or/config.c b/src/or/config.c
index d100af812c..6948bdbdb4 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -1780,25 +1780,6 @@ options_act(const or_options_t *old_options)
monitor_owning_controller_process(options->OwningControllerProcess);
- /* We must create new keys after we poison the directories, because our
- * poisoning code checks for existing keys, and refuses to modify their
- * directories. */
-
- /* If we use non-anonymous single onion services, make sure we poison any
- new hidden service directories, so that we never accidentally launch the
- non-anonymous hidden services thinking they are anonymous. */
- if (running_tor && rend_service_non_anonymous_mode_enabled(options)) {
- if (options->RendConfigLines && !num_rend_services()) {
- log_warn(LD_BUG,"Error: hidden services configured, but not parsed.");
- return -1;
- }
- if (rend_service_poison_new_single_onion_dirs(NULL) < 0) {
- log_warn(LD_GENERAL,"Failed to mark new hidden services as non-anonymous"
- ".");
- return -1;
- }
- }
-
/* reload keys as needed for rendezvous services. */
if (rend_service_load_all_keys(NULL)<0) {
log_warn(LD_GENERAL,"Error loading rendezvous service keys");
@@ -2942,21 +2923,6 @@ options_validate_single_onion(or_options_t *options, char **msg)
options->UseEntryGuards = 0;
}
- /* Check if existing hidden service keys were created in a different
- * single onion service mode, and refuse to launch if they
- * have. We'll poison new keys in options_act() just before we create them.
- */
- if (rend_service_list_verify_single_onion_poison(NULL, options) < 0) {
- log_warn(LD_GENERAL, "We are configured with "
- "HiddenServiceNonAnonymousMode %d, but one or more hidden "
- "service keys were created in %s mode. This is not allowed.",
- rend_service_non_anonymous_mode_enabled(options) ? 1 : 0,
- rend_service_non_anonymous_mode_enabled(options) ?
- "an anonymous" : "a non-anonymous"
- );
- return -1;
- }
-
return 0;
}
@@ -3089,7 +3055,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
} else if (!strcasecmp(options->TransProxyType, "ipfw")) {
#ifndef KERNEL_MAY_SUPPORT_IPFW
/* Earlier versions of OS X have ipfw */
- REJECT("ipfw is a FreeBSD-specific"
+ REJECT("ipfw is a FreeBSD-specific "
"and OS X/Darwin-specific feature.");
#else
options->TransProxyType_parsed = TPT_IPFW;
diff --git a/src/or/connection.c b/src/or/connection.c
index f80602155b..ac3408a72e 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -1595,16 +1595,19 @@ connection_handle_listener_read(connection_t *conn, int new_type)
/* remember the remote address */
tor_addr_copy(&newconn->addr, &addr);
- newconn->port = port;
- newconn->address = tor_addr_to_str_dup(&addr);
+ if (new_type == CONN_TYPE_AP && conn->socket_family == AF_UNIX) {
+ newconn->port = 0;
+ newconn->address = tor_strdup(conn->address);
+ } else {
+ newconn->port = port;
+ newconn->address = tor_addr_to_str_dup(&addr);
+ }
if (new_type == CONN_TYPE_AP && conn->socket_family != AF_UNIX) {
log_info(LD_NET, "New SOCKS connection opened from %s.",
fmt_and_decorate_addr(&addr));
}
if (new_type == CONN_TYPE_AP && conn->socket_family == AF_UNIX) {
- newconn->port = 0;
- newconn->address = tor_strdup(conn->address);
log_info(LD_NET, "New SOCKS AF_UNIX connection opened");
}
if (new_type == CONN_TYPE_CONTROL) {
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c
index 875c911f01..3874d52c23 100644
--- a/src/or/connection_edge.c
+++ b/src/or/connection_edge.c
@@ -1627,11 +1627,9 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
}
tor_assert(!automap);
rep_hist_note_used_resolve(now); /* help predict this next time */
- }
+ } else if (socks->command == SOCKS_COMMAND_CONNECT) {
+ /* Now see if this is a connect request that we can reject immediately */
- /* Now see if this is a connect request that we can reject immediately */
- if (socks->command == SOCKS_COMMAND_CONNECT) {
- /* Special handling for attempts to connect */
tor_assert(!automap);
/* Don't allow connections to port 0. */
if (socks->port == 0) {
@@ -1771,7 +1769,7 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
rep_hist_note_used_resolve(now); /* help predict this next time */
/* no extra processing needed */
} else {
- /* We should only be doing CONNECT or RESOLVE! */
+ /* We should only be doing CONNECT, RESOLVE, or RESOLVE_PTR! */
tor_fragile_assert();
}
diff --git a/src/or/control.c b/src/or/control.c
index 96cc41bc4b..a22113174a 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -1705,7 +1705,7 @@ getinfo_helper_misc(control_connection_t *conn, const char *question,
*answer = tor_strdup("VERBOSE_NAMES EXTENDED_EVENTS");
} else if (!strcmp(question, "address")) {
uint32_t addr;
- if (router_pick_published_address(get_options(), &addr) < 0) {
+ if (router_pick_published_address(get_options(), &addr, 0) < 0) {
*errmsg = "Address unknown";
return -1;
}
@@ -2029,7 +2029,7 @@ getinfo_helper_dir(control_connection_t *control_conn,
} else if (!strcmpstart(question, "dir/status/")) {
*answer = tor_strdup("");
} else if (!strcmp(question, "dir/status-vote/current/consensus")) { /* v3 */
- if (directory_caches_dir_info(get_options())) {
+ if (we_want_to_fetch_flavor(get_options(), FLAV_NS)) {
const cached_dir_t *consensus = dirserv_get_consensus("ns");
if (consensus)
*answer = tor_strdup(consensus->dir);
diff --git a/src/or/directory.c b/src/or/directory.c
index 65ddd7d583..f0affbd395 100644
--- a/src/or/directory.c
+++ b/src/or/directory.c
@@ -3988,10 +3988,12 @@ STATIC int
next_random_exponential_delay(int delay, int max_delay)
{
/* Check preconditions */
+ if (BUG(max_delay < 0))
+ max_delay = 0;
if (BUG(delay > max_delay))
delay = max_delay;
- if (BUG(delay == INT_MAX))
- delay -= 1; /* prevent overflow */
+ if (delay == INT_MAX)
+ return INT_MAX; /* prevent overflow */
if (BUG(delay < 0))
delay = 0;
diff --git a/src/or/dirserv.c b/src/or/dirserv.c
index 0b896a2845..399d5ea955 100644
--- a/src/or/dirserv.c
+++ b/src/or/dirserv.c
@@ -1033,7 +1033,8 @@ directory_fetches_from_authorities(const or_options_t *options)
return 1;
if (options->BridgeRelay == 1)
return 0;
- if (server_mode(options) && router_pick_published_address(options, &addr)<0)
+ if (server_mode(options) &&
+ router_pick_published_address(options, &addr, 1) < 0)
return 1; /* we don't know our IP address; ask an authority. */
refuseunknown = ! router_my_exit_policy_is_reject_star() &&
should_refuse_unknown_exits(options);
@@ -1068,8 +1069,10 @@ directory_fetches_dir_info_later(const or_options_t *options)
return options->UseBridges != 0;
}
-/** Return true iff we want to fetch and keep certificates for authorities
+/** Return true iff we want to serve certificates for authorities
* that we don't acknowledge as authorities ourself.
+ * Use we_want_to_fetch_unknown_auth_certs to check if we want to fetch
+ * and keep these certificates.
*/
int
directory_caches_unknown_auth_certs(const or_options_t *options)
@@ -1077,11 +1080,14 @@ directory_caches_unknown_auth_certs(const or_options_t *options)
return dir_server_mode(options) || options->BridgeRelay;
}
-/** Return 1 if we want to keep descriptors, networkstatuses, etc around.
+/** Return 1 if we want to fetch and serve descriptors, networkstatuses, etc
* Else return 0.
* Check options->DirPort_set and directory_permits_begindir_requests()
* to see if we are willing to serve these directory documents to others via
* the DirPort and begindir-over-ORPort, respectively.
+ *
+ * To check if we should fetch documents, use we_want_to_fetch_flavor and
+ * we_want_to_fetch_unknown_auth_certs instead of this function.
*/
int
directory_caches_dir_info(const or_options_t *options)
diff --git a/src/or/hs_descriptor.c b/src/or/hs_descriptor.c
index 1517ccb12e..37aa1d745e 100644
--- a/src/or/hs_descriptor.c
+++ b/src/or/hs_descriptor.c
@@ -15,6 +15,7 @@
#include "ed25519_cert.h" /* Trunnel interface. */
#include "parsecommon.h"
#include "rendcache.h"
+#include "torcert.h" /* tor_cert_encode_ed22519() */
/* Constant string value used for the descriptor format. */
#define str_hs_desc "hs-descriptor"
@@ -135,45 +136,6 @@ desc_encrypted_data_free_contents(hs_desc_encrypted_data_t *desc)
/* === ENCODING === */
-/* Encode the ed25519 certificate <b>cert</b> and put the newly allocated
- * string in <b>cert_str_out</b>. Return 0 on success else a negative value. */
-STATIC int
-encode_cert(const tor_cert_t *cert, char **cert_str_out)
-{
- int ret = -1;
- char *ed_cert_b64 = NULL;
- size_t ed_cert_b64_len;
-
- tor_assert(cert);
- tor_assert(cert_str_out);
-
- /* Get the encoded size and add the NUL byte. */
- ed_cert_b64_len = base64_encode_size(cert->encoded_len,
- BASE64_ENCODE_MULTILINE) + 1;
- ed_cert_b64 = tor_malloc_zero(ed_cert_b64_len);
-
- /* Base64 encode the encoded certificate. */
- if (base64_encode(ed_cert_b64, ed_cert_b64_len,
- (const char *) cert->encoded, cert->encoded_len,
- BASE64_ENCODE_MULTILINE) < 0) {
- log_err(LD_BUG, "Couldn't base64-encode descriptor signing key cert!");
- goto err;
- }
-
- /* Put everything together in a NUL terminated string. */
- tor_asprintf(cert_str_out,
- "-----BEGIN ED25519 CERT-----\n"
- "%s"
- "-----END ED25519 CERT-----",
- ed_cert_b64);
- /* Success! */
- ret = 0;
-
- err:
- tor_free(ed_cert_b64);
- return ret;
-}
-
/* Encode the given link specifier objects into a newly allocated string.
* This can't fail so caller can always assume a valid string being
* returned. */
@@ -327,7 +289,7 @@ encode_enc_key(const ed25519_keypair_t *sig_key,
if (!cross_cert) {
goto err;
}
- ret = encode_cert(cross_cert, &encoded_cert);
+ ret = tor_cert_encode_ed22519(cross_cert, &encoded_cert);
tor_cert_free(cross_cert);
if (ret) {
goto err;
@@ -375,7 +337,7 @@ encode_intro_point(const ed25519_keypair_t *sig_key,
/* Authentication key encoding. */
{
char *encoded_cert;
- if (encode_cert(ip->auth_key_cert, &encoded_cert) < 0) {
+ if (tor_cert_encode_ed22519(ip->auth_key_cert, &encoded_cert) < 0) {
goto err;
}
smartlist_add_asprintf(lines, "%s\n%s", str_ip_auth_key, encoded_cert);
@@ -769,7 +731,7 @@ desc_encode_v3(const hs_descriptor_t *desc, char **encoded_out)
"(%d)", (int) desc->plaintext_data.signing_key_cert->cert_type);
goto err;
}
- if (encode_cert(desc->plaintext_data.signing_key_cert,
+ if (tor_cert_encode_ed22519(desc->plaintext_data.signing_key_cert,
&encoded_cert) < 0) {
/* The function will print error logs. */
goto err;
@@ -1394,15 +1356,10 @@ decode_intro_points(const hs_descriptor_t *desc,
retval = 0;
err:
- if (chunked_desc) {
- SMARTLIST_FOREACH(chunked_desc, char *, a, tor_free(a));
- smartlist_free(chunked_desc);
- }
- if (intro_points) {
- SMARTLIST_FOREACH(intro_points, char *, a, tor_free(a));
- smartlist_free(intro_points);
- }
-
+ SMARTLIST_FOREACH(chunked_desc, char *, a, tor_free(a));
+ smartlist_free(chunked_desc);
+ SMARTLIST_FOREACH(intro_points, char *, a, tor_free(a));
+ smartlist_free(intro_points);
return retval;
}
/* Return 1 iff the given base64 encoded signature in b64_sig from the encoded
diff --git a/src/or/hs_descriptor.h b/src/or/hs_descriptor.h
index 895bed2485..083d353860 100644
--- a/src/or/hs_descriptor.h
+++ b/src/or/hs_descriptor.h
@@ -216,7 +216,6 @@ size_t hs_desc_plaintext_obj_size(const hs_desc_plaintext_data_t *data);
#ifdef HS_DESCRIPTOR_PRIVATE
/* Encoding. */
-STATIC int encode_cert(const tor_cert_t *cert, char **cert_str_out);
STATIC char *encode_link_specifiers(const smartlist_t *specs);
STATIC size_t build_plaintext_padding(const char *plaintext,
size_t plaintext_len,
diff --git a/src/or/include.am b/src/or/include.am
index 10f8b85bdf..99912a9947 100644
--- a/src/or/include.am
+++ b/src/or/include.am
@@ -206,7 +206,7 @@ noinst_HEADERS+= $(ORHEADERS) micro-revision.i
micro-revision.i: FORCE
$(AM_V_at)rm -f micro-revision.tmp; \
- if test -d "$(top_srcdir)/.git" && \
+ if test -r "$(top_srcdir)/.git" && \
test -x "`which git 2>&1;true`"; then \
HASH="`cd "$(top_srcdir)" && git rev-parse --short=16 HEAD`"; \
echo \"$$HASH\" > micro-revision.tmp; \
diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c
index 316ce48387..bfb36413ce 100644
--- a/src/or/networkstatus.c
+++ b/src/or/networkstatus.c
@@ -814,8 +814,11 @@ networkstatus_nickname_is_unnamed(const char *nickname)
#define NONAUTHORITY_NS_CACHE_INTERVAL (60*60)
/** Return true iff, given the options listed in <b>options</b>, <b>flavor</b>
- * is the flavor of a consensus networkstatus that we would like to fetch. */
-static int
+ * is the flavor of a consensus networkstatus that we would like to fetch.
+ *
+ * For certificate fetches, use we_want_to_fetch_unknown_auth_certs, and
+ * for serving fetched documents, use directory_caches_dir_info. */
+int
we_want_to_fetch_flavor(const or_options_t *options, int flavor)
{
if (flavor < 0 || flavor > N_CONSENSUS_FLAVORS) {
@@ -837,6 +840,29 @@ we_want_to_fetch_flavor(const or_options_t *options, int flavor)
return flavor == usable_consensus_flavor();
}
+/** Return true iff, given the options listed in <b>options</b>, we would like
+ * to fetch and store unknown authority certificates.
+ *
+ * For consensus and descriptor fetches, use we_want_to_fetch_flavor, and
+ * for serving fetched certificates, use directory_caches_unknown_auth_certs.
+ */
+int
+we_want_to_fetch_unknown_auth_certs(const or_options_t *options)
+{
+ if (authdir_mode_v3(options) ||
+ directory_caches_unknown_auth_certs((options))) {
+ /* We want to serve all certs to others, regardless if we would use
+ * them ourselves. */
+ return 1;
+ }
+ if (options->FetchUselessDescriptors) {
+ /* Unknown certificates are definitely useless. */
+ return 1;
+ }
+ /* Otherwise, don't fetch unknown certificates. */
+ return 0;
+}
+
/** How long will we hang onto a possibly live consensus for which we're
* fetching certs before we check whether there is a better one? */
#define DELAY_WHILE_FETCHING_CERTS (20*60)
@@ -1728,9 +1754,9 @@ networkstatus_set_current_consensus(const char *consensus,
}
if (flav != usable_consensus_flavor() &&
- !directory_caches_dir_info(options)) {
- /* This consensus is totally boring to us: we won't use it, and we won't
- * serve it. Drop it. */
+ !we_want_to_fetch_flavor(options, flav)) {
+ /* This consensus is totally boring to us: we won't use it, we didn't want
+ * it, and we won't serve it. Drop it. */
goto done;
}
@@ -1932,7 +1958,7 @@ networkstatus_set_current_consensus(const char *consensus,
download_status_failed(&consensus_dl_status[flav], 0);
}
- if (directory_caches_dir_info(options)) {
+ if (we_want_to_fetch_flavor(options, flav)) {
dirserv_set_cached_consensus_networkstatus(consensus,
flavor,
&c->digests,
@@ -2381,9 +2407,9 @@ int
client_would_use_router(const routerstatus_t *rs, time_t now,
const or_options_t *options)
{
- if (!rs->is_flagged_running && !options->FetchUselessDescriptors) {
+ if (!rs->is_flagged_running) {
/* If we had this router descriptor, we wouldn't even bother using it.
- * But, if we want to have a complete list, fetch it anyway. */
+ * (Fetching and storing depends on by we_want_to_fetch_flavor().) */
return 0;
}
if (rs->published_on + options->TestingEstimatedDescriptorPropagationTime
diff --git a/src/or/networkstatus.h b/src/or/networkstatus.h
index 71f36b69ed..454356e0bb 100644
--- a/src/or/networkstatus.h
+++ b/src/or/networkstatus.h
@@ -66,6 +66,8 @@ const routerstatus_t *router_get_consensus_status_by_nickname(
int warn_if_unnamed);
const char *networkstatus_get_router_digest_by_nickname(const char *nickname);
int networkstatus_nickname_is_unnamed(const char *nickname);
+int we_want_to_fetch_flavor(const or_options_t *options, int flavor);
+int we_want_to_fetch_unknown_auth_certs(const or_options_t *options);
void networkstatus_consensus_download_failed(int status_code,
const char *flavname);
void update_consensus_networkstatus_fetch_time(time_t now);
diff --git a/src/or/nodelist.c b/src/or/nodelist.c
index d8d2dbbfd4..6117b86d65 100644
--- a/src/or/nodelist.c
+++ b/src/or/nodelist.c
@@ -1639,8 +1639,8 @@ router_have_minimum_dir_info(void)
* this can cause router_have_consensus_path() to be set to
* CONSENSUS_PATH_EXIT, even if there are no nodes with accept exit policies.
*/
-consensus_path_type_t
-router_have_consensus_path(void)
+MOCK_IMPL(consensus_path_type_t,
+router_have_consensus_path, (void))
{
return have_consensus_path;
}
diff --git a/src/or/nodelist.h b/src/or/nodelist.h
index 31fdc64663..8456d21c6c 100644
--- a/src/or/nodelist.h
+++ b/src/or/nodelist.h
@@ -123,7 +123,8 @@ typedef enum {
* create exit and internal paths, circuits, streams, ... */
CONSENSUS_PATH_EXIT = 1
} consensus_path_type_t;
-consensus_path_type_t router_have_consensus_path(void);
+
+MOCK_DECL(consensus_path_type_t, router_have_consensus_path, (void));
void router_dir_info_changed(void);
const char *get_dir_info_status_string(void);
diff --git a/src/or/protover.c b/src/or/protover.c
index 5972e61be7..ceaf2d5ccf 100644
--- a/src/or/protover.c
+++ b/src/or/protover.c
@@ -697,7 +697,7 @@ protover_compute_for_old_tor(const char *version)
if (tor_version_as_new_as(version,
FIRST_TOR_VERSION_TO_ADVERTISE_PROTOCOLS)) {
return "";
- } else if (tor_version_as_new_as(version, "0.2.7.5")) {
+ } else if (tor_version_as_new_as(version, "0.2.9.1-alpha")) {
/* 0.2.9.1-alpha HSRend=2 */
return "Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 "
"Link=1-4 LinkAuth=1 "
diff --git a/src/or/rendservice.c b/src/or/rendservice.c
index 0819d8a713..545fba1449 100644
--- a/src/or/rendservice.c
+++ b/src/or/rendservice.c
@@ -76,6 +76,13 @@ static ssize_t rend_service_parse_intro_for_v3(
static int rend_service_check_private_dir(const or_options_t *options,
const rend_service_t *s,
int create);
+static int rend_service_check_private_dir_impl(const or_options_t *options,
+ const rend_service_t *s,
+ int create);
+static const smartlist_t* rend_get_service_list(
+ const smartlist_t* substitute_service_list);
+static smartlist_t* rend_get_service_list_mutable(
+ smartlist_t* substitute_service_list);
/** Represents the mapping from a virtual port of a rendezvous service to
* a real port on some IP.
@@ -121,8 +128,44 @@ static const char *hostname_fname = "hostname";
static const char *client_keys_fname = "client_keys";
static const char *sos_poison_fname = "onion_service_non_anonymous";
+/** A list of rend_service_t's for services run on this OP.
+ */
+static smartlist_t *rend_service_list = NULL;
+
+/* Like rend_get_service_list_mutable, but returns a read-only list. */
+static const smartlist_t*
+rend_get_service_list(const smartlist_t* substitute_service_list)
+{
+ /* It is safe to cast away the const here, because
+ * rend_get_service_list_mutable does not actually modify the list */
+ return rend_get_service_list_mutable((smartlist_t*)substitute_service_list);
+}
+
+/* Return a mutable list of hidden services.
+ * If substitute_service_list is not NULL, return it.
+ * Otherwise, check if the global rend_service_list is non-NULL, and if so,
+ * return it.
+ * Otherwise, log a BUG message and return NULL.
+ * */
+static smartlist_t*
+rend_get_service_list_mutable(smartlist_t* substitute_service_list)
+{
+ if (substitute_service_list) {
+ return substitute_service_list;
+ }
+
+ /* If no special service list is provided, then just use the global one. */
+
+ if (BUG(!rend_service_list)) {
+ /* No global HS list, which is a programmer error. */
+ return NULL;
+ }
+
+ return rend_service_list;
+}
+
/** Tells if onion service <b>s</b> is ephemeral.
-*/
+ */
static unsigned int
rend_service_is_ephemeral(const struct rend_service_t *s)
{
@@ -137,10 +180,6 @@ rend_service_escaped_dir(const struct rend_service_t *s)
return rend_service_is_ephemeral(s) ? "[EPHEMERAL]" : escaped(s->directory);
}
-/** A list of rend_service_t's for services run on this OP.
- */
-static smartlist_t *rend_service_list = NULL;
-
/** Return the number of rendezvous services we have configured. */
int
num_rend_services(void)
@@ -225,21 +264,32 @@ rend_service_free_all(void)
rend_service_list = NULL;
}
-/** Validate <b>service</b> and add it to rend_service_list if possible.
+/** Validate <b>service</b> and add it to <b>service_list</b>, or to
+ * the global rend_service_list if <b>service_list</b> is NULL.
* Return 0 on success. On failure, free <b>service</b> and return -1.
+ * Takes ownership of <b>service</b>.
*/
static int
-rend_add_service(rend_service_t *service)
+rend_add_service(smartlist_t *service_list, rend_service_t *service)
{
int i;
rend_service_port_config_t *p;
+ tor_assert(service);
+
+ smartlist_t *s_list = rend_get_service_list_mutable(service_list);
+ /* We must have a service list, even if it's a temporary one, so we can
+ * check for duplicate services */
+ if (BUG(!s_list)) {
+ return -1;
+ }
+
service->intro_nodes = smartlist_new();
service->expiring_nodes = smartlist_new();
if (service->max_streams_per_circuit < 0) {
log_warn(LD_CONFIG, "Hidden service (%s) configured with negative max "
- "streams per circuit; ignoring.",
+ "streams per circuit.",
rend_service_escaped_dir(service));
rend_service_free(service);
return -1;
@@ -248,24 +298,24 @@ rend_add_service(rend_service_t *service)
if (service->max_streams_close_circuit < 0 ||
service->max_streams_close_circuit > 1) {
log_warn(LD_CONFIG, "Hidden service (%s) configured with invalid "
- "max streams handling; ignoring.",
+ "max streams handling.",
rend_service_escaped_dir(service));
rend_service_free(service);
return -1;
}
if (service->auth_type != REND_NO_AUTH &&
- smartlist_len(service->clients) == 0) {
+ (!service->clients ||
+ smartlist_len(service->clients) == 0)) {
log_warn(LD_CONFIG, "Hidden service (%s) with client authorization but no "
- "clients; ignoring.",
+ "clients.",
rend_service_escaped_dir(service));
rend_service_free(service);
return -1;
}
- if (!smartlist_len(service->ports)) {
- log_warn(LD_CONFIG, "Hidden service (%s) with no ports configured; "
- "ignoring.",
+ if (!service->ports || !smartlist_len(service->ports)) {
+ log_warn(LD_CONFIG, "Hidden service (%s) with no ports configured.",
rend_service_escaped_dir(service));
rend_service_free(service);
return -1;
@@ -286,20 +336,20 @@ rend_add_service(rend_service_t *service)
* lock file. But this is enough to detect a simple mistake that
* at least one person has actually made.
*/
+ tor_assert(s_list);
if (!rend_service_is_ephemeral(service)) {
/* Skip dupe for ephemeral services. */
- SMARTLIST_FOREACH(rend_service_list, rend_service_t*, ptr,
+ SMARTLIST_FOREACH(s_list, rend_service_t*, ptr,
dupe = dupe ||
!strcmp(ptr->directory, service->directory));
if (dupe) {
log_warn(LD_REND, "Another hidden service is already configured for "
- "directory %s, ignoring.",
+ "directory %s.",
rend_service_escaped_dir(service));
rend_service_free(service);
return -1;
}
}
- smartlist_add(rend_service_list, service);
log_debug(LD_REND,"Configuring service with directory %s",
rend_service_escaped_dir(service));
for (i = 0; i < smartlist_len(service->ports); ++i) {
@@ -315,14 +365,19 @@ rend_add_service(rend_service_t *service)
"Service maps port %d to socket at \"%s\"",
p->virtual_port, p->unix_addr);
#else
- log_debug(LD_REND,
- "Service maps port %d to an AF_UNIX socket, but we "
- "have no AF_UNIX support on this platform. This is "
- "probably a bug.",
- p->virtual_port);
+ log_warn(LD_BUG,
+ "Service maps port %d to an AF_UNIX socket, but we "
+ "have no AF_UNIX support on this platform. This is "
+ "probably a bug.",
+ p->virtual_port);
+ rend_service_free(service);
+ return -1;
#endif /* defined(HAVE_SYS_UN_H) */
}
}
+ /* The service passed all the checks */
+ tor_assert(s_list);
+ smartlist_add(s_list, service);
return 0;
}
/* NOTREACHED */
@@ -344,9 +399,9 @@ rend_service_port_config_new(const char *socket_path)
return conf;
}
-/** Parses a real-port to virtual-port mapping separated by the provided
- * separator and returns a new rend_service_port_config_t, or NULL and an
- * optional error string on failure.
+/** Parses a virtual-port to real-port/socket mapping separated by
+ * the provided separator and returns a new rend_service_port_config_t,
+ * or NULL and an optional error string on failure.
*
* The format is: VirtualPort SEP (IP|RealPort|IP:RealPort|'socket':path)?
*
@@ -371,14 +426,12 @@ rend_service_parse_port_config(const char *string, const char *sep,
smartlist_split_string(sl, string, sep,
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 2);
if (smartlist_len(sl) < 1 || BUG(smartlist_len(sl) > 2)) {
- if (err_msg_out)
- err_msg = tor_strdup("Bad syntax in hidden service port configuration.");
+ err_msg = tor_strdup("Bad syntax in hidden service port configuration.");
goto err;
}
virtport = (int)tor_parse_long(smartlist_get(sl,0), 10, 1, 65535, NULL,NULL);
if (!virtport) {
- if (err_msg_out)
- tor_asprintf(&err_msg, "Missing or invalid port %s in hidden service "
+ tor_asprintf(&err_msg, "Missing or invalid port %s in hidden service "
"port configuration", escaped(smartlist_get(sl,0)));
goto err;
@@ -406,10 +459,8 @@ rend_service_parse_port_config(const char *string, const char *sep,
} else if (strchr(addrport, ':') || strchr(addrport, '.')) {
/* else try it as an IP:port pair if it has a : or . in it */
if (tor_addr_port_lookup(addrport, &addr, &p)<0) {
- if (err_msg_out)
- err_msg = tor_strdup("Unparseable address in hidden service port "
- "configuration.");
-
+ err_msg = tor_strdup("Unparseable address in hidden service port "
+ "configuration.");
goto err;
}
realport = p?p:virtport;
@@ -417,11 +468,9 @@ rend_service_parse_port_config(const char *string, const char *sep,
/* No addr:port, no addr -- must be port. */
realport = (int)tor_parse_long(addrport, 10, 1, 65535, NULL, NULL);
if (!realport) {
- if (err_msg_out)
- tor_asprintf(&err_msg, "Unparseable or out-of-range port %s in "
- "hidden service port configuration.",
- escaped(addrport));
-
+ tor_asprintf(&err_msg, "Unparseable or out-of-range port %s in "
+ "hidden service port configuration.",
+ escaped(addrport));
goto err;
}
tor_addr_from_ipv4h(&addr, 0x7F000001u); /* Default to 127.0.0.1 */
@@ -440,7 +489,11 @@ rend_service_parse_port_config(const char *string, const char *sep,
err:
tor_free(addrport);
- if (err_msg_out) *err_msg_out = err_msg;
+ if (err_msg_out != NULL) {
+ *err_msg_out = err_msg;
+ } else {
+ tor_free(err_msg);
+ }
SMARTLIST_FOREACH(sl, char *, c, tor_free(c));
smartlist_free(sl);
@@ -454,6 +507,41 @@ rend_service_port_config_free(rend_service_port_config_t *p)
tor_free(p);
}
+/* Check the directory for <b>service</b>, and add the service to
+ * <b>service_list</b>, or to the global list if <b>service_list</b> is NULL.
+ * Only add the service to the list if <b>validate_only</b> is false.
+ * If <b>validate_only</b> is true, free the service.
+ * If <b>service</b> is NULL, ignore it, and return 0.
+ * Returns 0 on success, and -1 on failure.
+ * Takes ownership of <b>service</b>, either freeing it, or adding it to the
+ * global service list.
+ */
+STATIC int
+rend_service_check_dir_and_add(smartlist_t *service_list,
+ const or_options_t *options,
+ rend_service_t *service,
+ int validate_only)
+{
+ if (!service) {
+ /* It is ok for a service to be NULL, this means there are no services */
+ return 0;
+ }
+
+ if (rend_service_check_private_dir(options, service, !validate_only)
+ < 0) {
+ rend_service_free(service);
+ return -1;
+ }
+
+ smartlist_t *s_list = rend_get_service_list_mutable(service_list);
+ /* We must have a service list, even if it's a temporary one, so we can
+ * check for duplicate services */
+ if (BUG(!s_list)) {
+ return -1;
+ }
+ return rend_add_service(s_list, service);
+}
+
/** Set up rend_service_list, based on the values of HiddenServiceDir and
* HiddenServicePort in <b>options</b>. Return 0 on success and -1 on
* failure. (If <b>validate_only</b> is set, parse, warn and return as
@@ -466,25 +554,21 @@ rend_config_services(const or_options_t *options, int validate_only)
rend_service_t *service = NULL;
rend_service_port_config_t *portcfg;
smartlist_t *old_service_list = NULL;
+ smartlist_t *temp_service_list = NULL;
int ok = 0;
- if (!validate_only) {
- old_service_list = rend_service_list;
- rend_service_list = smartlist_new();
- }
+ /* Use a temporary service list, so that we can check the new services'
+ * consistency with each other */
+ temp_service_list = smartlist_new();
for (line = options->RendConfigLines; line; line = line->next) {
if (!strcasecmp(line->key, "HiddenServiceDir")) {
- if (service) { /* register the one we just finished parsing */
- if (rend_service_check_private_dir(options, service, 0) < 0) {
- rend_service_free(service);
+ /* register the service we just finished parsing
+ * this code registers every service except the last one parsed,
+ * which is registered below the loop */
+ if (rend_service_check_dir_and_add(temp_service_list, options, service,
+ validate_only) < 0) {
return -1;
- }
-
- if (validate_only)
- rend_service_free(service);
- else
- rend_add_service(service);
}
service = tor_malloc_zero(sizeof(rend_service_t));
service->directory = tor_strdup(line->value);
@@ -695,19 +779,30 @@ rend_config_services(const or_options_t *options, int validate_only)
}
}
}
- if (service) {
- if (rend_service_check_private_dir(options, service, 0) < 0) {
- rend_service_free(service);
- return -1;
- }
+ /* register the final service after we have finished parsing all services
+ * this code only registers the last service, other services are registered
+ * within the loop. It is ok for this service to be NULL, it is ignored. */
+ if (rend_service_check_dir_and_add(temp_service_list, options, service,
+ validate_only) < 0) {
+ return -1;
+ }
- if (validate_only) {
- rend_service_free(service);
- } else {
- rend_add_service(service);
- }
+ /* Free the newly added services if validating */
+ if (validate_only) {
+ SMARTLIST_FOREACH(temp_service_list, rend_service_t *, ptr,
+ rend_service_free(ptr));
+ smartlist_free(temp_service_list);
+ temp_service_list = NULL;
+ return 0;
}
+ /* Otherwise, use the newly added services as the new service list
+ * Since we have now replaced the global service list, from this point on we
+ * must succeed, or die trying. */
+ old_service_list = rend_service_list;
+ rend_service_list = temp_service_list;
+ temp_service_list = NULL;
+
/* If this is a reload and there were hidden services configured before,
* keep the introduction points that are still needed and close the
* other ones. */
@@ -729,7 +824,7 @@ rend_config_services(const or_options_t *options, int validate_only)
* will NOT have their intro point closed.
*/
SMARTLIST_FOREACH(old_service_list, rend_service_t *, old, {
- if (!old->directory) {
+ if (rend_service_is_ephemeral(old)) {
SMARTLIST_DEL_CURRENT(old_service_list, old);
smartlist_add(surviving_services, old);
smartlist_add(rend_service_list, old);
@@ -741,15 +836,20 @@ rend_config_services(const or_options_t *options, int validate_only)
* probably ok? */
SMARTLIST_FOREACH_BEGIN(rend_service_list, rend_service_t *, new) {
SMARTLIST_FOREACH_BEGIN(old_service_list, rend_service_t *, old) {
- if (new->directory && old->directory &&
- !strcmp(old->directory, new->directory)) {
- smartlist_add_all(new->intro_nodes, old->intro_nodes);
- smartlist_clear(old->intro_nodes);
- smartlist_add_all(new->expiring_nodes, old->expiring_nodes);
- smartlist_clear(old->expiring_nodes);
- smartlist_add(surviving_services, old);
- break;
+ if (BUG(rend_service_is_ephemeral(new)) ||
+ BUG(rend_service_is_ephemeral(old))) {
+ continue;
+ }
+ if (BUG(!new->directory) || BUG(!old->directory) ||
+ strcmp(old->directory, new->directory)) {
+ continue;
}
+ smartlist_add_all(new->intro_nodes, old->intro_nodes);
+ smartlist_clear(old->intro_nodes);
+ smartlist_add_all(new->expiring_nodes, old->expiring_nodes);
+ smartlist_clear(old->expiring_nodes);
+ smartlist_add(surviving_services, old);
+ break;
} SMARTLIST_FOREACH_END(old);
} SMARTLIST_FOREACH_END(new);
@@ -861,7 +961,7 @@ rend_service_add_ephemeral(crypto_pk_t *pk,
}
/* Initialize the service. */
- if (rend_add_service(s)) {
+ if (rend_add_service(NULL, s)) {
return RSAE_INTERNAL;
}
*service_id_out = tor_strdup(s->service_id);
@@ -1011,6 +1111,11 @@ service_is_single_onion_poisoned(const rend_service_t *service)
char *poison_fname = NULL;
file_status_t fstatus;
+ /* Passing a NULL service is a bug */
+ if (BUG(!service)) {
+ return 0;
+ }
+
if (rend_service_is_ephemeral(service)) {
return 0;
}
@@ -1044,58 +1149,69 @@ rend_service_private_key_exists(const rend_service_t *service)
return private_key_status == FN_FILE;
}
-/** Check the single onion service poison state of all existing hidden service
- * directories:
- * - If each service is poisoned, and we are in Single Onion Mode,
+/** Check the single onion service poison state of the directory for s:
+ * - If the service is poisoned, and we are in Single Onion Mode,
* return 0,
- * - If each service is not poisoned, and we are not in Single Onion Mode,
+ * - If the service is not poisoned, and we are not in Single Onion Mode,
* return 0,
- * - Otherwise, the poison state is invalid, and a service that was created in
- * one mode is being used in the other, return -1.
- * Hidden service directories without keys are not checked for consistency.
- * When their keys are created, they will be poisoned (if needed).
- * If a <b>service_list</b> is provided, treat it
- * as the list of hidden services (used in unittests). */
-int
-rend_service_list_verify_single_onion_poison(const smartlist_t *service_list,
- const or_options_t *options)
+ * - Otherwise, the poison state is invalid: the service was created in one
+ * mode, and is being used in the other, return -1.
+ * Hidden service directories without keys are always considered consistent.
+ * They will be poisoned after their directory is created (if needed). */
+STATIC int
+rend_service_verify_single_onion_poison(const rend_service_t* s,
+ const or_options_t* options)
{
- const smartlist_t *s_list;
- /* If no special service list is provided, then just use the global one. */
- if (!service_list) {
- if (!rend_service_list) { /* No global HS list. Nothing to see here. */
- return 0;
- }
+ /* Passing a NULL service is a bug */
+ if (BUG(!s)) {
+ return -1;
+ }
- s_list = rend_service_list;
- } else {
- s_list = service_list;
+ /* Ephemeral services are checked at ADD_ONION time */
+ if (BUG(rend_service_is_ephemeral(s))) {
+ return -1;
}
- int consistent = 1;
- SMARTLIST_FOREACH_BEGIN(s_list, const rend_service_t *, s) {
- if (service_is_single_onion_poisoned(s) !=
- rend_service_non_anonymous_mode_enabled(options) &&
- rend_service_private_key_exists(s)) {
- consistent = 0;
- }
- } SMARTLIST_FOREACH_END(s);
+ /* Service is expected to have a directory */
+ if (BUG(!s->directory)) {
+ return -1;
+ }
- return consistent ? 0 : -1;
+ /* Services without keys are always ok - their keys will only ever be used
+ * in the current mode */
+ if (!rend_service_private_key_exists(s)) {
+ return 0;
+ }
+
+ /* The key has been used before in a different mode */
+ if (service_is_single_onion_poisoned(s) !=
+ rend_service_non_anonymous_mode_enabled(options)) {
+ return -1;
+ }
+
+ /* The key exists and is consistent with the current mode */
+ return 0;
}
-/*** Helper for rend_service_poison_new_single_onion_dirs(). Add a file to
- * this hidden service directory that marks it as a single onion service.
- * Tor must be in single onion mode before calling this function.
+/*** Helper for rend_service_poison_new_single_onion_dir(). Add a file to
+ * the hidden service directory for s that marks it as a single onion service.
+ * Tor must be in single onion mode before calling this function, and the
+ * service directory must already have been created.
* Returns 0 when a directory is successfully poisoned, or if it is already
* poisoned. Returns -1 on a failure to read the directory or write the poison
* file, or if there is an existing private key file in the directory. (The
* service should have been poisoned when the key was created.) */
static int
-poison_new_single_onion_hidden_service_dir(const rend_service_t *service)
+poison_new_single_onion_hidden_service_dir_impl(const rend_service_t *service,
+ const or_options_t* options)
{
+ /* Passing a NULL service is a bug */
+ if (BUG(!service)) {
+ return -1;
+ }
+
/* We must only poison directories if we're in Single Onion mode */
- tor_assert(rend_service_non_anonymous_mode_enabled(get_options()));
+ tor_assert(rend_service_non_anonymous_mode_enabled(options));
int fd;
int retval = -1;
@@ -1113,8 +1229,8 @@ poison_new_single_onion_hidden_service_dir(const rend_service_t *service)
return -1;
}
- /* Make sure the directory exists */
- if (rend_service_check_private_dir(get_options(), service, 1) < 0)
+ /* Make sure the directory was created before calling this function. */
+ if (BUG(rend_service_check_private_dir_impl(options, service, 0) < 0))
return -1;
poison_fname = rend_service_sos_poison_path(service);
@@ -1151,44 +1267,39 @@ poison_new_single_onion_hidden_service_dir(const rend_service_t *service)
return retval;
}
-/** We just got launched in Single Onion Mode. That's a non-anoymous
- * mode for hidden services; hence we should mark all new hidden service
- * directories appropriately so that they are never launched as
- * location-private hidden services again. (New directories don't have private
- * key files.)
- * If a <b>service_list</b> is provided, treat it as the list of hidden
- * services (used in unittests).
+/** We just got launched in Single Onion Mode. That's a non-anonymous mode for
+ * hidden services. If s is new, we should mark its hidden service
+ * directory appropriately so that it is never launched as a location-private
+ * hidden service. (New directories don't have private key files.)
* Return 0 on success, -1 on fail. */
-int
-rend_service_poison_new_single_onion_dirs(const smartlist_t *service_list)
+STATIC int
+rend_service_poison_new_single_onion_dir(const rend_service_t *s,
+ const or_options_t* options)
{
+ /* Passing a NULL service is a bug */
+ if (BUG(!s)) {
+ return -1;
+ }
+
/* We must only poison directories if we're in Single Onion mode */
- tor_assert(rend_service_non_anonymous_mode_enabled(get_options()));
+ tor_assert(rend_service_non_anonymous_mode_enabled(options));
- const smartlist_t *s_list;
- /* If no special service list is provided, then just use the global one. */
- if (!service_list) {
- if (!rend_service_list) { /* No global HS list. Nothing to see here. */
- return 0;
- }
+ /* Ephemeral services aren't allowed in non-anonymous mode */
+ if (BUG(rend_service_is_ephemeral(s))) {
+ return -1;
+ }
- s_list = rend_service_list;
- } else {
- s_list = service_list;
+ /* Service is expected to have a directory */
+ if (BUG(!s->directory)) {
+ return -1;
}
- SMARTLIST_FOREACH_BEGIN(s_list, const rend_service_t *, s) {
- if (!rend_service_private_key_exists(s)) {
- if (poison_new_single_onion_hidden_service_dir(s) < 0) {
- return -1;
- }
+ if (!rend_service_private_key_exists(s)) {
+ if (poison_new_single_onion_hidden_service_dir_impl(s, options)
+ < 0) {
+ return -1;
}
- } SMARTLIST_FOREACH_END(s);
-
- /* The keys for these services are linked to the server IP address */
- log_notice(LD_REND, "The configured onion service directories have been "
- "used in single onion mode. They can not be used for anonymous "
- "hidden services.");
+ }
return 0;
}
@@ -1202,13 +1313,10 @@ rend_service_poison_new_single_onion_dirs(const smartlist_t *service_list)
int
rend_service_load_all_keys(const smartlist_t *service_list)
{
- const smartlist_t *s_list;
- /* If no special service list is provided, then just use the global one. */
- if (!service_list) {
- tor_assert(rend_service_list);
- s_list = rend_service_list;
- } else {
- s_list = service_list;
+ /* Use service_list for unit tests */
+ const smartlist_t *s_list = rend_get_service_list(service_list);
+ if (BUG(!s_list)) {
+ return -1;
}
SMARTLIST_FOREACH_BEGIN(s_list, rend_service_t *, s) {
@@ -1272,6 +1380,32 @@ rend_service_derive_key_digests(struct rend_service_t *s)
return 0;
}
+/* Implements the directory check from rend_service_check_private_dir,
+ * without doing the single onion poison checks. */
+static int
+rend_service_check_private_dir_impl(const or_options_t *options,
+ const rend_service_t *s,
+ int create)
+{
+ cpd_check_t check_opts = CPD_NONE;
+ if (create) {
+ check_opts |= CPD_CREATE;
+ } else {
+ check_opts |= CPD_CHECK_MODE_ONLY;
+ check_opts |= CPD_CHECK;
+ }
+ if (s->dir_group_readable) {
+ check_opts |= CPD_GROUP_READ;
+ }
+ /* Check/create directory */
+ if (check_private_dir(s->directory, check_opts, options->User) < 0) {
+ log_warn(LD_REND, "Checking service directory %s failed.", s->directory);
+ return -1;
+ }
+
+ return 0;
+}
+
/** Make sure that the directory for <b>s</b> is private, using the config in
* <b>options</b>.
* If <b>create</b> is true:
@@ -1286,20 +1420,58 @@ rend_service_check_private_dir(const or_options_t *options,
const rend_service_t *s,
int create)
{
- cpd_check_t check_opts = CPD_NONE;
- if (create) {
- check_opts |= CPD_CREATE;
- } else {
- check_opts |= CPD_CHECK_MODE_ONLY;
- check_opts |= CPD_CHECK;
- }
- if (s->dir_group_readable) {
- check_opts |= CPD_GROUP_READ;
+ /* Passing a NULL service is a bug */
+ if (BUG(!s)) {
+ return -1;
}
+
/* Check/create directory */
- if (check_private_dir(s->directory, check_opts, options->User) < 0) {
+ if (rend_service_check_private_dir_impl(options, s, create) < 0) {
+ return -1;
+ }
+
+ /* Check if the hidden service key exists, and was created in a different
+ * single onion service mode, and refuse to launch if it has.
+ * This is safe to call even when create is false, as it ignores missing
+ * keys and directories: they are always valid.
+ */
+ if (rend_service_verify_single_onion_poison(s, options) < 0) {
+ /* We can't use s->service_id here, as the key may not have been loaded */
+ log_warn(LD_GENERAL, "We are configured with "
+ "HiddenServiceNonAnonymousMode %d, but the hidden "
+ "service key in directory %s was created in %s mode. "
+ "This is not allowed.",
+ rend_service_non_anonymous_mode_enabled(options) ? 1 : 0,
+ rend_service_escaped_dir(s),
+ rend_service_non_anonymous_mode_enabled(options) ?
+ "an anonymous" : "a non-anonymous"
+ );
return -1;
}
+
+ /* Poison new single onion directories immediately after they are created,
+ * so that we never accidentally launch non-anonymous hidden services
+ * thinking they are anonymous. Any keys created later will end up with the
+ * correct poisoning state.
+ */
+ if (create && rend_service_non_anonymous_mode_enabled(options)) {
+ static int logged_warning = 0;
+
+ if (rend_service_poison_new_single_onion_dir(s, options) < 0) {
+ log_warn(LD_GENERAL,"Failed to mark new hidden services as non-anonymous"
+ ".");
+ return -1;
+ }
+
+ if (!logged_warning) {
+ /* The keys for these services are linked to the server IP address */
+ log_notice(LD_REND, "The configured onion service directories have been "
+ "used in single onion mode. They can not be used for "
+ "anonymous hidden services.");
+ logged_warning = 1;
+ }
+ }
+
return 0;
}
@@ -1312,7 +1484,9 @@ rend_service_load_keys(rend_service_t *s)
char *fname = NULL;
char buf[128];
- if (rend_service_check_private_dir(get_options(), s, 1) < 0)
+ /* Make sure the directory was created and single onion poisoning was
+ * checked before calling this function */
+ if (BUG(rend_service_check_private_dir(get_options(), s, 0) < 0))
goto err;
/* Load key */
@@ -3086,7 +3260,7 @@ rend_service_intro_has_opened(origin_circuit_t *circuit)
len += 2;
memcpy(auth, circuit->cpath->prev->rend_circ_nonce, DIGEST_LEN);
memcpy(auth+DIGEST_LEN, "INTRODUCE", 9);
- if (crypto_digest(buf+len, auth, DIGEST_LEN+9))
+ if (crypto_digest(buf+len, auth, DIGEST_LEN+9) < 0)
goto err;
len += 20;
note_crypto_pk_op(REND_SERVER);
diff --git a/src/or/rendservice.h b/src/or/rendservice.h
index 630191e8b7..3b185672f6 100644
--- a/src/or/rendservice.h
+++ b/src/or/rendservice.h
@@ -119,7 +119,16 @@ typedef struct rend_service_t {
STATIC void rend_service_free(rend_service_t *service);
STATIC char *rend_service_sos_poison_path(const rend_service_t *service);
-
+STATIC int rend_service_check_dir_and_add(smartlist_t *service_list,
+ const or_options_t *options,
+ rend_service_t *service,
+ int validate_only);
+STATIC int rend_service_verify_single_onion_poison(
+ const rend_service_t *s,
+ const or_options_t *options);
+STATIC int rend_service_poison_new_single_onion_dir(
+ const rend_service_t *s,
+ const or_options_t* options);
#endif
int num_rend_services(void);
@@ -165,11 +174,6 @@ void rend_service_port_config_free(rend_service_port_config_t *p);
void rend_authorized_client_free(rend_authorized_client_t *client);
-int rend_service_list_verify_single_onion_poison(
- const smartlist_t *service_list,
- const or_options_t *options);
-int rend_service_poison_new_single_onion_dirs(const smartlist_t *service_list);
-
/** Return value from rend_service_add_ephemeral. */
typedef enum {
RSAE_BADAUTH = -5, /**< Invalid auth_type/auth_clients */
diff --git a/src/or/router.c b/src/or/router.c
index bc0eb3a34a..917caaa1f5 100644
--- a/src/or/router.c
+++ b/src/or/router.c
@@ -1968,23 +1968,34 @@ static int router_guess_address_from_dir_headers(uint32_t *guess);
/** Make a current best guess at our address, either because
* it's configured in torrc, or because we've learned it from
* dirserver headers. Place the answer in *<b>addr</b> and return
- * 0 on success, else return -1 if we have no guess. */
+ * 0 on success, else return -1 if we have no guess.
+ *
+ * If <b>cache_only</b> is true, just return any cached answers, and
+ * don't try to get any new answers.
+ */
MOCK_IMPL(int,
-router_pick_published_address,(const or_options_t *options, uint32_t *addr))
+router_pick_published_address,(const or_options_t *options, uint32_t *addr,
+ int cache_only))
{
+ /* First, check the cached output from resolve_my_address(). */
*addr = get_last_resolved_addr();
- if (!*addr &&
- resolve_my_address(LOG_INFO, options, addr, NULL, NULL) < 0) {
- log_info(LD_CONFIG, "Could not determine our address locally. "
- "Checking if directory headers provide any hints.");
- if (router_guess_address_from_dir_headers(addr) < 0) {
- log_info(LD_CONFIG, "No hints from directory headers either. "
- "Will try again later.");
- return -1;
+ if (*addr)
+ return 0;
+
+ /* Second, consider doing a resolve attempt right here. */
+ if (!cache_only) {
+ if (resolve_my_address(LOG_INFO, options, addr, NULL, NULL) >= 0) {
+ log_info(LD_CONFIG,"Success: chose address '%s'.", fmt_addr32(*addr));
+ return 0;
}
}
- log_info(LD_CONFIG,"Success: chose address '%s'.", fmt_addr32(*addr));
- return 0;
+
+ /* Third, check the cached output from router_new_address_suggestion(). */
+ if (router_guess_address_from_dir_headers(addr) >= 0)
+ return 0;
+
+ /* We have no useful cached answers. Return failure. */
+ return -1;
}
/* Like router_check_descriptor_address_consistency, but specifically for the
@@ -2081,7 +2092,7 @@ router_build_fresh_descriptor(routerinfo_t **r, extrainfo_t **e)
int hibernating = we_are_hibernating();
const or_options_t *options = get_options();
- if (router_pick_published_address(options, &addr) < 0) {
+ if (router_pick_published_address(options, &addr, 0) < 0) {
log_warn(LD_CONFIG, "Don't know my address while generating descriptor");
return -1;
}
@@ -2330,7 +2341,7 @@ router_rebuild_descriptor(int force)
if (desc_clean_since && !force)
return 0;
- if (router_pick_published_address(options, &addr) < 0 ||
+ if (router_pick_published_address(options, &addr, 0) < 0 ||
router_get_advertised_or_port(options) == 0) {
/* Stop trying to rebuild our descriptor every second. We'll
* learn that it's time to try again when ip_address_changed()
diff --git a/src/or/router.h b/src/or/router.h
index 73bfea1faa..c30a0301b7 100644
--- a/src/or/router.h
+++ b/src/or/router.h
@@ -91,7 +91,8 @@ const uint8_t *router_get_my_id_digest(void);
int router_extrainfo_digest_is_me(const char *digest);
int router_is_me(const routerinfo_t *router);
MOCK_DECL(int,router_pick_published_address,(const or_options_t *options,
- uint32_t *addr));
+ uint32_t *addr,
+ int cache_only));
int router_build_fresh_descriptor(routerinfo_t **r, extrainfo_t **e);
int router_rebuild_descriptor(int force);
char *router_dump_router_to_string(routerinfo_t *router,
diff --git a/src/or/routerkeys.c b/src/or/routerkeys.c
index ab78dbe61e..51802b15e5 100644
--- a/src/or/routerkeys.c
+++ b/src/or/routerkeys.c
@@ -742,8 +742,12 @@ load_ed_keys(const or_options_t *options, time_t now)
if (need_new_signing_key) {
log_notice(LD_OR, "It looks like I need to generate and sign a new "
- "medium-term signing key, because %s. To do that, I need to "
- "load%s the permanent master identity key.",
+ "medium-term signing key, because %s. To do that, I "
+ "need to load%s the permanent master identity key. "
+ "If the master identity key was not moved or encrypted "
+ "with a passphrase, this will be done automatically and "
+ "no further action is required. Otherwise, provide the "
+ "necessary data using 'tor --keygen' to do it manually.",
(NULL == use_signing) ? "I don't have one" :
EXPIRES_SOON(check_signing_cert, 0) ? "the one I have is expired" :
"you asked me to make one with --keygen",
@@ -751,15 +755,19 @@ load_ed_keys(const or_options_t *options, time_t now)
} else if (want_new_signing_key && !offline_master) {
log_notice(LD_OR, "It looks like I should try to generate and sign a "
"new medium-term signing key, because the one I have is "
- "going to expire soon. To do that, I'm going to have to try to "
- "load the permanent master identity key.");
+ "going to expire soon. To do that, I'm going to have to "
+ "try to load the permanent master identity key. "
+ "If the master identity key was not moved or encrypted "
+ "with a passphrase, this will be done automatically and "
+ "no further action is required. Otherwise, provide the "
+ "necessary data using 'tor --keygen' to do it manually.");
} else if (want_new_signing_key) {
log_notice(LD_OR, "It looks like I should try to generate and sign a "
"new medium-term signing key, because the one I have is "
"going to expire soon. But OfflineMasterKey is set, so I "
- "won't try to load a permanent master identity key is set. "
- "You will need to use 'tor --keygen' make a new signing key "
- "and certificate.");
+ "won't try to load a permanent master identity key. You "
+ "will need to use 'tor --keygen' to make a new signing "
+ "key and certificate.");
}
{
diff --git a/src/or/routerlist.c b/src/or/routerlist.c
index c99d22ed41..9bcca76b63 100644
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@ -586,7 +586,7 @@ trusted_dirs_load_certs_from_string(const char *contents, int source,
"signing key %s", from_store ? "cached" : "downloaded",
ds->nickname, hex_str(cert->signing_key_digest,DIGEST_LEN));
} else {
- int adding = directory_caches_unknown_auth_certs(get_options());
+ int adding = we_want_to_fetch_unknown_auth_certs(get_options());
log_info(LD_DIR, "%s %s certificate for unrecognized directory "
"authority with signing key %s",
adding ? "Adding" : "Not adding",
@@ -1012,7 +1012,7 @@ authority_certs_fetch_missing(networkstatus_t *status, time_t now,
char *resource = NULL;
cert_list_t *cl;
const or_options_t *options = get_options();
- const int cache = directory_caches_unknown_auth_certs(options);
+ const int keep_unknown = we_want_to_fetch_unknown_auth_certs(options);
fp_pair_t *fp_tmp = NULL;
char id_digest_str[2*DIGEST_LEN+1];
char sk_digest_str[2*DIGEST_LEN+1];
@@ -1084,9 +1084,10 @@ authority_certs_fetch_missing(networkstatus_t *status, time_t now,
if (!smartlist_len(voter->sigs))
continue; /* This authority never signed this consensus, so don't
* go looking for a cert with key digest 0000000000. */
- if (!cache &&
+ if (!keep_unknown &&
!trusteddirserver_get_by_v3_auth_digest(voter->identity_digest))
- continue; /* We are not a cache, and we don't know this authority.*/
+ continue; /* We don't want unknown certs, and we don't know this
+ * authority.*/
/*
* If we don't know *any* cert for this authority, and a download by ID
@@ -3895,7 +3896,7 @@ router_add_to_routerlist(routerinfo_t *router, const char **msg,
router_describe(router));
*msg = "Router descriptor is not referenced by any network-status.";
- /* Only journal this desc if we'll be serving it. */
+ /* Only journal this desc if we want to keep old descriptors */
if (!from_cache && should_cache_old_descriptors())
signed_desc_append_to_journal(&router->cache_info,
&routerlist->desc_store);
@@ -4525,13 +4526,14 @@ router_load_extrainfo_from_string(const char *s, const char *eos,
smartlist_free(extrainfo_list);
}
-/** Return true iff any networkstatus includes a descriptor whose digest
- * is that of <b>desc</b>. */
+/** Return true iff the latest ns-flavored consensus includes a descriptor
+ * whose digest is that of <b>desc</b>. */
static int
signed_desc_digest_is_recognized(signed_descriptor_t *desc)
{
const routerstatus_t *rs;
- networkstatus_t *consensus = networkstatus_get_latest_consensus();
+ networkstatus_t *consensus = networkstatus_get_latest_consensus_by_flavor(
+ FLAV_NS);
if (consensus) {
rs = networkstatus_vote_find_entry(consensus, desc->identity_digest);
@@ -5154,7 +5156,7 @@ update_consensus_router_descriptor_downloads(time_t now, int is_vote,
++n_would_reject;
continue; /* We would throw it out immediately. */
}
- if (!directory_caches_dir_info(options) &&
+ if (!we_want_to_fetch_flavor(options, consensus->flavor) &&
!client_would_use_router(rs, now, options)) {
++n_wouldnt_use;
continue; /* We would never use it ourself. */
diff --git a/src/or/routerparse.c b/src/or/routerparse.c
index 2cfd3fc58a..38ceb942a9 100644
--- a/src/or/routerparse.c
+++ b/src/or/routerparse.c
@@ -715,7 +715,7 @@ dump_desc_populate_one_file, (const char *dirname, const char *f))
* filename.
*/
if (crypto_digest256((char *)content_digest, desc, (size_t) st.st_size,
- DIGEST_SHA256) != 0) {
+ DIGEST_SHA256) < 0) {
/* Weird, but okay */
log_info(LD_DIR,
"Unable to hash content of %s from unparseable descriptors "
@@ -879,7 +879,7 @@ dump_desc(const char *desc, const char *type)
/* Get the hash for logging purposes anyway */
len = strlen(desc);
if (crypto_digest256((char *)digest_sha256, desc, len,
- DIGEST_SHA256) != 0) {
+ DIGEST_SHA256) < 0) {
log_info(LD_DIR,
"Unable to parse descriptor of type %s, and unable to even hash"
" it!", type);
@@ -4536,12 +4536,12 @@ router_get_hash_impl(const char *s, size_t s_len, char *digest,
return -1;
if (alg == DIGEST_SHA1) {
- if (crypto_digest(digest, start, end-start)) {
+ if (crypto_digest(digest, start, end-start) < 0) {
log_warn(LD_BUG,"couldn't compute digest");
return -1;
}
} else {
- if (crypto_digest256(digest, start, end-start, alg)) {
+ if (crypto_digest256(digest, start, end-start, alg) < 0) {
log_warn(LD_BUG,"couldn't compute digest");
return -1;
}
diff --git a/src/or/shared_random.c b/src/or/shared_random.c
index 5f6b03f1ba..0eb93382ca 100644
--- a/src/or/shared_random.c
+++ b/src/or/shared_random.c
@@ -192,7 +192,7 @@ verify_commit_and_reveal(const sr_commit_t *commit)
/* Use the invariant length since the encoded reveal variable has an
* extra byte for the NUL terminated byte. */
if (crypto_digest256(received_hashed_reveal, commit->encoded_reveal,
- SR_REVEAL_BASE64_LEN, commit->alg)) {
+ SR_REVEAL_BASE64_LEN, commit->alg) < 0) {
/* Unable to digest the reveal blob, this is unlikely. */
goto invalid;
}
@@ -932,7 +932,7 @@ sr_generate_our_commit(time_t timestamp, const authority_cert_t *my_rsa_cert)
/* The invariant length is used here since the encoded reveal variable
* has an extra byte added for the NULL terminated byte. */
if (crypto_digest256(commit->hashed_reveal, commit->encoded_reveal,
- SR_REVEAL_BASE64_LEN, commit->alg)) {
+ SR_REVEAL_BASE64_LEN, commit->alg) < 0) {
goto error;
}
@@ -1012,7 +1012,7 @@ sr_compute_srv(void)
SMARTLIST_FOREACH(chunks, char *, s, tor_free(s));
smartlist_free(chunks);
if (crypto_digest256(hashed_reveals, reveals, strlen(reveals),
- SR_DIGEST_ALG)) {
+ SR_DIGEST_ALG) < 0) {
goto end;
}
current_srv = generate_srv(hashed_reveals, reveal_num,
diff --git a/src/or/torcert.c b/src/or/torcert.c
index 852def9ef6..c58f3da2d3 100644
--- a/src/or/torcert.c
+++ b/src/or/torcert.c
@@ -156,11 +156,12 @@ tor_cert_parse(const uint8_t *encoded, const size_t len)
cert->encoded_len = len;
memcpy(cert->signed_key.pubkey, parsed->certified_key, 32);
- const int64_t valid_until_64 = ((int64_t)parsed->exp_field) * 3600;
+ int64_t valid_until_64 = ((int64_t)parsed->exp_field) * 3600;
+#if SIZEOF_TIME_T < SIZEOF_INT64_T
if (valid_until_64 > TIME_MAX)
- cert->valid_until = TIME_MAX - 1;
- else
- cert->valid_until = (time_t) valid_until_64;
+ valid_until_64 = TIME_MAX - 1;
+#endif
+ cert->valid_until = (time_t) valid_until_64;
cert->cert_type = parsed->cert_type;
for (unsigned i = 0; i < ed25519_cert_getlen_ext(parsed); ++i) {
@@ -647,3 +648,44 @@ or_handshake_certs_check_both(int severity,
}
}
+/* === ENCODING === */
+
+/* Encode the ed25519 certificate <b>cert</b> and put the newly allocated
+ * string in <b>cert_str_out</b>. Return 0 on success else a negative value. */
+int
+tor_cert_encode_ed22519(const tor_cert_t *cert, char **cert_str_out)
+{
+ int ret = -1;
+ char *ed_cert_b64 = NULL;
+ size_t ed_cert_b64_len;
+
+ tor_assert(cert);
+ tor_assert(cert_str_out);
+
+ /* Get the encoded size and add the NUL byte. */
+ ed_cert_b64_len = base64_encode_size(cert->encoded_len,
+ BASE64_ENCODE_MULTILINE) + 1;
+ ed_cert_b64 = tor_malloc_zero(ed_cert_b64_len);
+
+ /* Base64 encode the encoded certificate. */
+ if (base64_encode(ed_cert_b64, ed_cert_b64_len,
+ (const char *) cert->encoded, cert->encoded_len,
+ BASE64_ENCODE_MULTILINE) < 0) {
+ log_err(LD_BUG, "Couldn't base64-encode ed22519 cert!");
+ goto err;
+ }
+
+ /* Put everything together in a NUL terminated string. */
+ tor_asprintf(cert_str_out,
+ "-----BEGIN ED25519 CERT-----\n"
+ "%s"
+ "-----END ED25519 CERT-----",
+ ed_cert_b64);
+ /* Success! */
+ ret = 0;
+
+ err:
+ tor_free(ed_cert_b64);
+ return ret;
+}
+
diff --git a/src/or/torcert.h b/src/or/torcert.h
index 4bd816f4a4..090f6b5811 100644
--- a/src/or/torcert.h
+++ b/src/or/torcert.h
@@ -98,5 +98,7 @@ void or_handshake_certs_check_both(int severity,
const ed25519_public_key_t **ed_id_out,
const common_digests_t **rsa_id_out);
+int tor_cert_encode_ed22519(const tor_cert_t *cert, char **cert_str_out);
+
#endif
diff --git a/src/or/transports.c b/src/or/transports.c
index 614b28c168..f755882c16 100644
--- a/src/or/transports.c
+++ b/src/or/transports.c
@@ -1611,7 +1611,7 @@ pt_get_extra_info_descriptor_string(void)
uint32_t external_ip_address = 0;
if (tor_addr_is_null(&t->addr) &&
router_pick_published_address(get_options(),
- &external_ip_address) >= 0) {
+ &external_ip_address, 0) >= 0) {
tor_addr_t addr;
tor_addr_from_ipv4h(&addr, external_ip_address);
addrport = fmt_addrport(&addr, t->port);
diff --git a/src/test/include.am b/src/test/include.am
index f6e43148f0..8d0fc2ff6b 100644
--- a/src/test/include.am
+++ b/src/test/include.am
@@ -80,6 +80,7 @@ src_test_test_SOURCES = \
src/test/test_checkdir.c \
src/test/test_circuitlist.c \
src/test/test_circuitmux.c \
+ src/test/test_circuituse.c \
src/test/test_compat_libevent.c \
src/test/test_config.c \
src/test/test_connection.c \
diff --git a/src/test/log_test_helpers.h b/src/test/log_test_helpers.h
index 4c020c7ec3..922c68b42f 100644
--- a/src/test/log_test_helpers.h
+++ b/src/test/log_test_helpers.h
@@ -49,7 +49,22 @@ void mock_dump_saved_logs(void);
#define expect_log_msg_containing_either(str1, str2) \
assert_log_predicate(mock_saved_log_has_message_containing(str1) || \
mock_saved_log_has_message_containing(str2), \
- "expected log to contain " # str1 " or " # str2);
+ "expected log to contain " # str1 " or " # str2);
+
+#define expect_log_msg_containing_either3(str1, str2, str3) \
+ assert_log_predicate(mock_saved_log_has_message_containing(str1) || \
+ mock_saved_log_has_message_containing(str2) || \
+ mock_saved_log_has_message_containing(str3), \
+ "expected log to contain " # str1 " or " # str2 \
+ " or " # str3);
+
+#define expect_log_msg_containing_either4(str1, str2, str3, str4) \
+ assert_log_predicate(mock_saved_log_has_message_containing(str1) || \
+ mock_saved_log_has_message_containing(str2) || \
+ mock_saved_log_has_message_containing(str3) || \
+ mock_saved_log_has_message_containing(str4), \
+ "expected log to contain " # str1 " or " # str2 \
+ " or " # str3 " or " # str4);
#define expect_single_log_msg(str) \
do { \
diff --git a/src/test/test.c b/src/test/test.c
index b02ecb922d..750d8b00e4 100644
--- a/src/test/test.c
+++ b/src/test/test.c
@@ -1190,6 +1190,7 @@ struct testgroup_t testgroups[] = {
{ "checkdir/", checkdir_tests },
{ "circuitlist/", circuitlist_tests },
{ "circuitmux/", circuitmux_tests },
+ { "circuituse/", circuituse_tests },
{ "compat/libevent/", compat_libevent_tests },
{ "config/", config_tests },
{ "connection/", connection_tests },
diff --git a/src/test/test.h b/src/test/test.h
index 49b4499594..2fa73592ef 100644
--- a/src/test/test.h
+++ b/src/test/test.h
@@ -185,6 +185,7 @@ extern struct testcase_t channeltls_tests[];
extern struct testcase_t checkdir_tests[];
extern struct testcase_t circuitlist_tests[];
extern struct testcase_t circuitmux_tests[];
+extern struct testcase_t circuituse_tests[];
extern struct testcase_t compat_libevent_tests[];
extern struct testcase_t config_tests[];
extern struct testcase_t connection_tests[];
diff --git a/src/test/test_address.c b/src/test/test_address.c
index e52779cb64..0d142ad483 100644
--- a/src/test/test_address.c
+++ b/src/test/test_address.c
@@ -808,8 +808,13 @@ test_address_get_if_addrs6_list_internal(void *arg)
results = get_interface_address6_list(LOG_ERR, AF_INET6, 1);
tt_int_op(smartlist_len(mock_saved_logs()), OP_LE, 1);
if (smartlist_len(mock_saved_logs()) == 1) {
- expect_log_msg_containing_either("connect() failed",
- "unable to create socket");
+ expect_log_msg_containing_either4("connect() failed",
+ "unable to create socket",
+ "Address that we determined via UDP "
+ "socket magic is unsuitable for public "
+ "comms.",
+ "getsockname() to determine interface "
+ "failed");
}
teardown_capture_of_logs();
@@ -846,8 +851,13 @@ test_address_get_if_addrs6_list_no_internal(void *arg)
results = get_interface_address6_list(LOG_ERR, AF_INET6, 0);
tt_int_op(smartlist_len(mock_saved_logs()), OP_LE, 1);
if (smartlist_len(mock_saved_logs()) == 1) {
- expect_log_msg_containing_either("connect() failed",
- "unable to create socket");
+ expect_log_msg_containing_either4("connect() failed",
+ "unable to create socket",
+ "Address that we determined via UDP "
+ "socket magic is unsuitable for public "
+ "comms.",
+ "getsockname() to determine interface "
+ "failed");
}
teardown_capture_of_logs();
diff --git a/src/test/test_circuituse.c b/src/test/test_circuituse.c
new file mode 100644
index 0000000000..edbc9f6391
--- /dev/null
+++ b/src/test/test_circuituse.c
@@ -0,0 +1,302 @@
+/* Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2016, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "or.h"
+#include "test.h"
+#include "test_helpers.h"
+#include "config.h"
+#include "circuitlist.h"
+#include "circuituse.h"
+#include "circuitbuild.h"
+#include "nodelist.h"
+
+static void
+test_circuit_is_available_for_use_ret_false_when_marked_for_close(void *arg)
+{
+ (void)arg;
+
+ circuit_t *circ = tor_malloc(sizeof(circuit_t));
+ circ->marked_for_close = 1;
+
+ tt_int_op(0, ==, circuit_is_available_for_use(circ));
+
+ done:
+ tor_free(circ);
+}
+
+static void
+test_circuit_is_available_for_use_ret_false_when_timestamp_dirty(void *arg)
+{
+ (void)arg;
+
+ circuit_t *circ = tor_malloc(sizeof(circuit_t));
+ circ->timestamp_dirty = 1;
+
+ tt_int_op(0, ==, circuit_is_available_for_use(circ));
+
+ done:
+ tor_free(circ);
+}
+
+static void
+test_circuit_is_available_for_use_ret_false_for_non_general_purpose(void *arg)
+{
+ (void)arg;
+
+ circuit_t *circ = tor_malloc(sizeof(circuit_t));
+ circ->purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING;
+
+ tt_int_op(0, ==, circuit_is_available_for_use(circ));
+
+ done:
+ tor_free(circ);
+}
+
+static void
+test_circuit_is_available_for_use_ret_false_for_non_general_origin(void *arg)
+{
+ (void)arg;
+
+ circuit_t *circ = tor_malloc(sizeof(circuit_t));
+ circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT;
+
+ tt_int_op(0, ==, circuit_is_available_for_use(circ));
+
+ done:
+ tor_free(circ);
+}
+
+static void
+test_circuit_is_available_for_use_ret_false_for_non_origin_purpose(void *arg)
+{
+ (void)arg;
+
+ circuit_t *circ = tor_malloc(sizeof(circuit_t));
+ circ->purpose = CIRCUIT_PURPOSE_OR;
+
+ tt_int_op(0, ==, circuit_is_available_for_use(circ));
+
+ done:
+ tor_free(circ);
+}
+
+static void
+test_circuit_is_available_for_use_ret_false_unusable_for_new_conns(void *arg)
+{
+ (void)arg;
+
+ circuit_t *circ = dummy_origin_circuit_new(30);
+ mark_circuit_unusable_for_new_conns(TO_ORIGIN_CIRCUIT(circ));
+
+ tt_int_op(0, ==, circuit_is_available_for_use(circ));
+
+ done:
+ tor_free(circ);
+}
+
+static void
+test_circuit_is_available_for_use_returns_false_for_onehop_tunnel(void *arg)
+{
+ (void)arg;
+
+ circuit_t *circ = dummy_origin_circuit_new(30);
+ origin_circuit_t *oc = TO_ORIGIN_CIRCUIT(circ);
+ oc->build_state = tor_malloc(sizeof(cpath_build_state_t));
+ oc->build_state->onehop_tunnel = 1;
+
+ tt_int_op(0, ==, circuit_is_available_for_use(circ));
+
+ done:
+ tor_free(circ);
+}
+
+static void
+test_circuit_is_available_for_use_returns_true_for_clean_circuit(void *arg)
+{
+ (void)arg;
+
+ circuit_t *circ = dummy_origin_circuit_new(30);
+ origin_circuit_t *oc = TO_ORIGIN_CIRCUIT(circ);
+ oc->build_state = tor_malloc(sizeof(cpath_build_state_t));
+ oc->build_state->onehop_tunnel = 0;
+
+ tt_int_op(1, ==, circuit_is_available_for_use(circ));
+
+ done:
+ tor_free(circ);
+}
+
+static int
+mock_circuit_all_predicted_ports_handled(time_t now,
+ int *need_uptime,
+ int *need_capacity)
+{
+ (void)now;
+
+ if (need_uptime && need_capacity)
+ return 0;
+ return 1;
+}
+
+static consensus_path_type_t
+mock_router_have_unknown_consensus_path(void)
+{
+ return CONSENSUS_PATH_UNKNOWN;
+}
+
+static consensus_path_type_t
+mock_router_have_exit_consensus_path(void)
+{
+ return CONSENSUS_PATH_EXIT;
+}
+
+static void
+test_needs_exit_circuits_ret_false_for_predicted_ports_and_path(void *arg)
+{
+ (void)arg;
+
+ MOCK(circuit_all_predicted_ports_handled,
+ mock_circuit_all_predicted_ports_handled);
+ int needs_uptime = 1;
+ int needs_capacity = 0;
+
+ time_t now = time(NULL);
+ tt_int_op(0, ==, needs_exit_circuits(now, &needs_uptime, &needs_capacity));
+
+ done:
+ UNMOCK(circuit_all_predicted_ports_handled);
+}
+
+static void
+test_needs_exit_circuits_ret_false_for_non_exit_consensus_path(void *arg)
+{
+ (void)arg;
+
+ MOCK(circuit_all_predicted_ports_handled,
+ mock_circuit_all_predicted_ports_handled);
+ int needs_uptime = 1;
+ int needs_capacity = 1;
+ MOCK(router_have_consensus_path, mock_router_have_unknown_consensus_path);
+
+ time_t now = time(NULL);
+ tt_int_op(0, ==, needs_exit_circuits(now, &needs_uptime, &needs_capacity));
+
+ done:
+ UNMOCK(circuit_all_predicted_ports_handled);
+ UNMOCK(router_have_consensus_path);
+}
+
+static void
+test_needs_exit_circuits_ret_true_for_predicted_ports_and_path(void *arg)
+{
+ (void)arg;
+
+ MOCK(circuit_all_predicted_ports_handled,
+ mock_circuit_all_predicted_ports_handled);
+ int needs_uptime = 1;
+ int needs_capacity = 1;
+ MOCK(router_have_consensus_path, mock_router_have_exit_consensus_path);
+
+ time_t now = time(NULL);
+ tt_int_op(1, ==, needs_exit_circuits(now, &needs_uptime, &needs_capacity));
+
+ done:
+ UNMOCK(circuit_all_predicted_ports_handled);
+ UNMOCK(router_have_consensus_path);
+}
+
+static void
+test_needs_circuits_for_build_ret_false_consensus_path_unknown(void *arg)
+{
+ (void)arg;
+ MOCK(router_have_consensus_path, mock_router_have_unknown_consensus_path);
+ tt_int_op(0, ==, needs_circuits_for_build(0));
+ done: ;
+}
+
+static void
+test_needs_circuits_for_build_ret_false_if_num_less_than_max(void *arg)
+{
+ (void)arg;
+ MOCK(router_have_consensus_path, mock_router_have_exit_consensus_path);
+ tt_int_op(0, ==, needs_circuits_for_build(13));
+ done:
+ UNMOCK(router_have_consensus_path);
+}
+
+static void
+test_needs_circuits_for_build_returns_true_when_more_are_needed(void *arg)
+{
+ (void)arg;
+ MOCK(router_have_consensus_path, mock_router_have_exit_consensus_path);
+ tt_int_op(1, ==, needs_circuits_for_build(0));
+ done:
+ UNMOCK(router_have_consensus_path);
+}
+
+struct testcase_t circuituse_tests[] = {
+ { "marked",
+ test_circuit_is_available_for_use_ret_false_when_marked_for_close,
+ TT_FORK, NULL, NULL
+ },
+ { "timestamp",
+ test_circuit_is_available_for_use_ret_false_when_timestamp_dirty,
+ TT_FORK, NULL, NULL
+ },
+ { "non_general",
+ test_circuit_is_available_for_use_ret_false_for_non_general_purpose,
+ TT_FORK, NULL, NULL
+ },
+ { "non_general",
+ test_circuit_is_available_for_use_ret_false_for_non_general_origin,
+ TT_FORK, NULL, NULL
+ },
+ { "origin",
+ test_circuit_is_available_for_use_ret_false_for_non_origin_purpose,
+ TT_FORK, NULL, NULL
+ },
+ { "clean",
+ test_circuit_is_available_for_use_ret_false_unusable_for_new_conns,
+ TT_FORK, NULL, NULL
+ },
+ { "onehop",
+ test_circuit_is_available_for_use_returns_false_for_onehop_tunnel,
+ TT_FORK, NULL, NULL
+ },
+ { "clean_circ",
+ test_circuit_is_available_for_use_returns_true_for_clean_circuit,
+ TT_FORK, NULL, NULL
+ },
+ { "exit_f",
+ test_needs_exit_circuits_ret_false_for_predicted_ports_and_path,
+ TT_FORK, NULL, NULL
+ },
+ { "exit_t",
+ test_needs_exit_circuits_ret_true_for_predicted_ports_and_path,
+ TT_FORK, NULL, NULL
+ },
+ { "non_exit",
+ test_needs_exit_circuits_ret_false_for_non_exit_consensus_path,
+ TT_FORK, NULL, NULL
+ },
+ { "true",
+ test_needs_exit_circuits_ret_true_for_predicted_ports_and_path,
+ TT_FORK, NULL, NULL
+ },
+ { "consensus_path_unknown",
+ test_needs_circuits_for_build_ret_false_consensus_path_unknown,
+ TT_FORK, NULL, NULL
+ },
+ { "less_than_max",
+ test_needs_circuits_for_build_ret_false_if_num_less_than_max,
+ TT_FORK, NULL, NULL
+ },
+ { "more_needed",
+ test_needs_circuits_for_build_returns_true_when_more_are_needed,
+ TT_FORK, NULL, NULL
+ },
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_config.c b/src/test/test_config.c
index 384bff410f..2fc37b0bb8 100644
--- a/src/test/test_config.c
+++ b/src/test/test_config.c
@@ -3480,10 +3480,12 @@ test_config_default_dir_servers(void *arg)
static int mock_router_pick_published_address_result = 0;
static int
-mock_router_pick_published_address(const or_options_t *options, uint32_t *addr)
+mock_router_pick_published_address(const or_options_t *options,
+ uint32_t *addr, int cache_only)
{
(void)options;
(void)addr;
+ (void)cache_only;
return mock_router_pick_published_address_result;
}
diff --git a/src/test/test_dir.c b/src/test/test_dir.c
index 6f83ceff00..fa0a174813 100644
--- a/src/test/test_dir.c
+++ b/src/test/test_dir.c
@@ -3501,10 +3501,15 @@ test_dir_purpose_needs_anonymity_returns_true_by_default(void *arg)
(void)arg;
tor_capture_bugs_(1);
+ setup_full_capture_of_logs(LOG_WARN);
tt_int_op(1, ==, purpose_needs_anonymity(0, 0, NULL));
tt_int_op(1, ==, smartlist_len(tor_get_captured_bug_log_()));
+ expect_single_log_msg_containing("Called with dir_purpose=0");
+
tor_end_capture_bugs_();
- done: ;
+ done:
+ tor_end_capture_bugs_();
+ teardown_capture_of_logs();
}
static void
diff --git a/src/test/test_helpers.c b/src/test/test_helpers.c
index 130ec43a3a..132af39776 100644
--- a/src/test/test_helpers.c
+++ b/src/test/test_helpers.c
@@ -10,6 +10,7 @@
#include "orconfig.h"
#include "or.h"
+#include "relay.h"
#include "routerlist.h"
#include "nodelist.h"
#include "buffers.h"
@@ -23,6 +24,8 @@ DISABLE_GCC_WARNING(overlength-strings)
* at large. */
#endif
#include "test_descriptors.inc"
+#include "or.h"
+#include "circuitlist.h"
#ifdef HAVE_CFLAG_WOVERLENGTH_STRINGS
ENABLE_GCC_WARNING(overlength-strings)
#endif
@@ -105,3 +108,23 @@ connection_write_to_buf_mock(const char *string, size_t len,
write_to_buf(string, len, conn->outbuf);
}
+/* Set up a fake origin circuit with the specified number of cells,
+ * Return a pointer to the newly-created dummy circuit */
+circuit_t *
+dummy_origin_circuit_new(int n_cells)
+{
+ origin_circuit_t *circ = origin_circuit_new();
+ int i;
+ cell_t cell;
+
+ for (i=0; i < n_cells; ++i) {
+ crypto_rand((void*)&cell, sizeof(cell));
+ cell_queue_append_packed_copy(TO_CIRCUIT(circ),
+ &TO_CIRCUIT(circ)->n_chan_cells,
+ 1, &cell, 1, 0);
+ }
+
+ TO_CIRCUIT(circ)->purpose = CIRCUIT_PURPOSE_C_GENERAL;
+ return TO_CIRCUIT(circ);
+}
+
diff --git a/src/test/test_helpers.h b/src/test/test_helpers.h
index b77a459256..ba93b100d5 100644
--- a/src/test/test_helpers.h
+++ b/src/test/test_helpers.h
@@ -6,6 +6,8 @@
const char *get_yesterday_date_str(void);
+circuit_t * dummy_origin_circuit_new(int num_cells);
+
/* Number of descriptors contained in test_descriptors.txt. */
#define HELPER_NUMBER_OF_DESCRIPTORS 8
diff --git a/src/test/test_hs.c b/src/test/test_hs.c
index 318c549762..6fadeeead2 100644
--- a/src/test/test_hs.c
+++ b/src/test/test_hs.c
@@ -550,17 +550,18 @@ test_single_onion_poisoning(void *arg)
rend_service_t *service_2 = tor_malloc_zero(sizeof(rend_service_t));
char *dir2 = tor_strdup(get_fname_rnd("test_hs_dir2"));
smartlist_t *services = smartlist_new();
+ char *poison_path = NULL;
- /* No services, no problem! */
+ /* No services, no service to verify, no problem! */
mock_options->HiddenServiceSingleHopMode = 0;
mock_options->HiddenServiceNonAnonymousMode = 0;
- ret = rend_service_list_verify_single_onion_poison(services, mock_options);
+ ret = rend_config_services(mock_options, 1);
tt_assert(ret == 0);
/* Either way, no problem. */
mock_options->HiddenServiceSingleHopMode = 1;
mock_options->HiddenServiceNonAnonymousMode = 1;
- ret = rend_service_list_verify_single_onion_poison(services, mock_options);
+ ret = rend_config_services(mock_options, 1);
tt_assert(ret == 0);
/* Create the data directory, and, if the correct bit in arg is set,
@@ -578,44 +579,88 @@ test_single_onion_poisoning(void *arg)
tt_assert(ret == 0);
}
- service_1->directory = dir1;
- service_2->directory = dir2;
+ service_1->directory = tor_strdup(dir1);
+ service_2->directory = tor_strdup(dir2);
+ /* The services own the directory pointers now */
dir1 = dir2 = NULL;
- smartlist_add(services, service_1);
+ /* Add port to service 1 */
+ service_1->ports = smartlist_new();
+ service_2->ports = smartlist_new();
+ char *err_msg = NULL;
+ rend_service_port_config_t *port1 = rend_service_parse_port_config("80", " ",
+ &err_msg);
+ tt_assert(port1);
+ tt_assert(!err_msg);
+ smartlist_add(service_1->ports, port1);
+
+ rend_service_port_config_t *port2 = rend_service_parse_port_config("90", " ",
+ &err_msg);
+ /* Add port to service 2 */
+ tt_assert(port2);
+ tt_assert(!err_msg);
+ smartlist_add(service_2->ports, port2);
+
+ /* No services, a service to verify, no problem! */
+ mock_options->HiddenServiceSingleHopMode = 0;
+ mock_options->HiddenServiceNonAnonymousMode = 0;
+ ret = rend_service_verify_single_onion_poison(service_1, mock_options);
+ tt_assert(ret == 0);
+ ret = rend_service_verify_single_onion_poison(service_2, mock_options);
+ tt_assert(ret == 0);
+
+ /* Either way, no problem. */
+ mock_options->HiddenServiceSingleHopMode = 1;
+ mock_options->HiddenServiceNonAnonymousMode = 1;
+ ret = rend_service_verify_single_onion_poison(service_1, mock_options);
+ tt_assert(ret == 0);
+ ret = rend_service_verify_single_onion_poison(service_2, mock_options);
+ tt_assert(ret == 0);
+
+ /* Add the first service */
+ ret = rend_service_check_dir_and_add(services, mock_options, service_1, 0);
+ tt_assert(ret == 0);
/* But don't add the second service yet. */
/* Service directories, but no previous keys, no problem! */
mock_options->HiddenServiceSingleHopMode = 0;
mock_options->HiddenServiceNonAnonymousMode = 0;
- ret = rend_service_list_verify_single_onion_poison(services, mock_options);
+ ret = rend_service_verify_single_onion_poison(service_1, mock_options);
+ tt_assert(ret == 0);
+ ret = rend_service_verify_single_onion_poison(service_2, mock_options);
tt_assert(ret == 0);
/* Either way, no problem. */
mock_options->HiddenServiceSingleHopMode = 1;
mock_options->HiddenServiceNonAnonymousMode = 1;
- ret = rend_service_list_verify_single_onion_poison(services, mock_options);
+ ret = rend_service_verify_single_onion_poison(service_1, mock_options);
+ tt_assert(ret == 0);
+ ret = rend_service_verify_single_onion_poison(service_2, mock_options);
tt_assert(ret == 0);
/* Poison! Poison! Poison!
* This can only be done in HiddenServiceSingleHopMode. */
mock_options->HiddenServiceSingleHopMode = 1;
mock_options->HiddenServiceNonAnonymousMode = 1;
- ret = rend_service_poison_new_single_onion_dirs(services);
+ ret = rend_service_poison_new_single_onion_dir(service_1, mock_options);
tt_assert(ret == 0);
/* Poisoning twice is a no-op. */
- ret = rend_service_poison_new_single_onion_dirs(services);
+ ret = rend_service_poison_new_single_onion_dir(service_1, mock_options);
tt_assert(ret == 0);
/* Poisoned service directories, but no previous keys, no problem! */
mock_options->HiddenServiceSingleHopMode = 0;
mock_options->HiddenServiceNonAnonymousMode = 0;
- ret = rend_service_list_verify_single_onion_poison(services, mock_options);
+ ret = rend_service_verify_single_onion_poison(service_1, mock_options);
+ tt_assert(ret == 0);
+ ret = rend_service_verify_single_onion_poison(service_2, mock_options);
tt_assert(ret == 0);
/* Either way, no problem. */
mock_options->HiddenServiceSingleHopMode = 1;
mock_options->HiddenServiceNonAnonymousMode = 1;
- ret = rend_service_list_verify_single_onion_poison(services, mock_options);
+ ret = rend_service_verify_single_onion_poison(service_1, mock_options);
+ tt_assert(ret == 0);
+ ret = rend_service_verify_single_onion_poison(service_2, mock_options);
tt_assert(ret == 0);
/* Now add some keys, and we'll have a problem. */
@@ -625,95 +670,121 @@ test_single_onion_poisoning(void *arg)
/* Poisoned service directories with previous keys are not allowed. */
mock_options->HiddenServiceSingleHopMode = 0;
mock_options->HiddenServiceNonAnonymousMode = 0;
- ret = rend_service_list_verify_single_onion_poison(services, mock_options);
+ ret = rend_service_verify_single_onion_poison(service_1, mock_options);
tt_assert(ret < 0);
+ ret = rend_service_verify_single_onion_poison(service_2, mock_options);
+ tt_assert(ret == 0);
/* But they are allowed if we're in non-anonymous mode. */
mock_options->HiddenServiceSingleHopMode = 1;
mock_options->HiddenServiceNonAnonymousMode = 1;
- ret = rend_service_list_verify_single_onion_poison(services, mock_options);
+ ret = rend_service_verify_single_onion_poison(service_1, mock_options);
+ tt_assert(ret == 0);
+ ret = rend_service_verify_single_onion_poison(service_2, mock_options);
tt_assert(ret == 0);
/* Re-poisoning directories with existing keys is a no-op, because
* directories with existing keys are ignored. */
mock_options->HiddenServiceSingleHopMode = 1;
mock_options->HiddenServiceNonAnonymousMode = 1;
- ret = rend_service_poison_new_single_onion_dirs(services);
+ ret = rend_service_poison_new_single_onion_dir(service_1, mock_options);
tt_assert(ret == 0);
/* And it keeps the poison. */
- ret = rend_service_list_verify_single_onion_poison(services, mock_options);
+ ret = rend_service_verify_single_onion_poison(service_1, mock_options);
+ tt_assert(ret == 0);
+ ret = rend_service_verify_single_onion_poison(service_2, mock_options);
tt_assert(ret == 0);
/* Now add the second service: it has no key and no poison file */
- smartlist_add(services, service_2);
+ ret = rend_service_check_dir_and_add(services, mock_options, service_2, 0);
+ tt_assert(ret == 0);
/* A new service, and an existing poisoned service. Not ok. */
mock_options->HiddenServiceSingleHopMode = 0;
mock_options->HiddenServiceNonAnonymousMode = 0;
- ret = rend_service_list_verify_single_onion_poison(services, mock_options);
+ ret = rend_service_verify_single_onion_poison(service_1, mock_options);
tt_assert(ret < 0);
+ ret = rend_service_verify_single_onion_poison(service_2, mock_options);
+ tt_assert(ret == 0);
/* But ok to add in non-anonymous mode. */
mock_options->HiddenServiceSingleHopMode = 1;
mock_options->HiddenServiceNonAnonymousMode = 1;
- ret = rend_service_list_verify_single_onion_poison(services, mock_options);
+ ret = rend_service_verify_single_onion_poison(service_1, mock_options);
+ tt_assert(ret == 0);
+ ret = rend_service_verify_single_onion_poison(service_2, mock_options);
tt_assert(ret == 0);
/* Now remove the poisoning from the first service, and we have the opposite
* problem. */
- char *poison_path = rend_service_sos_poison_path(service_1);
+ poison_path = rend_service_sos_poison_path(service_1);
+ tt_assert(poison_path);
ret = unlink(poison_path);
- tor_free(poison_path);
tt_assert(ret == 0);
/* Unpoisoned service directories with previous keys are ok, as are empty
* directories. */
mock_options->HiddenServiceSingleHopMode = 0;
mock_options->HiddenServiceNonAnonymousMode = 0;
- ret = rend_service_list_verify_single_onion_poison(services, mock_options);
+ ret = rend_service_verify_single_onion_poison(service_1, mock_options);
+ tt_assert(ret == 0);
+ ret = rend_service_verify_single_onion_poison(service_2, mock_options);
tt_assert(ret == 0);
/* But the existing unpoisoned key is not ok in non-anonymous mode, even if
* there is an empty service. */
mock_options->HiddenServiceSingleHopMode = 1;
mock_options->HiddenServiceNonAnonymousMode = 1;
- ret = rend_service_list_verify_single_onion_poison(services, mock_options);
+ ret = rend_service_verify_single_onion_poison(service_1, mock_options);
tt_assert(ret < 0);
+ ret = rend_service_verify_single_onion_poison(service_2, mock_options);
+ tt_assert(ret == 0);
/* Poisoning directories with existing keys is a no-op, because directories
* with existing keys are ignored. But the new directory should poison. */
mock_options->HiddenServiceSingleHopMode = 1;
mock_options->HiddenServiceNonAnonymousMode = 1;
- ret = rend_service_poison_new_single_onion_dirs(services);
+ ret = rend_service_poison_new_single_onion_dir(service_1, mock_options);
+ tt_assert(ret == 0);
+ ret = rend_service_poison_new_single_onion_dir(service_2, mock_options);
tt_assert(ret == 0);
/* And the old directory remains unpoisoned. */
- ret = rend_service_list_verify_single_onion_poison(services, mock_options);
+ ret = rend_service_verify_single_onion_poison(service_1, mock_options);
tt_assert(ret < 0);
+ ret = rend_service_verify_single_onion_poison(service_2, mock_options);
+ tt_assert(ret == 0);
/* And the new directory should be ignored, because it has no key. */
mock_options->HiddenServiceSingleHopMode = 0;
mock_options->HiddenServiceNonAnonymousMode = 0;
- ret = rend_service_list_verify_single_onion_poison(services, mock_options);
+ ret = rend_service_verify_single_onion_poison(service_1, mock_options);
+ tt_assert(ret == 0);
+ ret = rend_service_verify_single_onion_poison(service_2, mock_options);
tt_assert(ret == 0);
/* Re-poisoning directories without existing keys is a no-op. */
mock_options->HiddenServiceSingleHopMode = 1;
mock_options->HiddenServiceNonAnonymousMode = 1;
- ret = rend_service_poison_new_single_onion_dirs(services);
+ ret = rend_service_poison_new_single_onion_dir(service_1, mock_options);
+ tt_assert(ret == 0);
+ ret = rend_service_poison_new_single_onion_dir(service_2, mock_options);
tt_assert(ret == 0);
/* And the old directory remains unpoisoned. */
- ret = rend_service_list_verify_single_onion_poison(services, mock_options);
+ ret = rend_service_verify_single_onion_poison(service_1, mock_options);
tt_assert(ret < 0);
+ ret = rend_service_verify_single_onion_poison(service_2, mock_options);
+ tt_assert(ret == 0);
done:
/* The test harness deletes the directories at exit */
+ tor_free(poison_path);
+ tor_free(dir1);
+ tor_free(dir2);
+ smartlist_free(services);
rend_service_free(service_1);
rend_service_free(service_2);
- smartlist_free(services);
UNMOCK(get_options);
tor_free(mock_options->DataDirectory);
- tor_free(dir1);
- tor_free(dir2);
}
struct testcase_t hs_tests[] = {
diff --git a/src/test/test_hs_descriptor.c b/src/test/test_hs_descriptor.c
index 8af5cabca3..9749c3b096 100644
--- a/src/test/test_hs_descriptor.c
+++ b/src/test/test_hs_descriptor.c
@@ -254,7 +254,7 @@ test_cert_encoding(void *arg)
tt_assert(cert);
/* Test the certificate encoding function. */
- ret = encode_cert(cert, &encoded);
+ ret = tor_cert_encode_ed22519(cert, &encoded);
tt_int_op(ret, ==, 0);
/* Validated the certificate string. */
diff --git a/src/test/test_oom.c b/src/test/test_oom.c
index 6102af01f5..0f97972032 100644
--- a/src/test/test_oom.c
+++ b/src/test/test_oom.c
@@ -15,6 +15,7 @@
#include "config.h"
#include "relay.h"
#include "test.h"
+#include "test_helpers.h"
/* small replacement mock for circuit_mark_for_close_ to avoid doing all
* the other bookkeeping that comes with marking circuits. */
@@ -58,24 +59,6 @@ dummy_or_circuit_new(int n_p_cells, int n_n_cells)
return TO_CIRCUIT(circ);
}
-static circuit_t *
-dummy_origin_circuit_new(int n_cells)
-{
- origin_circuit_t *circ = origin_circuit_new();
- int i;
- cell_t cell;
-
- for (i=0; i < n_cells; ++i) {
- crypto_rand((void*)&cell, sizeof(cell));
- cell_queue_append_packed_copy(TO_CIRCUIT(circ),
- &TO_CIRCUIT(circ)->n_chan_cells,
- 1, &cell, 1, 0);
- }
-
- TO_CIRCUIT(circ)->purpose = CIRCUIT_PURPOSE_C_GENERAL;
- return TO_CIRCUIT(circ);
-}
-
static void
add_bytes_to_buf(buf_t *buf, size_t n_bytes)
{
diff --git a/src/test/test_options.c b/src/test/test_options.c
index 0eada98cb2..e85e11805b 100644
--- a/src/test/test_options.c
+++ b/src/test/test_options.c
@@ -1050,7 +1050,7 @@ test_options_validate__transproxy(void *ignored)
tt_int_op(ret, OP_EQ, -1);
#ifndef KERNEL_MAY_SUPPORT_IPFW
- tt_str_op(msg, OP_EQ, "ipfw is a FreeBSD-specificand OS X/Darwin-specific "
+ tt_str_op(msg, OP_EQ, "ipfw is a FreeBSD-specific and OS X/Darwin-specific "
"feature.");
#else
tt_int_op(tdata->opt->TransProxyType_parsed, OP_EQ, TPT_IPFW);
@@ -1071,26 +1071,38 @@ test_options_validate__transproxy(void *ignored)
free_options_test_data(tdata);
tdata = NULL;
-#if defined(linux)
+#if defined(__linux__)
tdata = get_options_test_data("TransProxyType tproxy\n"
"TransPort 127.0.0.1:123\n");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
- tt_assert(!msg);
-#endif
-#if defined(__FreeBSD_kernel__) || defined( DARWIN ) || defined(__NetBSD__)
+ if (msg) {
+ TT_DIE(("Expected NULL but got '%s'", msg));
+ }
+#elif defined(KERNEL_MAY_SUPPORT_IPFW)
tdata = get_options_test_data("TransProxyType ipfw\n"
"TransPort 127.0.0.1:123\n");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
- tt_assert(!msg);
-#endif
-#if defined(__OpenBSD__)
+ if (msg) {
+ TT_DIE(("Expected NULL but got '%s'", msg));
+ }
+#elif defined(__OpenBSD__)
tdata = get_options_test_data("TransProxyType pf-divert\n"
"TransPort 127.0.0.1:123\n");
ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
tt_int_op(ret, OP_EQ, -1);
- tt_assert(!msg);
+ if (msg) {
+ TT_DIE(("Expected NULL but got '%s'", msg));
+ }
+#elif defined(__NetBSD__)
+ tdata = get_options_test_data("TransProxyType default\n"
+ "TransPort 127.0.0.1:123\n");
+ ret = options_validate(tdata->old_opt, tdata->opt, tdata->def_opt, 0, &msg);
+ tt_int_op(ret, OP_EQ, -1);
+ if (msg) {
+ TT_DIE(("Expected NULL but got '%s'", msg));
+ }
#endif
// Assert that a test has run for some TransProxyType
diff --git a/src/test/test_util.c b/src/test/test_util.c
index b74f658146..7e5a44cb59 100644
--- a/src/test/test_util.c
+++ b/src/test/test_util.c
@@ -5531,9 +5531,9 @@ test_util_monotonic_time(void *arg)
tt_u64_op(msecc1, OP_GE, nsecc1 / 1000000);
tt_u64_op(usecc1, OP_GE, nsecc1 / 1000);
tt_u64_op(msec1, OP_LE, nsec1 / 1000000 + 1);
- tt_u64_op(usec1, OP_LE, nsec1 / 1000 +10);
+ tt_u64_op(usec1, OP_LE, nsec1 / 1000 + 1000);
tt_u64_op(msecc1, OP_LE, nsecc1 / 1000000 + 1);
- tt_u64_op(usecc1, OP_LE, nsecc1 / 1000 + 10);
+ tt_u64_op(usecc1, OP_LE, nsecc1 / 1000 + 1000);
done:
;