aboutsummaryrefslogtreecommitdiff
path: root/src/or
diff options
context:
space:
mode:
Diffstat (limited to 'src/or')
-rw-r--r--src/or/auth_dirs.inc33
-rw-r--r--src/or/bridges.c4
-rw-r--r--src/or/channel.c23
-rw-r--r--src/or/channel.h3
-rw-r--r--src/or/channelpadding.c1
-rw-r--r--src/or/channeltls.c5
-rw-r--r--src/or/circuitbuild.c91
-rw-r--r--src/or/circuitlist.c32
-rw-r--r--src/or/circuitmux.c678
-rw-r--r--src/or/circuitmux_ewma.c115
-rw-r--r--src/or/circuitmux_ewma.h7
-rw-r--r--src/or/command.c4
-rw-r--r--src/or/config.c153
-rw-r--r--src/or/connection_or.c225
-rw-r--r--src/or/connection_or.h5
-rw-r--r--src/or/control.c86
-rw-r--r--src/or/cpuworker.c27
-rw-r--r--src/or/directory.c122
-rw-r--r--src/or/directory.h25
-rw-r--r--src/or/dirserv.c8
-rw-r--r--src/or/dns.c19
-rw-r--r--src/or/dnsserv.c1
-rw-r--r--src/or/entrynodes.c2
-rw-r--r--src/or/geoip.c6
-rw-r--r--src/or/hs_cell.c2
-rw-r--r--src/or/hs_service.c34
-rw-r--r--src/or/include.am3
-rw-r--r--src/or/keypin.c2
-rw-r--r--src/or/main.c119
-rw-r--r--src/or/microdesc.c3
-rw-r--r--src/or/networkstatus.c67
-rw-r--r--src/or/nodelist.c32
-rw-r--r--src/or/nodelist.h2
-rw-r--r--src/or/ntmain.c5
-rw-r--r--src/or/onion_ntor.c1
-rw-r--r--src/or/or.h101
-rw-r--r--src/or/periodic.c21
-rw-r--r--src/or/periodic.h5
-rw-r--r--src/or/proto_socks.c4
-rw-r--r--src/or/protover.c112
-rw-r--r--src/or/relay.c206
-rw-r--r--src/or/relay.h4
-rw-r--r--src/or/relay_crypto.c326
-rw-r--r--src/or/relay_crypto.h31
-rw-r--r--src/or/router.c104
-rw-r--r--src/or/router.h18
-rw-r--r--src/or/routerlist.c19
-rw-r--r--src/or/routerparse.c1
-rw-r--r--src/or/scheduler.c25
-rw-r--r--src/or/scheduler.h4
-rw-r--r--src/or/scheduler_kist.c4
-rw-r--r--src/or/scheduler_vanilla.c4
-rw-r--r--src/or/tor_api.h14
-rw-r--r--src/or/transports.c182
54 files changed, 1314 insertions, 1816 deletions
diff --git a/src/or/auth_dirs.inc b/src/or/auth_dirs.inc
new file mode 100644
index 0000000000..58e6817c86
--- /dev/null
+++ b/src/or/auth_dirs.inc
@@ -0,0 +1,33 @@
+"moria1 orport=9101 "
+ "v3ident=D586D18309DED4CD6D57C18FDB97EFA96D330566 "
+ "128.31.0.39:9131 9695 DFC3 5FFE B861 329B 9F1A B04C 4639 7020 CE31",
+"tor26 orport=443 "
+ "v3ident=14C131DFC5C6F93646BE72FA1401C02A8DF2E8B4 "
+ "ipv6=[2001:858:2:2:aabb:0:563b:1526]:443 "
+ "86.59.21.38:80 847B 1F85 0344 D787 6491 A548 92F9 0493 4E4E B85D",
+"dizum orport=443 "
+ "v3ident=E8A9C45EDE6D711294FADF8E7951F4DE6CA56B58 "
+ "194.109.206.212:80 7EA6 EAD6 FD83 083C 538F 4403 8BBF A077 587D D755",
+"Bifroest orport=443 bridge "
+ "37.218.247.217:80 1D8F 3A91 C37C 5D1C 4C19 B1AD 1D0C FBE8 BF72 D8E1",
+"gabelmoo orport=443 "
+ "v3ident=ED03BB616EB2F60BEC80151114BB25CEF515B226 "
+ "ipv6=[2001:638:a000:4140::ffff:189]:443 "
+ "131.188.40.189:80 F204 4413 DAC2 E02E 3D6B CF47 35A1 9BCA 1DE9 7281",
+"dannenberg orport=443 "
+ "v3ident=0232AF901C31A04EE9848595AF9BB7620D4C5B2E "
+ "193.23.244.244:80 7BE6 83E6 5D48 1413 21C5 ED92 F075 C553 64AC 7123",
+"maatuska orport=80 "
+ "v3ident=49015F787433103580E3B66A1707A00E60F2D15B "
+ "ipv6=[2001:67c:289c::9]:80 "
+ "171.25.193.9:443 BD6A 8292 55CB 08E6 6FBE 7D37 4836 3586 E46B 3810",
+"Faravahar orport=443 "
+ "v3ident=EFCBE720AB3A82B99F9E953CD5BF50F7EEFC7B97 "
+ "154.35.175.225:80 CF6D 0AAF B385 BE71 B8E1 11FC 5CFF 4B47 9237 33BC",
+"longclaw orport=443 "
+ "v3ident=23D15D965BC35114467363C165C4F724B64B4F66 "
+ "199.58.81.140:80 74A9 1064 6BCE EFBC D2E8 74FC 1DC9 9743 0F96 8145",
+"bastet orport=443 "
+ "v3ident=27102BC123E7AF1D4741AE047E160C91ADC76B21 "
+ "ipv6=[2620:13:4000:6000::1000:118]:443 "
+ "204.13.164.118:80 24E2 F139 121D 4394 C54B 5BCC 368B 3B41 1857 C413",
diff --git a/src/or/bridges.c b/src/or/bridges.c
index 4ee3550048..699e030e6c 100644
--- a/src/or/bridges.c
+++ b/src/or/bridges.c
@@ -460,7 +460,6 @@ bridge_add_from_config(bridge_line_t *bridge_line)
if (bridge_line->transport_name)
b->transport_name = bridge_line->transport_name;
b->fetch_status.schedule = DL_SCHED_BRIDGE;
- b->fetch_status.backoff = DL_SCHED_RANDOM_EXPONENTIAL;
b->fetch_status.increment_on = DL_SCHED_INCREMENT_ATTEMPT;
/* We can't reset the bridge's download status here, because UseBridges
* might be 0 now, and it might be changed to 1 much later. */
@@ -639,8 +638,7 @@ fetch_bridge_descriptors(const or_options_t *options, time_t now)
SMARTLIST_FOREACH_BEGIN(bridge_list, bridge_info_t *, bridge)
{
/* This resets the download status on first use */
- if (!download_status_is_ready(&bridge->fetch_status, now,
- IMPOSSIBLE_TO_DOWNLOAD))
+ if (!download_status_is_ready(&bridge->fetch_status, now))
continue; /* don't bother, no need to retry yet */
if (routerset_contains_bridge(options->ExcludeNodes, bridge)) {
download_status_mark_impossible(&bridge->fetch_status);
diff --git a/src/or/channel.c b/src/or/channel.c
index ff1cfde2ad..68245db497 100644
--- a/src/or/channel.c
+++ b/src/or/channel.c
@@ -1849,8 +1849,8 @@ channel_do_open_actions(channel_t *chan)
circuit_build_times_network_is_live(get_circuit_build_times_mutable());
router_set_status(chan->identity_digest, 1);
} else {
- /* only report it to the geoip module if it's not a known router */
- if (!connection_or_digest_is_known_relay(chan->identity_digest)) {
+ /* only report it to the geoip module if it's a client */
+ if (channel_is_client(chan)) {
if (channel_get_addr_if_possible(chan, &remote_addr)) {
char *transport_name = NULL;
channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan);
@@ -2109,21 +2109,6 @@ channel_listener_dumpstats(int severity)
}
/**
- * Set the cmux policy on all active channels.
- */
-void
-channel_set_cmux_policy_everywhere(circuitmux_policy_t *pol)
-{
- if (!active_channels) return;
-
- SMARTLIST_FOREACH_BEGIN(active_channels, channel_t *, curr) {
- if (curr->cmux) {
- circuitmux_set_policy(curr->cmux, pol);
- }
- } SMARTLIST_FOREACH_END(curr);
-}
-
-/**
* Clean up channels.
*
* This gets called periodically from run_scheduled_events() in main.c;
@@ -2402,7 +2387,7 @@ channel_get_for_extend(const char *rsa_id_digest,
{
channel_t *chan, *best = NULL;
int n_inprogress_goodaddr = 0, n_old = 0;
- int n_noncanonical = 0, n_possible = 0;
+ int n_noncanonical = 0;
tor_assert(msg_out);
tor_assert(launch_out);
@@ -2465,8 +2450,6 @@ channel_get_for_extend(const char *rsa_id_digest,
continue;
}
- ++n_possible;
-
if (!best) {
best = chan; /* If we have no 'best' so far, this one is good enough. */
continue;
diff --git a/src/or/channel.h b/src/or/channel.h
index 0af5aed414..6cf8cd7f72 100644
--- a/src/or/channel.h
+++ b/src/or/channel.h
@@ -422,9 +422,6 @@ void channel_free_all(void);
void channel_dumpstats(int severity);
void channel_listener_dumpstats(int severity);
-/* Set the cmux policy on all active channels */
-void channel_set_cmux_policy_everywhere(circuitmux_policy_t *pol);
-
#ifdef TOR_CHANNEL_INTERNAL_
#ifdef CHANNEL_PRIVATE_
diff --git a/src/or/channelpadding.c b/src/or/channelpadding.c
index 5da3009e67..33b1cba355 100644
--- a/src/or/channelpadding.c
+++ b/src/or/channelpadding.c
@@ -20,7 +20,6 @@
#include "rephist.h"
#include "router.h"
#include "compat_time.h"
-#include <event2/event.h>
#include "rendservice.h"
STATIC int32_t channelpadding_get_netflow_inactive_timeout_ms(
diff --git a/src/or/channeltls.c b/src/or/channeltls.c
index 9000703b01..54d94f6109 100644
--- a/src/or/channeltls.c
+++ b/src/or/channeltls.c
@@ -160,9 +160,8 @@ channel_tls_common_init(channel_tls_t *tlschan)
chan->write_var_cell = channel_tls_write_var_cell_method;
chan->cmux = circuitmux_alloc();
- if (cell_ewma_enabled()) {
- circuitmux_set_policy(chan->cmux, &ewma_policy);
- }
+ /* We only have one policy for now so always set it to EWMA. */
+ circuitmux_set_policy(chan->cmux, &ewma_policy);
}
/**
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c
index b3b543348c..488f6a2148 100644
--- a/src/or/circuitbuild.c
+++ b/src/or/circuitbuild.c
@@ -56,6 +56,7 @@
#include "onion_fast.h"
#include "policies.h"
#include "relay.h"
+#include "relay_crypto.h"
#include "rendcommon.h"
#include "rephist.h"
#include "router.h"
@@ -1336,69 +1337,10 @@ circuit_init_cpath_crypto(crypt_path_t *cpath,
const char *key_data, size_t key_data_len,
int reverse, int is_hs_v3)
{
- crypto_digest_t *tmp_digest;
- crypto_cipher_t *tmp_crypto;
- size_t digest_len = 0;
- size_t cipher_key_len = 0;
tor_assert(cpath);
- tor_assert(key_data);
- tor_assert(!(cpath->f_crypto || cpath->b_crypto ||
- cpath->f_digest || cpath->b_digest));
-
- /* Basic key size validation */
- if (is_hs_v3 && BUG(key_data_len != HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN)) {
- return -1;
- } else if (!is_hs_v3 && BUG(key_data_len != CPATH_KEY_MATERIAL_LEN)) {
- return -1;
- }
-
- /* If we are using this cpath for next gen onion services use SHA3-256,
- otherwise use good ol' SHA1 */
- if (is_hs_v3) {
- digest_len = DIGEST256_LEN;
- cipher_key_len = CIPHER256_KEY_LEN;
- cpath->f_digest = crypto_digest256_new(DIGEST_SHA3_256);
- cpath->b_digest = crypto_digest256_new(DIGEST_SHA3_256);
- } else {
- digest_len = DIGEST_LEN;
- cipher_key_len = CIPHER_KEY_LEN;
- cpath->f_digest = crypto_digest_new();
- cpath->b_digest = crypto_digest_new();
- }
-
- tor_assert(digest_len != 0);
- tor_assert(cipher_key_len != 0);
- const int cipher_key_bits = (int) cipher_key_len * 8;
-
- crypto_digest_add_bytes(cpath->f_digest, key_data, digest_len);
- crypto_digest_add_bytes(cpath->b_digest, key_data+digest_len, digest_len);
-
- cpath->f_crypto = crypto_cipher_new_with_bits(key_data+(2*digest_len),
- cipher_key_bits);
- if (!cpath->f_crypto) {
- log_warn(LD_BUG,"Forward cipher initialization failed.");
- return -1;
- }
-
- cpath->b_crypto = crypto_cipher_new_with_bits(
- key_data+(2*digest_len)+cipher_key_len,
- cipher_key_bits);
- if (!cpath->b_crypto) {
- log_warn(LD_BUG,"Backward cipher initialization failed.");
- return -1;
- }
-
- if (reverse) {
- tmp_digest = cpath->f_digest;
- cpath->f_digest = cpath->b_digest;
- cpath->b_digest = tmp_digest;
- tmp_crypto = cpath->f_crypto;
- cpath->f_crypto = cpath->b_crypto;
- cpath->b_crypto = tmp_crypto;
- }
-
- return 0;
+ return relay_crypto_init(&cpath->crypto, key_data, key_data_len, reverse,
+ is_hs_v3);
}
/** A "created" cell <b>reply</b> came back to us on circuit <b>circ</b>.
@@ -1521,7 +1463,6 @@ onionskin_answer(or_circuit_t *circ,
const uint8_t *rend_circ_nonce)
{
cell_t cell;
- crypt_path_t *tmp_cpath;
tor_assert(keys_len == CPATH_KEY_MATERIAL_LEN);
@@ -1532,25 +1473,15 @@ onionskin_answer(or_circuit_t *circ,
}
cell.circ_id = circ->p_circ_id;
- tmp_cpath = tor_malloc_zero(sizeof(crypt_path_t));
- tmp_cpath->magic = CRYPT_PATH_MAGIC;
-
circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OPEN);
log_debug(LD_CIRC,"init digest forward 0x%.8x, backward 0x%.8x.",
(unsigned int)get_uint32(keys),
(unsigned int)get_uint32(keys+20));
- if (circuit_init_cpath_crypto(tmp_cpath, keys, keys_len, 0, 0)<0) {
+ if (relay_crypto_init(&circ->crypto, keys, keys_len, 0, 0)<0) {
log_warn(LD_BUG,"Circuit initialization failed");
- tor_free(tmp_cpath);
return -1;
}
- circ->n_digest = tmp_cpath->f_digest;
- circ->n_crypto = tmp_cpath->f_crypto;
- circ->p_digest = tmp_cpath->b_digest;
- circ->p_crypto = tmp_cpath->b_crypto;
- tmp_cpath->magic = 0;
- tor_free(tmp_cpath);
memcpy(circ->rend_circ_nonce, rend_circ_nonce, DIGEST_LEN);
@@ -2857,8 +2788,18 @@ extend_info_from_node(const node_t *node, int for_direct_connect)
tor_addr_port_t ap;
int valid_addr = 0;
- if (node->ri == NULL && (node->rs == NULL || node->md == NULL))
- return NULL;
+ const int is_bridge = node_is_a_configured_bridge(node);
+ const int we_use_mds = we_use_microdescriptors_for_circuits(get_options());
+
+ if (is_bridge || !we_use_mds) {
+ /* We need an ri in this case. */
+ if (!node->ri)
+ return NULL;
+ } else {
+ /* Otherwise we need an md. */
+ if (node->rs == NULL || node->md == NULL)
+ return NULL;
+ }
/* Choose a preferred address first, but fall back to an allowed address.
* choose_address returns 1 on success, but get_prim_orport returns 0. */
diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c
index 29ad9a8ee5..9a82713cbe 100644
--- a/src/or/circuitlist.c
+++ b/src/or/circuitlist.c
@@ -76,12 +76,16 @@
#include "onion_fast.h"
#include "policies.h"
#include "relay.h"
+#include "relay_crypto.h"
#include "rendclient.h"
#include "rendcommon.h"
#include "rephist.h"
#include "routerlist.h"
#include "routerset.h"
#include "channelpadding.h"
+#include "compress_lzma.h"
+#include "compress_zlib.h"
+#include "compress_zstd.h"
#include "ht.h"
@@ -403,9 +407,6 @@ circuit_set_p_circid_chan(or_circuit_t *or_circ, circid_t id,
circuit_set_circid_chan_helper(circ, CELL_DIRECTION_IN, id, chan);
if (chan) {
- tor_assert(bool_eq(or_circ->p_chan_cells.n,
- or_circ->next_active_on_p_chan));
-
chan->timestamp_last_had_circuits = approx_time();
}
@@ -428,8 +429,6 @@ circuit_set_n_circid_chan(circuit_t *circ, circid_t id,
circuit_set_circid_chan_helper(circ, CELL_DIRECTION_OUT, id, chan);
if (chan) {
- tor_assert(bool_eq(circ->n_chan_cells.n, circ->next_active_on_n_chan));
-
chan->timestamp_last_had_circuits = approx_time();
}
@@ -1084,10 +1083,7 @@ circuit_free_(circuit_t *circ)
should_free = (ocirc->workqueue_entry == NULL);
- crypto_cipher_free(ocirc->p_crypto);
- crypto_digest_free(ocirc->p_digest);
- crypto_cipher_free(ocirc->n_crypto);
- crypto_digest_free(ocirc->n_digest);
+ relay_crypto_clear(&ocirc->crypto);
if (ocirc->rend_splice) {
or_circuit_t *other = ocirc->rend_splice;
@@ -1227,10 +1223,7 @@ circuit_free_cpath_node(crypt_path_t *victim)
if (!victim)
return;
- crypto_cipher_free(victim->f_crypto);
- crypto_cipher_free(victim->b_crypto);
- crypto_digest_free(victim->f_digest);
- crypto_digest_free(victim->b_digest);
+ relay_crypto_clear(&victim->crypto);
onion_handshake_state_release(&victim->handshake_state);
crypto_dh_free(victim->rend_dh_handshake_state);
extend_info_free(victim->extend_info);
@@ -2476,12 +2469,17 @@ circuits_handle_oom(size_t current_allocation)
log_notice(LD_GENERAL, "We're low on memory (cell queues total alloc:"
" %"TOR_PRIuSZ" buffer total alloc: %" TOR_PRIuSZ ","
" tor compress total alloc: %" TOR_PRIuSZ
+ " (zlib: %" TOR_PRIuSZ ", zstd: %" TOR_PRIuSZ ","
+ " lzma: %" TOR_PRIuSZ "),"
" rendezvous cache total alloc: %" TOR_PRIuSZ "). Killing"
" circuits withover-long queues. (This behavior is controlled by"
" MaxMemInQueues.)",
cell_queues_get_total_allocation(),
buf_get_total_allocation(),
tor_compress_get_total_allocation(),
+ tor_zlib_get_total_allocation(),
+ tor_zstd_get_total_allocation(),
+ tor_lzma_get_total_allocation(),
rend_cache_get_total_allocation());
{
@@ -2588,8 +2586,7 @@ assert_cpath_layer_ok(const crypt_path_t *cp)
switch (cp->state)
{
case CPATH_STATE_OPEN:
- tor_assert(cp->f_crypto);
- tor_assert(cp->b_crypto);
+ relay_crypto_assert_ok(&cp->crypto);
/* fall through */
case CPATH_STATE_CLOSED:
/*XXXX Assert that there's no handshake_state either. */
@@ -2679,10 +2676,7 @@ assert_circuit_ok,(const circuit_t *c))
c->state == CIRCUIT_STATE_GUARD_WAIT) {
tor_assert(!c->n_chan_create_cell);
if (or_circ) {
- tor_assert(or_circ->n_crypto);
- tor_assert(or_circ->p_crypto);
- tor_assert(or_circ->n_digest);
- tor_assert(or_circ->p_digest);
+ relay_crypto_assert_ok(&or_circ->crypto);
}
}
if (c->state == CIRCUIT_STATE_CHAN_WAIT && !c->marked_for_close) {
diff --git a/src/or/circuitmux.c b/src/or/circuitmux.c
index fe3d8f1332..f9f5faa057 100644
--- a/src/or/circuitmux.c
+++ b/src/or/circuitmux.c
@@ -114,13 +114,6 @@ struct circuitmux_s {
*/
chanid_circid_muxinfo_map_t *chanid_circid_map;
- /*
- * Double-linked ring of circuits with queued cells waiting for room to
- * free up on this connection's outbuf. Every time we pull cells from
- * a circuit, we advance this pointer to the next circuit in the ring.
- */
- struct circuit_t *active_circuits_head, *active_circuits_tail;
-
/** List of queued destroy cells */
destroy_cell_queue_t destroy_cell_queue;
/** Boolean: True iff the last cell to circuitmux_get_first_active_circuit
@@ -177,17 +170,6 @@ struct chanid_circid_muxinfo_t {
};
/*
- * Internal-use #defines
- */
-
-#ifdef CMUX_PARANOIA
-#define circuitmux_assert_okay_paranoid(cmux) \
- circuitmux_assert_okay(cmux)
-#else
-#define circuitmux_assert_okay_paranoid(cmux)
-#endif /* defined(CMUX_PARANOIA) */
-
-/*
* Static function declarations
*/
@@ -199,21 +181,9 @@ chanid_circid_entry_hash(chanid_circid_muxinfo_t *a);
static chanid_circid_muxinfo_t *
circuitmux_find_map_entry(circuitmux_t *cmux, circuit_t *circ);
static void
-circuitmux_make_circuit_active(circuitmux_t *cmux, circuit_t *circ,
- cell_direction_t direction);
+circuitmux_make_circuit_active(circuitmux_t *cmux, circuit_t *circ);
static void
-circuitmux_make_circuit_inactive(circuitmux_t *cmux, circuit_t *circ,
- cell_direction_t direction);
-static inline void
-circuitmux_move_active_circ_to_tail(circuitmux_t *cmux, circuit_t *circ,
- cell_direction_t direction);
-static inline circuit_t **
-circuitmux_next_active_circ_p(circuitmux_t *cmux, circuit_t *circ);
-static inline circuit_t **
-circuitmux_prev_active_circ_p(circuitmux_t *cmux, circuit_t *circ);
-static void circuitmux_assert_okay_pass_one(circuitmux_t *cmux);
-static void circuitmux_assert_okay_pass_two(circuitmux_t *cmux);
-static void circuitmux_assert_okay_pass_three(circuitmux_t *cmux);
+circuitmux_make_circuit_inactive(circuitmux_t *cmux, circuit_t *circ);
/* Static global variables */
@@ -223,119 +193,6 @@ static int64_t global_destroy_ctr = 0;
/* Function definitions */
/**
- * Linked list helpers
- */
-
-/**
- * Move an active circuit to the tail of the cmux's active circuits list;
- * used by circuitmux_notify_xmit_cells().
- */
-
-static inline void
-circuitmux_move_active_circ_to_tail(circuitmux_t *cmux, circuit_t *circ,
- cell_direction_t direction)
-{
- circuit_t **next_p = NULL, **prev_p = NULL;
- circuit_t **next_prev = NULL, **prev_next = NULL;
- circuit_t **tail_next = NULL;
- or_circuit_t *or_circ = NULL;
-
- tor_assert(cmux);
- tor_assert(circ);
-
- circuitmux_assert_okay_paranoid(cmux);
-
- /* Figure out our next_p and prev_p for this cmux/direction */
- if (direction) {
- if (direction == CELL_DIRECTION_OUT) {
- tor_assert(circ->n_mux == cmux);
- next_p = &(circ->next_active_on_n_chan);
- prev_p = &(circ->prev_active_on_n_chan);
- } else {
- or_circ = TO_OR_CIRCUIT(circ);
- tor_assert(or_circ->p_mux == cmux);
- next_p = &(or_circ->next_active_on_p_chan);
- prev_p = &(or_circ->prev_active_on_p_chan);
- }
- } else {
- if (circ->n_mux == cmux) {
- next_p = &(circ->next_active_on_n_chan);
- prev_p = &(circ->prev_active_on_n_chan);
- } else {
- or_circ = TO_OR_CIRCUIT(circ);
- tor_assert(or_circ->p_mux == cmux);
- next_p = &(or_circ->next_active_on_p_chan);
- prev_p = &(or_circ->prev_active_on_p_chan);
- }
- }
- tor_assert(next_p);
- tor_assert(prev_p);
-
- /* Check if this really is an active circuit */
- if ((*next_p == NULL && *prev_p == NULL) &&
- !(circ == cmux->active_circuits_head ||
- circ == cmux->active_circuits_tail)) {
- /* Not active, no-op */
- return;
- }
-
- /* Check if this is already the tail */
- if (circ == cmux->active_circuits_tail) return;
-
- /* Okay, we have to move it; figure out next_prev and prev_next */
- if (*next_p) next_prev = circuitmux_prev_active_circ_p(cmux, *next_p);
- if (*prev_p) prev_next = circuitmux_next_active_circ_p(cmux, *prev_p);
- /* Adjust the previous node's next pointer, if any */
- if (prev_next) *prev_next = *next_p;
- /* Otherwise, we were the head */
- else cmux->active_circuits_head = *next_p;
- /* Adjust the next node's previous pointer, if any */
- if (next_prev) *next_prev = *prev_p;
- /* We're out of the list; now re-attach at the tail */
- /* Adjust our next and prev pointers */
- *next_p = NULL;
- *prev_p = cmux->active_circuits_tail;
- /* Set the next pointer of the tail, or the head if none */
- if (cmux->active_circuits_tail) {
- tail_next = circuitmux_next_active_circ_p(cmux,
- cmux->active_circuits_tail);
- *tail_next = circ;
- } else {
- cmux->active_circuits_head = circ;
- }
- /* Set the tail to this circuit */
- cmux->active_circuits_tail = circ;
-
- circuitmux_assert_okay_paranoid(cmux);
-}
-
-static inline circuit_t **
-circuitmux_next_active_circ_p(circuitmux_t *cmux, circuit_t *circ)
-{
- tor_assert(cmux);
- tor_assert(circ);
-
- if (circ->n_mux == cmux) return &(circ->next_active_on_n_chan);
- else {
- tor_assert(TO_OR_CIRCUIT(circ)->p_mux == cmux);
- return &(TO_OR_CIRCUIT(circ)->next_active_on_p_chan);
- }
-}
-
-static inline circuit_t **
-circuitmux_prev_active_circ_p(circuitmux_t *cmux, circuit_t *circ)
-{
- tor_assert(cmux);
- tor_assert(circ);
-
- if (circ->n_mux == cmux) return &(circ->prev_active_on_n_chan);
- else {
- tor_assert(TO_OR_CIRCUIT(circ)->p_mux == cmux);
- return &(TO_OR_CIRCUIT(circ)->prev_active_on_p_chan);
- }
-}
-
-/**
* Helper for chanid_circid_cell_count_map_t hash table: compare the channel
* ID and circuit ID for a and b, and return less than, equal to, or greater
* than zero appropriately.
@@ -406,11 +263,6 @@ circuitmux_detach_all_circuits(circuitmux_t *cmux, smartlist_t *detached_out)
circuit_t *circ = NULL;
tor_assert(cmux);
- /*
- * Don't circuitmux_assert_okay_paranoid() here; this gets called when
- * channels are being freed and have already been unregistered, so
- * the channel ID lookups it does will fail.
- */
i = HT_START(chanid_circid_muxinfo_map, cmux->chanid_circid_map);
while (i) {
@@ -435,7 +287,7 @@ circuitmux_detach_all_circuits(circuitmux_t *cmux, smartlist_t *detached_out)
*/
if (to_remove->muxinfo.cell_count > 0) {
- circuitmux_make_circuit_inactive(cmux, circ, CELL_DIRECTION_OUT);
+ circuitmux_make_circuit_inactive(cmux, circ);
}
/* Clear n_mux */
@@ -450,7 +302,7 @@ circuitmux_detach_all_circuits(circuitmux_t *cmux, smartlist_t *detached_out)
*/
if (to_remove->muxinfo.cell_count > 0) {
- circuitmux_make_circuit_inactive(cmux, circ, CELL_DIRECTION_IN);
+ circuitmux_make_circuit_inactive(cmux, circ);
}
/*
@@ -606,9 +458,7 @@ circuitmux_clear_policy(circuitmux_t *cmux)
tor_assert(cmux);
/* Internally, this is just setting policy to NULL */
- if (cmux->policy) {
- circuitmux_set_policy(cmux, NULL);
- }
+ circuitmux_set_policy(cmux, NULL);
}
/**
@@ -944,7 +794,6 @@ circuitmux_attach_circuit,(circuitmux_t *cmux, circuit_t *circ,
tor_assert(circ);
tor_assert(direction == CELL_DIRECTION_IN ||
direction == CELL_DIRECTION_OUT);
- circuitmux_assert_okay_paranoid(cmux);
/*
* Figure out which channel we're using, and get the circuit's current
@@ -1002,10 +851,10 @@ circuitmux_attach_circuit,(circuitmux_t *cmux, circuit_t *circ,
*/
if (hashent->muxinfo.cell_count > 0 && cell_count == 0) {
--(cmux->n_active_circuits);
- circuitmux_make_circuit_inactive(cmux, circ, direction);
+ circuitmux_make_circuit_inactive(cmux, circ);
} else if (hashent->muxinfo.cell_count == 0 && cell_count > 0) {
++(cmux->n_active_circuits);
- circuitmux_make_circuit_active(cmux, circ, direction);
+ circuitmux_make_circuit_active(cmux, circ);
}
cmux->n_cells -= hashent->muxinfo.cell_count;
cmux->n_cells += cell_count;
@@ -1033,7 +882,7 @@ circuitmux_attach_circuit,(circuitmux_t *cmux, circuit_t *circ,
hashent->muxinfo.cell_count = cell_count;
hashent->muxinfo.direction = direction;
/* Allocate policy specific circuit data if we need it */
- if (cmux->policy && cmux->policy->alloc_circ_data) {
+ if (cmux->policy->alloc_circ_data) {
/* Assert that we have the means to free policy-specific data */
tor_assert(cmux->policy->free_circ_data);
/* Allocate it */
@@ -1053,25 +902,14 @@ circuitmux_attach_circuit,(circuitmux_t *cmux, circuit_t *circ,
if (direction == CELL_DIRECTION_OUT) circ->n_mux = cmux;
else TO_OR_CIRCUIT(circ)->p_mux = cmux;
- /* Make sure the next/prev pointers are NULL */
- if (direction == CELL_DIRECTION_OUT) {
- circ->next_active_on_n_chan = NULL;
- circ->prev_active_on_n_chan = NULL;
- } else {
- TO_OR_CIRCUIT(circ)->next_active_on_p_chan = NULL;
- TO_OR_CIRCUIT(circ)->prev_active_on_p_chan = NULL;
- }
-
/* Update counters */
++(cmux->n_circuits);
if (cell_count > 0) {
++(cmux->n_active_circuits);
- circuitmux_make_circuit_active(cmux, circ, direction);
+ circuitmux_make_circuit_active(cmux, circ);
}
cmux->n_cells += cell_count;
}
-
- circuitmux_assert_okay_paranoid(cmux);
}
/**
@@ -1095,7 +933,6 @@ circuitmux_detach_circuit,(circuitmux_t *cmux, circuit_t *circ))
tor_assert(cmux);
tor_assert(cmux->chanid_circid_map);
tor_assert(circ);
- circuitmux_assert_okay_paranoid(cmux);
/* See if we have it for n_chan/n_circ_id */
if (circ->n_chan) {
@@ -1133,7 +970,7 @@ circuitmux_detach_circuit,(circuitmux_t *cmux, circuit_t *circ))
if (hashent->muxinfo.cell_count > 0) {
--(cmux->n_active_circuits);
/* This does policy notifies, so comes before freeing policy data */
- circuitmux_make_circuit_inactive(cmux, circ, last_searched_direction);
+ circuitmux_make_circuit_inactive(cmux, circ);
}
cmux->n_cells -= hashent->muxinfo.cell_count;
@@ -1162,8 +999,6 @@ circuitmux_detach_circuit,(circuitmux_t *cmux, circuit_t *circ))
/* Free the hash entry */
tor_free(hashent);
}
-
- circuitmux_assert_okay_paranoid(cmux);
}
/**
@@ -1172,94 +1007,22 @@ circuitmux_detach_circuit,(circuitmux_t *cmux, circuit_t *circ))
*/
static void
-circuitmux_make_circuit_active(circuitmux_t *cmux, circuit_t *circ,
- cell_direction_t direction)
+circuitmux_make_circuit_active(circuitmux_t *cmux, circuit_t *circ)
{
- circuit_t **next_active = NULL, **prev_active = NULL, **next_prev = NULL;
- circuitmux_t *circuit_cmux = NULL;
- chanid_circid_muxinfo_t *hashent = NULL;
- channel_t *chan = NULL;
- circid_t circ_id;
- int already_active;
-
tor_assert(cmux);
+ tor_assert(cmux->policy);
tor_assert(circ);
- tor_assert(direction == CELL_DIRECTION_OUT ||
- direction == CELL_DIRECTION_IN);
- /*
- * Don't circuitmux_assert_okay_paranoid(cmux) here because the cell count
- * already got changed and we have to update the list for it to be consistent
- * again.
- */
-
- /* Get the right set of active list links for this direction */
- if (direction == CELL_DIRECTION_OUT) {
- next_active = &(circ->next_active_on_n_chan);
- prev_active = &(circ->prev_active_on_n_chan);
- circuit_cmux = circ->n_mux;
- chan = circ->n_chan;
- circ_id = circ->n_circ_id;
- } else {
- next_active = &(TO_OR_CIRCUIT(circ)->next_active_on_p_chan);
- prev_active = &(TO_OR_CIRCUIT(circ)->prev_active_on_p_chan);
- circuit_cmux = TO_OR_CIRCUIT(circ)->p_mux;
- chan = TO_OR_CIRCUIT(circ)->p_chan;
- circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
- }
-
- /* Assert that it is attached to this mux and a channel */
- tor_assert(cmux == circuit_cmux);
- tor_assert(chan != NULL);
-
- /*
- * Check if the circuit really was inactive; if it's active, at least one
- * of the next_active and prev_active pointers will not be NULL, or this
- * circuit will be either the head or tail of the list for this cmux.
- */
- already_active = (*prev_active != NULL || *next_active != NULL ||
- cmux->active_circuits_head == circ ||
- cmux->active_circuits_tail == circ);
-
- /* If we're already active, log a warning and finish */
- if (already_active) {
- log_warn(LD_CIRC,
- "Circuit %u on channel " U64_FORMAT " was already active",
- (unsigned)circ_id, U64_PRINTF_ARG(chan->global_identifier));
- return;
- }
-
- /*
- * This is going at the head of the list; if the old head is not NULL,
- * then its prev pointer should point to this.
- */
- *next_active = cmux->active_circuits_head; /* Next is old head */
- *prev_active = NULL; /* Prev is NULL (this will be the head) */
- if (cmux->active_circuits_head) {
- /* The list had an old head; update its prev pointer */
- next_prev =
- circuitmux_prev_active_circ_p(cmux, cmux->active_circuits_head);
- tor_assert(next_prev);
- *next_prev = circ;
- } else {
- /* The list was empty; this becomes the tail as well */
- cmux->active_circuits_tail = circ;
- }
- /* This becomes the new head of the list */
- cmux->active_circuits_head = circ;
/* Policy-specific notification */
- if (cmux->policy &&
- cmux->policy->notify_circ_active) {
+ if (cmux->policy->notify_circ_active) {
/* Okay, we need to check the circuit for policy data now */
- hashent = circuitmux_find_map_entry(cmux, circ);
+ chanid_circid_muxinfo_t *hashent = circuitmux_find_map_entry(cmux, circ);
/* We should have found something */
tor_assert(hashent);
/* Notify */
cmux->policy->notify_circ_active(cmux, cmux->policy_data,
circ, hashent->muxinfo.policy_data);
}
-
- circuitmux_assert_okay_paranoid(cmux);
}
/**
@@ -1268,112 +1031,22 @@ circuitmux_make_circuit_active(circuitmux_t *cmux, circuit_t *circ,
*/
static void
-circuitmux_make_circuit_inactive(circuitmux_t *cmux, circuit_t *circ,
- cell_direction_t direction)
+circuitmux_make_circuit_inactive(circuitmux_t *cmux, circuit_t *circ)
{
- circuit_t **next_active = NULL, **prev_active = NULL;
- circuit_t **next_prev = NULL, **prev_next = NULL;
- circuitmux_t *circuit_cmux = NULL;
- chanid_circid_muxinfo_t *hashent = NULL;
- channel_t *chan = NULL;
- circid_t circ_id;
- int already_inactive;
-
tor_assert(cmux);
+ tor_assert(cmux->policy);
tor_assert(circ);
- tor_assert(direction == CELL_DIRECTION_OUT ||
- direction == CELL_DIRECTION_IN);
- /*
- * Don't circuitmux_assert_okay_paranoid(cmux) here because the cell count
- * already got changed and we have to update the list for it to be consistent
- * again.
- */
-
- /* Get the right set of active list links for this direction */
- if (direction == CELL_DIRECTION_OUT) {
- next_active = &(circ->next_active_on_n_chan);
- prev_active = &(circ->prev_active_on_n_chan);
- circuit_cmux = circ->n_mux;
- chan = circ->n_chan;
- circ_id = circ->n_circ_id;
- } else {
- next_active = &(TO_OR_CIRCUIT(circ)->next_active_on_p_chan);
- prev_active = &(TO_OR_CIRCUIT(circ)->prev_active_on_p_chan);
- circuit_cmux = TO_OR_CIRCUIT(circ)->p_mux;
- chan = TO_OR_CIRCUIT(circ)->p_chan;
- circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
- }
-
- /* Assert that it is attached to this mux and a channel */
- tor_assert(cmux == circuit_cmux);
- tor_assert(chan != NULL);
-
- /*
- * Check if the circuit really was active; if it's inactive, the
- * next_active and prev_active pointers will be NULL and this circuit
- * will not be the head or tail of the list for this cmux.
- */
- already_inactive = (*prev_active == NULL && *next_active == NULL &&
- cmux->active_circuits_head != circ &&
- cmux->active_circuits_tail != circ);
-
- /* If we're already inactive, log a warning and finish */
- if (already_inactive) {
- log_warn(LD_CIRC,
- "Circuit %d on channel " U64_FORMAT " was already inactive",
- (unsigned)circ_id, U64_PRINTF_ARG(chan->global_identifier));
- return;
- }
-
- /* Remove from the list; first get next_prev and prev_next */
- if (*next_active) {
- /*
- * If there's a next circuit, its previous circuit becomes this
- * circuit's previous circuit.
- */
- next_prev = circuitmux_prev_active_circ_p(cmux, *next_active);
- } else {
- /* Else, the tail becomes this circuit's previous circuit */
- next_prev = &(cmux->active_circuits_tail);
- }
-
- /* Got next_prev, now prev_next */
- if (*prev_active) {
- /*
- * If there's a previous circuit, its next circuit becomes this circuit's
- * next circuit.
- */
- prev_next = circuitmux_next_active_circ_p(cmux, *prev_active);
- } else {
- /* Else, the head becomes this circuit's next circuit */
- prev_next = &(cmux->active_circuits_head);
- }
-
- /* Assert that we got sensible values for the next/prev pointers */
- tor_assert(next_prev != NULL);
- tor_assert(prev_next != NULL);
-
- /* Update the next/prev pointers - this removes circ from the list */
- *next_prev = *prev_active;
- *prev_next = *next_active;
-
- /* Now null out prev_active/next_active */
- *prev_active = NULL;
- *next_active = NULL;
/* Policy-specific notification */
- if (cmux->policy &&
- cmux->policy->notify_circ_inactive) {
+ if (cmux->policy->notify_circ_inactive) {
/* Okay, we need to check the circuit for policy data now */
- hashent = circuitmux_find_map_entry(cmux, circ);
+ chanid_circid_muxinfo_t *hashent = circuitmux_find_map_entry(cmux, circ);
/* We should have found something */
tor_assert(hashent);
/* Notify */
cmux->policy->notify_circ_inactive(cmux, cmux->policy_data,
circ, hashent->muxinfo.policy_data);
}
-
- circuitmux_assert_okay_paranoid(cmux);
}
/**
@@ -1400,8 +1073,6 @@ circuitmux_set_num_cells(circuitmux_t *cmux, circuit_t *circ,
tor_assert(cmux);
tor_assert(circ);
- circuitmux_assert_okay_paranoid(cmux);
-
/* Search for this circuit's entry */
hashent = circuitmux_find_map_entry(cmux, circ);
/* Assert that we found one */
@@ -1412,7 +1083,7 @@ circuitmux_set_num_cells(circuitmux_t *cmux, circuit_t *circ,
cmux->n_cells += n_cells;
/* Do we need to notify a cmux policy? */
- if (cmux->policy && cmux->policy->notify_set_n_cells) {
+ if (cmux->policy->notify_set_n_cells) {
/* Call notify_set_n_cells */
cmux->policy->notify_set_n_cells(cmux,
cmux->policy_data,
@@ -1428,21 +1099,15 @@ circuitmux_set_num_cells(circuitmux_t *cmux, circuit_t *circ,
if (hashent->muxinfo.cell_count > 0 && n_cells == 0) {
--(cmux->n_active_circuits);
hashent->muxinfo.cell_count = n_cells;
- circuitmux_make_circuit_inactive(cmux, circ, hashent->muxinfo.direction);
+ circuitmux_make_circuit_inactive(cmux, circ);
/* Is the old cell count == 0 and the new cell count > 0 ? */
} else if (hashent->muxinfo.cell_count == 0 && n_cells > 0) {
++(cmux->n_active_circuits);
hashent->muxinfo.cell_count = n_cells;
- circuitmux_make_circuit_active(cmux, circ, hashent->muxinfo.direction);
+ circuitmux_make_circuit_active(cmux, circ);
} else {
- /*
- * Update the entry cell count like this so we can put a
- * circuitmux_assert_okay_paranoid inside make_circuit_(in)active() too.
- */
hashent->muxinfo.cell_count = n_cells;
}
-
- circuitmux_assert_okay_paranoid(cmux);
}
/*
@@ -1468,6 +1133,9 @@ circuitmux_get_first_active_circuit(circuitmux_t *cmux,
circuit_t *circ = NULL;
tor_assert(cmux);
+ tor_assert(cmux->policy);
+ /* This callback is mandatory. */
+ tor_assert(cmux->policy->pick_active_circuit);
tor_assert(destroy_queue_out);
*destroy_queue_out = NULL;
@@ -1486,14 +1154,7 @@ circuitmux_get_first_active_circuit(circuitmux_t *cmux,
/* We also must have a cell available for this to be the case */
tor_assert(cmux->n_cells > 0);
/* Do we have a policy-provided circuit selector? */
- if (cmux->policy && cmux->policy->pick_active_circuit) {
- circ = cmux->policy->pick_active_circuit(cmux, cmux->policy_data);
- }
- /* Fall back on the head of the active circuits list */
- if (!circ) {
- tor_assert(cmux->active_circuits_head);
- circ = cmux->active_circuits_head;
- }
+ circ = cmux->policy->pick_active_circuit(cmux, cmux->policy_data);
cmux->last_cell_was_destroy = 0;
} else {
tor_assert(cmux->n_cells == 0);
@@ -1517,7 +1178,6 @@ circuitmux_notify_xmit_cells(circuitmux_t *cmux, circuit_t *circ,
tor_assert(cmux);
tor_assert(circ);
- circuitmux_assert_okay_paranoid(cmux);
if (n_cells == 0) return;
@@ -1544,17 +1204,11 @@ circuitmux_notify_xmit_cells(circuitmux_t *cmux, circuit_t *circ,
/* Adjust the mux cell counter */
cmux->n_cells -= n_cells;
- /* If we aren't making it inactive later, move it to the tail of the list */
- if (!becomes_inactive) {
- circuitmux_move_active_circ_to_tail(cmux, circ,
- hashent->muxinfo.direction);
- }
-
/*
* We call notify_xmit_cells() before making the circuit inactive if needed,
* so the policy can always count on this coming in on an active circuit.
*/
- if (cmux->policy && cmux->policy->notify_xmit_cells) {
+ if (cmux->policy->notify_xmit_cells) {
cmux->policy->notify_xmit_cells(cmux, cmux->policy_data, circ,
hashent->muxinfo.policy_data,
n_cells);
@@ -1566,10 +1220,8 @@ circuitmux_notify_xmit_cells(circuitmux_t *cmux, circuit_t *circ,
*/
if (becomes_inactive) {
--(cmux->n_active_circuits);
- circuitmux_make_circuit_inactive(cmux, circ, hashent->muxinfo.direction);
+ circuitmux_make_circuit_inactive(cmux, circ);
}
-
- circuitmux_assert_okay_paranoid(cmux);
}
/**
@@ -1592,282 +1244,6 @@ circuitmux_notify_xmit_destroy(circuitmux_t *cmux)
I64_PRINTF_ARG(global_destroy_ctr));
}
-/*
- * Circuitmux consistency checking assertions
- */
-
-/**
- * Check that circuitmux data structures are consistent and fail with an
- * assert if not.
- */
-
-void
-circuitmux_assert_okay(circuitmux_t *cmux)
-{
- tor_assert(cmux);
-
- /*
- * Pass 1: iterate the hash table; for each entry:
- * a) Check that the circuit has this cmux for n_mux or p_mux
- * b) If the cell_count is > 0, set the mark bit; otherwise clear it
- * c) Also check activeness (cell_count > 0 should be active)
- * d) Count the number of circuits, active circuits and queued cells
- * and at the end check that they match the counters in the cmux.
- *
- * Pass 2: iterate the active circuits list; for each entry,
- * make sure the circuit is attached to this mux and appears
- * in the hash table. Make sure the mark bit is 1, and clear
- * it in the hash table entry. Consistency-check the linked
- * list pointers.
- *
- * Pass 3: iterate the hash table again; assert if any active circuits
- * (mark bit set to 1) are discovered that weren't cleared in pass 2
- * (don't appear in the linked list).
- */
-
- circuitmux_assert_okay_pass_one(cmux);
- circuitmux_assert_okay_pass_two(cmux);
- circuitmux_assert_okay_pass_three(cmux);
-}
-
-/**
- * Do the first pass of circuitmux_assert_okay(); see the comment in that
- * function.
- */
-
-static void
-circuitmux_assert_okay_pass_one(circuitmux_t *cmux)
-{
- chanid_circid_muxinfo_t **i = NULL;
- uint64_t chan_id;
- channel_t *chan;
- circid_t circ_id;
- circuit_t *circ;
- or_circuit_t *or_circ;
- circuit_t **next_p, **prev_p;
- unsigned int n_circuits, n_active_circuits, n_cells;
-
- tor_assert(cmux);
- tor_assert(cmux->chanid_circid_map);
-
- /* Reset the counters */
- n_circuits = n_active_circuits = n_cells = 0;
- /* Start iterating the hash table */
- i = HT_START(chanid_circid_muxinfo_map, cmux->chanid_circid_map);
- while (i) {
- /* Assert that the hash table entry isn't null */
- tor_assert(*i);
-
- /* Get the channel and circuit id */
- chan_id = (*i)->chan_id;
- circ_id = (*i)->circ_id;
-
- /* Find the channel and circuit, assert that they exist */
- chan = channel_find_by_global_id(chan_id);
- tor_assert(chan);
- circ = circuit_get_by_circid_channel_even_if_marked(circ_id, chan);
- tor_assert(circ);
-
- /* Assert that we know which direction this is going */
- tor_assert((*i)->muxinfo.direction == CELL_DIRECTION_OUT ||
- (*i)->muxinfo.direction == CELL_DIRECTION_IN);
-
- if ((*i)->muxinfo.direction == CELL_DIRECTION_OUT) {
- /* We should be n_mux on this circuit */
- tor_assert(cmux == circ->n_mux);
- tor_assert(chan == circ->n_chan);
- /* Get next and prev for next test */
- next_p = &(circ->next_active_on_n_chan);
- prev_p = &(circ->prev_active_on_n_chan);
- } else {
- /* This should be an or_circuit_t and we should be p_mux */
- or_circ = TO_OR_CIRCUIT(circ);
- tor_assert(cmux == or_circ->p_mux);
- tor_assert(chan == or_circ->p_chan);
- /* Get next and prev for next test */
- next_p = &(or_circ->next_active_on_p_chan);
- prev_p = &(or_circ->prev_active_on_p_chan);
- }
-
- /*
- * Should this circuit be active? I.e., does the mux know about > 0
- * cells on it?
- */
- const int circ_is_active = ((*i)->muxinfo.cell_count > 0);
-
- /* It should be in the linked list iff it's active */
- if (circ_is_active) {
- /* Either we have a next link or we are the tail */
- tor_assert(*next_p || (circ == cmux->active_circuits_tail));
- /* Either we have a prev link or we are the head */
- tor_assert(*prev_p || (circ == cmux->active_circuits_head));
- /* Increment the active circuits counter */
- ++n_active_circuits;
- } else {
- /* Shouldn't be in list, so no next or prev link */
- tor_assert(!(*next_p));
- tor_assert(!(*prev_p));
- /* And can't be head or tail */
- tor_assert(circ != cmux->active_circuits_head);
- tor_assert(circ != cmux->active_circuits_tail);
- }
-
- /* Increment the circuits counter */
- ++n_circuits;
- /* Adjust the cell counter */
- n_cells += (*i)->muxinfo.cell_count;
-
- /* Set the mark bit to circ_is_active */
- (*i)->muxinfo.mark = circ_is_active;
-
- /* Advance to the next entry */
- i = HT_NEXT(chanid_circid_muxinfo_map, cmux->chanid_circid_map, i);
- }
-
- /* Now check the counters */
- tor_assert(n_cells == cmux->n_cells);
- tor_assert(n_circuits == cmux->n_circuits);
- tor_assert(n_active_circuits == cmux->n_active_circuits);
-}
-
-/**
- * Do the second pass of circuitmux_assert_okay(); see the comment in that
- * function.
- */
-
-static void
-circuitmux_assert_okay_pass_two(circuitmux_t *cmux)
-{
- circuit_t *curr_circ, *prev_circ = NULL, *next_circ;
- or_circuit_t *curr_or_circ;
- uint64_t curr_chan_id;
- circid_t curr_circ_id;
- circuit_t **next_p, **prev_p;
- channel_t *chan;
- unsigned int n_active_circuits = 0;
- chanid_circid_muxinfo_t search, *hashent = NULL;
-
- tor_assert(cmux);
- tor_assert(cmux->chanid_circid_map);
-
- /*
- * Walk the linked list of active circuits in cmux; keep track of the
- * previous circuit seen for consistency checking purposes. Count them
- * to make sure the number in the linked list matches
- * cmux->n_active_circuits.
- */
- curr_circ = cmux->active_circuits_head;
- while (curr_circ) {
- /* Reset some things */
- chan = NULL;
- curr_or_circ = NULL;
- next_circ = NULL;
- next_p = prev_p = NULL;
- cell_direction_t direction;
-
- /* Figure out if this is n_mux or p_mux */
- if (cmux == curr_circ->n_mux) {
- /* Get next_p and prev_p */
- next_p = &(curr_circ->next_active_on_n_chan);
- prev_p = &(curr_circ->prev_active_on_n_chan);
- /* Get the channel */
- chan = curr_circ->n_chan;
- /* Get the circuit id */
- curr_circ_id = curr_circ->n_circ_id;
- /* Remember the direction */
- direction = CELL_DIRECTION_OUT;
- } else {
- /* We must be p_mux and this must be an or_circuit_t */
- curr_or_circ = TO_OR_CIRCUIT(curr_circ);
- tor_assert(cmux == curr_or_circ->p_mux);
- /* Get next_p and prev_p */
- next_p = &(curr_or_circ->next_active_on_p_chan);
- prev_p = &(curr_or_circ->prev_active_on_p_chan);
- /* Get the channel */
- chan = curr_or_circ->p_chan;
- /* Get the circuit id */
- curr_circ_id = curr_or_circ->p_circ_id;
- /* Remember the direction */
- direction = CELL_DIRECTION_IN;
- }
-
- /* Assert that we got a channel and get the channel ID */
- tor_assert(chan);
- curr_chan_id = chan->global_identifier;
-
- /* Assert that prev_p points to last circuit we saw */
- tor_assert(*prev_p == prev_circ);
- /* If that's NULL, assert that we are the head */
- if (!(*prev_p)) tor_assert(curr_circ == cmux->active_circuits_head);
-
- /* Get the next circuit */
- next_circ = *next_p;
- /* If it's NULL, assert that we are the tail */
- if (!(*next_p)) tor_assert(curr_circ == cmux->active_circuits_tail);
-
- /* Now find the hash table entry for this circuit */
- search.chan_id = curr_chan_id;
- search.circ_id = curr_circ_id;
- hashent = HT_FIND(chanid_circid_muxinfo_map, cmux->chanid_circid_map,
- &search);
-
- /* Assert that we have one */
- tor_assert(hashent);
-
- /* Assert that the direction matches */
- tor_assert(direction == hashent->muxinfo.direction);
-
- /* Assert that the hash entry got marked in pass one */
- tor_assert(hashent->muxinfo.mark);
-
- /* Clear the mark */
- hashent->muxinfo.mark = 0;
-
- /* Increment the counter */
- ++n_active_circuits;
-
- /* Advance to the next active circuit and update prev_circ */
- prev_circ = curr_circ;
- curr_circ = next_circ;
- }
-
- /* Assert that the counter matches the cmux */
- tor_assert(n_active_circuits == cmux->n_active_circuits);
-}
-
-/**
- * Do the third pass of circuitmux_assert_okay(); see the comment in that
- * function.
- */
-
-static void
-circuitmux_assert_okay_pass_three(circuitmux_t *cmux)
-{
- chanid_circid_muxinfo_t **i = NULL;
-
- tor_assert(cmux);
- tor_assert(cmux->chanid_circid_map);
-
- /* Start iterating the hash table */
- i = HT_START(chanid_circid_muxinfo_map, cmux->chanid_circid_map);
-
- /* Advance through each entry */
- while (i) {
- /* Assert that it isn't null */
- tor_assert(*i);
-
- /*
- * Assert that this entry is not marked - i.e., that either we didn't
- * think it should be active in pass one or we saw it in the active
- * circuits linked list.
- */
- tor_assert(!((*i)->muxinfo.mark));
-
- /* Advance to the next entry */
- i = HT_NEXT(chanid_circid_muxinfo_map, cmux->chanid_circid_map, i);
- }
-}
-
/*DOCDOC */
void
circuitmux_append_destroy_cell(channel_t *chan,
diff --git a/src/or/circuitmux_ewma.c b/src/or/circuitmux_ewma.c
index fde2d22a89..b2ace8a9fa 100644
--- a/src/or/circuitmux_ewma.c
+++ b/src/or/circuitmux_ewma.c
@@ -223,8 +223,6 @@ ewma_cmp_cmux(circuitmux_t *cmux_1, circuitmux_policy_data_t *pol_data_1,
* has value ewma_scale_factor ** N.)
*/
static double ewma_scale_factor = 0.1;
-/* DOCDOC ewma_enabled */
-static int ewma_enabled = 0;
/*** EWMA circuitmux_policy_t method table ***/
@@ -243,6 +241,13 @@ circuitmux_policy_t ewma_policy = {
/*** EWMA method implementations using the below EWMA helper functions ***/
+/** Compute and return the current cell_ewma tick. */
+static inline unsigned int
+cell_ewma_get_tick(void)
+{
+ return ((unsigned)approx_time() / EWMA_TICK_LEN);
+}
+
/**
* Allocate an ewma_policy_data_t and upcast it to a circuitmux_policy_data_t;
* this is called when setting the policy on a circuitmux_t to ewma_policy.
@@ -612,59 +617,79 @@ cell_ewma_tick_from_timeval(const struct timeval *now,
return res;
}
-/** Tell the caller whether ewma_enabled is set */
-int
-cell_ewma_enabled(void)
+/* Default value for the CircuitPriorityHalflifeMsec consensus parameter in
+ * msec. */
+#define CMUX_PRIORITY_HALFLIFE_MSEC_DEFAULT 30000
+/* Minimum and maximum value for the CircuitPriorityHalflifeMsec consensus
+ * parameter. */
+#define CMUX_PRIORITY_HALFLIFE_MSEC_MIN 1
+#define CMUX_PRIORITY_HALFLIFE_MSEC_MAX INT32_MAX
+
+/* Return the value of the circuit priority halflife from the options if
+ * available or else from the consensus (in that order). If none can be found,
+ * a default value is returned.
+ *
+ * The source_msg points to a string describing from where the value was
+ * picked so it can be used for logging. */
+static double
+get_circuit_priority_halflife(const or_options_t *options,
+ const networkstatus_t *consensus,
+ const char **source_msg)
{
- return ewma_enabled;
-}
+ int32_t halflife_ms;
+ double halflife;
+ /* Compute the default value now. We might need it. */
+ double halflife_default =
+ ((double) CMUX_PRIORITY_HALFLIFE_MSEC_DEFAULT) / 1000.0;
-/** Compute and return the current cell_ewma tick. */
-unsigned int
-cell_ewma_get_tick(void)
-{
- return ((unsigned)approx_time() / EWMA_TICK_LEN);
+ /* Try to get it from configuration file first. */
+ if (options && options->CircuitPriorityHalflife < EPSILON) {
+ halflife = options->CircuitPriorityHalflife;
+ *source_msg = "CircuitPriorityHalflife in configuration";
+ goto end;
+ }
+
+ /* Try to get the msec value from the consensus. */
+ halflife_ms = networkstatus_get_param(consensus,
+ "CircuitPriorityHalflifeMsec",
+ CMUX_PRIORITY_HALFLIFE_MSEC_DEFAULT,
+ CMUX_PRIORITY_HALFLIFE_MSEC_MIN,
+ CMUX_PRIORITY_HALFLIFE_MSEC_MAX);
+ halflife = ((double) halflife_ms) / 1000.0;
+ *source_msg = "CircuitPriorityHalflifeMsec in consensus";
+
+ end:
+ /* We should never go below the EPSILON else we would consider it disabled
+ * and we can't have that. */
+ if (halflife < EPSILON) {
+ log_warn(LD_CONFIG, "CircuitPriorityHalflife is too small (%f). "
+ "Adjusting to the smallest value allowed: %f.",
+ halflife, halflife_default);
+ halflife = halflife_default;
+ }
+ return halflife;
}
/** Adjust the global cell scale factor based on <b>options</b> */
void
-cell_ewma_set_scale_factor(const or_options_t *options,
- const networkstatus_t *consensus)
+cmux_ewma_set_options(const or_options_t *options,
+ const networkstatus_t *consensus)
{
- int32_t halflife_ms;
double halflife;
const char *source;
- if (options && options->CircuitPriorityHalflife >= -EPSILON) {
- halflife = options->CircuitPriorityHalflife;
- source = "CircuitPriorityHalflife in configuration";
- } else if (consensus && (halflife_ms = networkstatus_get_param(
- consensus, "CircuitPriorityHalflifeMsec",
- -1, -1, INT32_MAX)) >= 0) {
- halflife = ((double)halflife_ms)/1000.0;
- source = "CircuitPriorityHalflifeMsec in consensus";
- } else {
- halflife = EWMA_DEFAULT_HALFLIFE;
- source = "Default value";
- }
- if (halflife <= EPSILON) {
- /* The cell EWMA algorithm is disabled. */
- ewma_scale_factor = 0.1;
- ewma_enabled = 0;
- log_info(LD_OR,
- "Disabled cell_ewma algorithm because of value in %s",
- source);
- } else {
- /* convert halflife into halflife-per-tick. */
- halflife /= EWMA_TICK_LEN;
- /* compute per-tick scale factor. */
- ewma_scale_factor = exp( LOG_ONEHALF / halflife );
- ewma_enabled = 1;
- log_info(LD_OR,
- "Enabled cell_ewma algorithm because of value in %s; "
- "scale factor is %f per %d seconds",
- source, ewma_scale_factor, EWMA_TICK_LEN);
- }
+ /* Both options and consensus can be NULL. This assures us to either get a
+ * valid configured value or the default one. */
+ halflife = get_circuit_priority_halflife(options, consensus, &source);
+
+ /* convert halflife into halflife-per-tick. */
+ halflife /= EWMA_TICK_LEN;
+ /* compute per-tick scale factor. */
+ ewma_scale_factor = exp( LOG_ONEHALF / halflife );
+ log_info(LD_OR,
+ "Enabled cell_ewma algorithm because of value in %s; "
+ "scale factor is %f per %d seconds",
+ source, ewma_scale_factor, EWMA_TICK_LEN);
}
/** Return the multiplier necessary to convert the value of a cell sent in
diff --git a/src/or/circuitmux_ewma.h b/src/or/circuitmux_ewma.h
index 8f4e57865e..2ef8c2586d 100644
--- a/src/or/circuitmux_ewma.h
+++ b/src/or/circuitmux_ewma.h
@@ -12,13 +12,12 @@
#include "or.h"
#include "circuitmux.h"
+/* The public EWMA policy callbacks object. */
extern circuitmux_policy_t ewma_policy;
/* Externally visible EWMA functions */
-int cell_ewma_enabled(void);
-unsigned int cell_ewma_get_tick(void);
-void cell_ewma_set_scale_factor(const or_options_t *options,
- const networkstatus_t *consensus);
+void cmux_ewma_set_options(const or_options_t *options,
+ const networkstatus_t *consensus);
#endif /* !defined(TOR_CIRCUITMUX_EWMA_H) */
diff --git a/src/or/command.c b/src/or/command.c
index 7280be1396..4f99462f38 100644
--- a/src/or/command.c
+++ b/src/or/command.c
@@ -339,7 +339,9 @@ command_process_create_cell(cell_t *cell, channel_t *chan)
return;
}
- if (connection_or_digest_is_known_relay(chan->identity_digest)) {
+ if (!channel_is_client(chan)) {
+ /* remember create types we've seen, but don't remember them from
+ * clients, to be extra conservative about client statistics. */
rep_hist_note_circuit_handshake_requested(create_cell->handshake_type);
}
diff --git a/src/or/config.c b/src/or/config.c
index d76a53a375..9cd66cbf63 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -264,7 +264,7 @@ static config_var_t option_vars_[] = {
OBSOLETE("CircuitIdleTimeout"),
V(CircuitsAvailableTimeout, INTERVAL, "0"),
V(CircuitStreamTimeout, INTERVAL, "0"),
- V(CircuitPriorityHalflife, DOUBLE, "-100.0"), /*negative:'Use default'*/
+ V(CircuitPriorityHalflife, DOUBLE, "-1.0"), /*negative:'Use default'*/
V(ClientDNSRejectInternalAddresses, BOOL,"1"),
V(ClientOnly, BOOL, "0"),
V(ClientPreferIPv6ORPort, AUTOBOOL, "auto"),
@@ -492,8 +492,8 @@ static config_var_t option_vars_[] = {
V(TestingSigningKeySlop, INTERVAL, "1 day"),
V(OptimisticData, AUTOBOOL, "auto"),
- V(PortForwarding, BOOL, "0"),
- V(PortForwardingHelper, FILENAME, "tor-fw-helper"),
+ OBSOLETE("PortForwarding"),
+ OBSOLETE("PortForwardingHelper"),
OBSOLETE("PreferTunneledDirConns"),
V(ProtocolWarnings, BOOL, "0"),
V(PublishServerDescriptor, CSV, "1"),
@@ -645,15 +645,12 @@ static config_var_t option_vars_[] = {
"0, 30, 90, 600, 3600, 10800, 25200, 54000, 111600, 262800"),
V(TestingClientMaxIntervalWithoutRequest, INTERVAL, "10 minutes"),
V(TestingDirConnectionMaxStall, INTERVAL, "5 minutes"),
- V(TestingConsensusMaxDownloadTries, UINT, "8"),
- /* Since we try connections rapidly and simultaneously, we can afford
- * to give up earlier. (This protects against overloading directories.) */
- V(ClientBootstrapConsensusMaxDownloadTries, UINT, "7"),
- /* We want to give up much earlier if we're only using authorities. */
- V(ClientBootstrapConsensusAuthorityOnlyMaxDownloadTries, UINT, "4"),
- V(TestingDescriptorMaxDownloadTries, UINT, "8"),
- V(TestingMicrodescMaxDownloadTries, UINT, "8"),
- V(TestingCertMaxDownloadTries, UINT, "8"),
+ OBSOLETE("TestingConsensusMaxDownloadTries"),
+ OBSOLETE("ClientBootstrapConsensusMaxDownloadTries"),
+ OBSOLETE("ClientBootstrapConsensusAuthorityOnlyMaxDownloadTries"),
+ OBSOLETE("TestingDescriptorMaxDownloadTries"),
+ OBSOLETE("TestingMicrodescMaxDownloadTries"),
+ OBSOLETE("TestingCertMaxDownloadTries"),
V(TestingDirAuthVoteExit, ROUTERSET, NULL),
V(TestingDirAuthVoteExitIsStrict, BOOL, "0"),
V(TestingDirAuthVoteGuard, ROUTERSET, NULL),
@@ -678,8 +675,6 @@ static const config_var_t testing_tor_network_defaults[] = {
"0, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 16, 32, 60"),
V(ClientBootstrapConsensusAuthorityOnlyDownloadSchedule, CSV_INTERVAL,
"0, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 16, 32, 60"),
- V(ClientBootstrapConsensusMaxDownloadTries, UINT, "80"),
- V(ClientBootstrapConsensusAuthorityOnlyMaxDownloadTries, UINT, "80"),
V(ClientDNSRejectInternalAddresses, BOOL,"0"),
V(ClientRejectInternalAddresses, BOOL, "0"),
V(CountPrivateBandwidth, BOOL, "1"),
@@ -707,10 +702,6 @@ static const config_var_t testing_tor_network_defaults[] = {
"15, 20, 30, 60"),
V(TestingClientMaxIntervalWithoutRequest, INTERVAL, "5 seconds"),
V(TestingDirConnectionMaxStall, INTERVAL, "30 seconds"),
- V(TestingConsensusMaxDownloadTries, UINT, "80"),
- V(TestingDescriptorMaxDownloadTries, UINT, "80"),
- V(TestingMicrodescMaxDownloadTries, UINT, "80"),
- V(TestingCertMaxDownloadTries, UINT, "80"),
V(TestingEnableConnBwEvent, BOOL, "1"),
V(TestingEnableCellStatsEvent, BOOL, "1"),
V(TestingEnableTbEmptyEvent, BOOL, "1"),
@@ -1128,39 +1119,7 @@ cleanup_protocol_warning_severity_level(void)
/** List of default directory authorities */
static const char *default_authorities[] = {
- "moria1 orport=9101 "
- "v3ident=D586D18309DED4CD6D57C18FDB97EFA96D330566 "
- "128.31.0.39:9131 9695 DFC3 5FFE B861 329B 9F1A B04C 4639 7020 CE31",
- "tor26 orport=443 "
- "v3ident=14C131DFC5C6F93646BE72FA1401C02A8DF2E8B4 "
- "ipv6=[2001:858:2:2:aabb:0:563b:1526]:443 "
- "86.59.21.38:80 847B 1F85 0344 D787 6491 A548 92F9 0493 4E4E B85D",
- "dizum orport=443 "
- "v3ident=E8A9C45EDE6D711294FADF8E7951F4DE6CA56B58 "
- "194.109.206.212:80 7EA6 EAD6 FD83 083C 538F 4403 8BBF A077 587D D755",
- "Bifroest orport=443 bridge "
- "37.218.247.217:80 1D8F 3A91 C37C 5D1C 4C19 B1AD 1D0C FBE8 BF72 D8E1",
- "gabelmoo orport=443 "
- "v3ident=ED03BB616EB2F60BEC80151114BB25CEF515B226 "
- "ipv6=[2001:638:a000:4140::ffff:189]:443 "
- "131.188.40.189:80 F204 4413 DAC2 E02E 3D6B CF47 35A1 9BCA 1DE9 7281",
- "dannenberg orport=443 "
- "v3ident=0232AF901C31A04EE9848595AF9BB7620D4C5B2E "
- "193.23.244.244:80 7BE6 83E6 5D48 1413 21C5 ED92 F075 C553 64AC 7123",
- "maatuska orport=80 "
- "v3ident=49015F787433103580E3B66A1707A00E60F2D15B "
- "ipv6=[2001:67c:289c::9]:80 "
- "171.25.193.9:443 BD6A 8292 55CB 08E6 6FBE 7D37 4836 3586 E46B 3810",
- "Faravahar orport=443 "
- "v3ident=EFCBE720AB3A82B99F9E953CD5BF50F7EEFC7B97 "
- "154.35.175.225:80 CF6D 0AAF B385 BE71 B8E1 11FC 5CFF 4B47 9237 33BC",
- "longclaw orport=443 "
- "v3ident=23D15D965BC35114467363C165C4F724B64B4F66 "
- "199.58.81.140:80 74A9 1064 6BCE EFBC D2E8 74FC 1DC9 9743 0F96 8145",
- "bastet orport=443 "
- "v3ident=27102BC123E7AF1D4741AE047E160C91ADC76B21 "
- "ipv6=[2620:13:4000:6000::1000:118]:443 "
- "204.13.164.118:80 24E2 F139 121D 4394 C54B 5BCC 368B 3B41 1857 C413",
+#include "auth_dirs.inc"
NULL
};
@@ -1691,8 +1650,7 @@ options_act_reversible(const or_options_t *old_options, char **msg)
int
options_need_geoip_info(const or_options_t *options, const char **reason_out)
{
- int bridge_usage =
- options->BridgeRelay && options->BridgeRecordUsageByCountry;
+ int bridge_usage = should_record_bridge_info(options);
int routerset_usage =
routerset_needs_geoip(options->EntryNodes) ||
routerset_needs_geoip(options->ExitNodes) ||
@@ -1800,7 +1758,6 @@ options_act(const or_options_t *old_options)
char *msg=NULL;
const int transition_affects_workers =
old_options && options_transition_affects_workers(old_options, options);
- int old_ewma_enabled;
const int transition_affects_guards =
old_options && options_transition_affects_guards(old_options, options);
@@ -2074,16 +2031,8 @@ options_act(const or_options_t *old_options)
if (accounting_is_enabled(options))
configure_accounting(time(NULL));
- old_ewma_enabled = cell_ewma_enabled();
/* Change the cell EWMA settings */
- cell_ewma_set_scale_factor(options, networkstatus_get_latest_consensus());
- /* If we just enabled ewma, set the cmux policy on all active channels */
- if (cell_ewma_enabled() && !old_ewma_enabled) {
- channel_set_cmux_policy_everywhere(&ewma_policy);
- } else if (!cell_ewma_enabled() && old_ewma_enabled) {
- /* Turn it off everywhere */
- channel_set_cmux_policy_everywhere(NULL);
- }
+ cmux_ewma_set_options(options, networkstatus_get_latest_consensus());
/* Update the BridgePassword's hashed version as needed. We store this as a
* digest so that we can do side-channel-proof comparisons on it.
@@ -2288,6 +2237,11 @@ options_act(const or_options_t *old_options)
}
if ((!old_options || !old_options->EntryStatistics) &&
options->EntryStatistics && !should_record_bridge_info(options)) {
+ /* If we get here, we've started recording bridge info when we didn't
+ * do so before. Note that "should_record_bridge_info()" will
+ * always be false at this point, because of the earlier block
+ * that cleared EntryStatistics when public_server_mode() was false.
+ * We're leaving it in as defensive programming. */
if (geoip_is_loaded(AF_INET) || geoip_is_loaded(AF_INET6)) {
geoip_entry_stats_init(now);
print_notice = 1;
@@ -3925,15 +3879,6 @@ options_validate(or_options_t *old_options, or_options_t *options,
if (options->KeepalivePeriod < 1)
REJECT("KeepalivePeriod option must be positive.");
- if (options->PortForwarding && options->Sandbox) {
- REJECT("PortForwarding is not compatible with Sandbox; at most one can "
- "be set");
- }
- if (options->PortForwarding && options->NoExec) {
- COMPLAIN("Both PortForwarding and NoExec are set; PortForwarding will "
- "be ignored.");
- }
-
if (ensure_bandwidth_cap(&options->BandwidthRate,
"BandwidthRate", msg) < 0)
return -1;
@@ -4418,10 +4363,6 @@ options_validate(or_options_t *old_options, or_options_t *options,
CHECK_DEFAULT(TestingBridgeBootstrapDownloadSchedule);
CHECK_DEFAULT(TestingClientMaxIntervalWithoutRequest);
CHECK_DEFAULT(TestingDirConnectionMaxStall);
- CHECK_DEFAULT(TestingConsensusMaxDownloadTries);
- CHECK_DEFAULT(TestingDescriptorMaxDownloadTries);
- CHECK_DEFAULT(TestingMicrodescMaxDownloadTries);
- CHECK_DEFAULT(TestingCertMaxDownloadTries);
CHECK_DEFAULT(TestingAuthKeyLifetime);
CHECK_DEFAULT(TestingLinkCertLifetime);
CHECK_DEFAULT(TestingSigningKeySlop);
@@ -4496,33 +4437,6 @@ options_validate(or_options_t *old_options, or_options_t *options,
COMPLAIN("TestingDirConnectionMaxStall is insanely high.");
}
- if (options->TestingConsensusMaxDownloadTries < 2) {
- REJECT("TestingConsensusMaxDownloadTries must be greater than 2.");
- } else if (options->TestingConsensusMaxDownloadTries > 800) {
- COMPLAIN("TestingConsensusMaxDownloadTries is insanely high.");
- }
-
- if (options->ClientBootstrapConsensusMaxDownloadTries < 2) {
- REJECT("ClientBootstrapConsensusMaxDownloadTries must be greater "
- "than 2."
- );
- } else if (options->ClientBootstrapConsensusMaxDownloadTries > 800) {
- COMPLAIN("ClientBootstrapConsensusMaxDownloadTries is insanely "
- "high.");
- }
-
- if (options->ClientBootstrapConsensusAuthorityOnlyMaxDownloadTries
- < 2) {
- REJECT("ClientBootstrapConsensusAuthorityOnlyMaxDownloadTries must "
- "be greater than 2."
- );
- } else if (
- options->ClientBootstrapConsensusAuthorityOnlyMaxDownloadTries
- > 800) {
- COMPLAIN("ClientBootstrapConsensusAuthorityOnlyMaxDownloadTries is "
- "insanely high.");
- }
-
if (options->ClientBootstrapConsensusMaxInProgressTries < 1) {
REJECT("ClientBootstrapConsensusMaxInProgressTries must be greater "
"than 0.");
@@ -4532,24 +4446,6 @@ options_validate(or_options_t *old_options, or_options_t *options,
"high.");
}
- if (options->TestingDescriptorMaxDownloadTries < 2) {
- REJECT("TestingDescriptorMaxDownloadTries must be greater than 1.");
- } else if (options->TestingDescriptorMaxDownloadTries > 800) {
- COMPLAIN("TestingDescriptorMaxDownloadTries is insanely high.");
- }
-
- if (options->TestingMicrodescMaxDownloadTries < 2) {
- REJECT("TestingMicrodescMaxDownloadTries must be greater than 1.");
- } else if (options->TestingMicrodescMaxDownloadTries > 800) {
- COMPLAIN("TestingMicrodescMaxDownloadTries is insanely high.");
- }
-
- if (options->TestingCertMaxDownloadTries < 2) {
- REJECT("TestingCertMaxDownloadTries must be greater than 1.");
- } else if (options->TestingCertMaxDownloadTries > 800) {
- COMPLAIN("TestingCertMaxDownloadTries is insanely high.");
- }
-
if (options->TestingEnableConnBwEvent &&
!options->TestingTorNetwork && !options->UsingTestNetworkDefaults_) {
REJECT("TestingEnableConnBwEvent may only be changed in testing "
@@ -4692,15 +4588,14 @@ have_enough_mem_for_dircache(const or_options_t *options, size_t total_mem,
if (options->DirCache) {
if (total_mem < DIRCACHE_MIN_MEM_BYTES) {
if (options->BridgeRelay) {
- *msg = tor_strdup("Running a Bridge with less than "
- STRINGIFY(DIRCACHE_MIN_MEM_MB) " MB of memory is not "
- "recommended.");
+ tor_asprintf(msg, "Running a Bridge with less than %d MB of memory "
+ "is not recommended.", DIRCACHE_MIN_MEM_MB);
} else {
- *msg = tor_strdup("Being a directory cache (default) with less than "
- STRINGIFY(DIRCACHE_MIN_MEM_MB) " MB of memory is not "
- "recommended and may consume most of the available "
- "resources, consider disabling this functionality by "
- "setting the DirCache option to 0.");
+ tor_asprintf(msg, "Being a directory cache (default) with less than "
+ "%d MB of memory is not recommended and may consume "
+ "most of the available resources. Consider disabling "
+ "this functionality by setting the DirCache option "
+ "to 0.", DIRCACHE_MIN_MEM_MB);
}
}
} else {
diff --git a/src/or/connection_or.c b/src/or/connection_or.c
index 272a086a32..267463312c 100644
--- a/src/or/connection_or.c
+++ b/src/or/connection_or.c
@@ -28,6 +28,7 @@
* part of a subclass (channel_tls_t).
*/
#define TOR_CHANNEL_INTERNAL_
+#define CONNECTION_OR_PRIVATE
#include "channel.h"
#include "channeltls.h"
#include "circuitbuild.h"
@@ -1122,6 +1123,216 @@ connection_or_group_set_badness_(smartlist_t *group, int force)
} SMARTLIST_FOREACH_END(or_conn);
}
+/* Lifetime of a connection failure. After that, we'll retry. This is in
+ * seconds. */
+#define OR_CONNECT_FAILURE_LIFETIME 60
+/* The interval to use with when to clean up the failure cache. */
+#define OR_CONNECT_FAILURE_CLEANUP_INTERVAL 60
+
+/* When is the next time we have to cleanup the failure map. We keep this
+ * because we clean it opportunistically. */
+static time_t or_connect_failure_map_next_cleanup_ts = 0;
+
+/* OR connection failure entry data structure. It is kept in the connection
+ * failure map defined below and indexed by OR identity digest, address and
+ * port.
+ *
+ * We need to identify a connection failure with these three values because we
+ * want to avoid to wrongfully blacklist a relay if someone is trying to
+ * extend to a known identity digest but with the wrong IP/port. For instance,
+ * it can happen if a relay changed its port but the client still has an old
+ * descriptor with the old port. We want to stop connecting to that
+ * IP/port/identity all together, not only the relay identity. */
+typedef struct or_connect_failure_entry_t {
+ HT_ENTRY(or_connect_failure_entry_t) node;
+ /* Identity digest of the connection where it is connecting to. */
+ uint8_t identity_digest[DIGEST_LEN];
+ /* This is the connection address from the base connection_t. After the
+ * connection is checked for canonicity, the base address should represent
+ * what we know instead of where we are connecting to. This is what we need
+ * so we can correlate known relays within the consensus. */
+ tor_addr_t addr;
+ uint16_t port;
+ /* Last time we were unable to connect. */
+ time_t last_failed_connect_ts;
+} or_connect_failure_entry_t;
+
+/* Map where we keep connection failure entries. They are indexed by addr,
+ * port and identity digest. */
+static HT_HEAD(or_connect_failure_ht, or_connect_failure_entry_t)
+ or_connect_failures_map = HT_INITIALIZER();
+
+/* Helper: Hashtable equal function. Return 1 if equal else 0. */
+static int
+or_connect_failure_ht_eq(const or_connect_failure_entry_t *a,
+ const or_connect_failure_entry_t *b)
+{
+ return fast_memeq(a->identity_digest, b->identity_digest, DIGEST_LEN) &&
+ tor_addr_eq(&a->addr, &b->addr) &&
+ a->port == b->port;
+}
+
+/* Helper: Return the hash for the hashtable of the given entry. For this
+ * table, it is a combination of address, port and identity digest. */
+static unsigned int
+or_connect_failure_ht_hash(const or_connect_failure_entry_t *entry)
+{
+ size_t offset = 0, addr_size;
+ const void *addr_ptr;
+ /* Largest size is IPv6 and IPv4 is smaller so it is fine. */
+ uint8_t data[16 + sizeof(uint16_t) + DIGEST_LEN];
+
+ /* Get the right address bytes depending on the family. */
+ switch (tor_addr_family(&entry->addr)) {
+ case AF_INET:
+ addr_size = 4;
+ addr_ptr = &entry->addr.addr.in_addr.s_addr;
+ break;
+ case AF_INET6:
+ addr_size = 16;
+ addr_ptr = &entry->addr.addr.in6_addr.s6_addr;
+ break;
+ default:
+ tor_assert_nonfatal_unreached();
+ return 0;
+ }
+
+ memcpy(data, addr_ptr, addr_size);
+ offset += addr_size;
+ memcpy(data + offset, entry->identity_digest, DIGEST_LEN);
+ offset += DIGEST_LEN;
+ set_uint16(data + offset, entry->port);
+ offset += sizeof(uint16_t);
+
+ return (unsigned int) siphash24g(data, offset);
+}
+
+HT_PROTOTYPE(or_connect_failure_ht, or_connect_failure_entry_t, node,
+ or_connect_failure_ht_hash, or_connect_failure_ht_eq)
+
+HT_GENERATE2(or_connect_failure_ht, or_connect_failure_entry_t, node,
+ or_connect_failure_ht_hash, or_connect_failure_ht_eq,
+ 0.6, tor_reallocarray_, tor_free_)
+
+/* Initialize a given connect failure entry with the given identity_digest,
+ * addr and port. All field are optional except ocf. */
+static void
+or_connect_failure_init(const char *identity_digest, const tor_addr_t *addr,
+ uint16_t port, or_connect_failure_entry_t *ocf)
+{
+ tor_assert(ocf);
+ if (identity_digest) {
+ memcpy(ocf->identity_digest, identity_digest,
+ sizeof(ocf->identity_digest));
+ }
+ if (addr) {
+ tor_addr_copy(&ocf->addr, addr);
+ }
+ ocf->port = port;
+}
+
+/* Return a newly allocated connection failure entry. It is initialized with
+ * the given or_conn data. This can't fail. */
+static or_connect_failure_entry_t *
+or_connect_failure_new(const or_connection_t *or_conn)
+{
+ or_connect_failure_entry_t *ocf = tor_malloc_zero(sizeof(*ocf));
+ or_connect_failure_init(or_conn->identity_digest, &or_conn->real_addr,
+ TO_CONN(or_conn)->port, ocf);
+ return ocf;
+}
+
+/* Return a connection failure entry matching the given or_conn. NULL is
+ * returned if not found. */
+static or_connect_failure_entry_t *
+or_connect_failure_find(const or_connection_t *or_conn)
+{
+ or_connect_failure_entry_t lookup;
+ tor_assert(or_conn);
+ or_connect_failure_init(or_conn->identity_digest, &TO_CONN(or_conn)->addr,
+ TO_CONN(or_conn)->port, &lookup);
+ return HT_FIND(or_connect_failure_ht, &or_connect_failures_map, &lookup);
+}
+
+/* Note down in the connection failure cache that a failure occurred on the
+ * given or_conn. */
+STATIC void
+note_or_connect_failed(const or_connection_t *or_conn)
+{
+ or_connect_failure_entry_t *ocf = NULL;
+
+ tor_assert(or_conn);
+
+ ocf = or_connect_failure_find(or_conn);
+ if (ocf == NULL) {
+ ocf = or_connect_failure_new(or_conn);
+ HT_INSERT(or_connect_failure_ht, &or_connect_failures_map, ocf);
+ }
+ ocf->last_failed_connect_ts = approx_time();
+}
+
+/* Cleanup the connection failure cache and remove all entries below the
+ * given cutoff. */
+static void
+or_connect_failure_map_cleanup(time_t cutoff)
+{
+ or_connect_failure_entry_t **ptr, **next, *entry;
+
+ for (ptr = HT_START(or_connect_failure_ht, &or_connect_failures_map);
+ ptr != NULL; ptr = next) {
+ entry = *ptr;
+ if (entry->last_failed_connect_ts <= cutoff) {
+ next = HT_NEXT_RMV(or_connect_failure_ht, &or_connect_failures_map, ptr);
+ tor_free(entry);
+ } else {
+ next = HT_NEXT(or_connect_failure_ht, &or_connect_failures_map, ptr);
+ }
+ }
+}
+
+/* Return true iff the given OR connection can connect to its destination that
+ * is the triplet identity_digest, address and port.
+ *
+ * The or_conn MUST have gone through connection_or_check_canonicity() so the
+ * base address is properly set to what we know or doesn't know. */
+STATIC int
+should_connect_to_relay(const or_connection_t *or_conn)
+{
+ time_t now, cutoff;
+ time_t connect_failed_since_ts = 0;
+ or_connect_failure_entry_t *ocf;
+
+ tor_assert(or_conn);
+
+ now = approx_time();
+ cutoff = now - OR_CONNECT_FAILURE_LIFETIME;
+
+ /* Opportunistically try to cleanup the failure cache. We do that at regular
+ * interval so it doesn't grow too big. */
+ if (or_connect_failure_map_next_cleanup_ts <= now) {
+ or_connect_failure_map_cleanup(cutoff);
+ or_connect_failure_map_next_cleanup_ts =
+ now + OR_CONNECT_FAILURE_CLEANUP_INTERVAL;
+ }
+
+ /* Look if we have failed previously to the same destination as this
+ * OR connection. */
+ ocf = or_connect_failure_find(or_conn);
+ if (ocf) {
+ connect_failed_since_ts = ocf->last_failed_connect_ts;
+ }
+ /* If we do have an unable to connect timestamp and it is below cutoff, we
+ * can connect. Or we have never failed before so let it connect. */
+ if (connect_failed_since_ts > cutoff) {
+ goto no_connect;
+ }
+
+ /* Ok we can connect! */
+ return 1;
+ no_connect:
+ return 0;
+}
+
/** <b>conn</b> is in the 'connecting' state, and it failed to complete
* a TCP connection. Send notifications appropriately.
*
@@ -1135,6 +1346,7 @@ connection_or_connect_failed(or_connection_t *conn,
control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED, reason);
if (!authdir_mode_tests_reachability(get_options()))
control_event_bootstrap_prob_or(msg, reason, conn);
+ note_or_connect_failed(conn);
}
/** <b>conn</b> got an error in connection_handle_read_impl() or
@@ -1225,6 +1437,19 @@ connection_or_connect, (const tor_addr_t *_addr, uint16_t port,
conn->chan = chan;
chan->conn = conn;
connection_or_init_conn_from_address(conn, &addr, port, id_digest, ed_id, 1);
+
+ /* We have a proper OR connection setup, now check if we can connect to it
+ * that is we haven't had a failure earlier. This is to avoid to try to
+ * constantly connect to relays that we think are not reachable. */
+ if (!should_connect_to_relay(conn)) {
+ log_info(LD_GENERAL, "Can't connect to identity %s at %s:%u because we "
+ "failed earlier. Refusing.",
+ hex_str(id_digest, DIGEST_LEN), fmt_addr(&TO_CONN(conn)->addr),
+ TO_CONN(conn)->port);
+ connection_free_(TO_CONN(conn));
+ return NULL;
+ }
+
connection_or_change_state(conn, OR_CONN_STATE_CONNECTING);
control_event_or_conn_status(conn, OR_CONN_EVENT_LAUNCHED, 0);
diff --git a/src/or/connection_or.h b/src/or/connection_or.h
index 7c1dced631..158eb1fdad 100644
--- a/src/or/connection_or.h
+++ b/src/or/connection_or.h
@@ -120,6 +120,11 @@ int connection_or_single_set_badness_(time_t now,
int force);
void connection_or_group_set_badness_(smartlist_t *group, int force);
+#ifdef CONNECTION_OR_PRIVATE
+STATIC int should_connect_to_relay(const or_connection_t *or_conn);
+STATIC void note_or_connect_failed(const or_connection_t *or_conn);
+#endif
+
#ifdef TOR_UNIT_TESTS
extern int certs_cell_ed25519_disabled_for_testing;
#endif
diff --git a/src/or/control.c b/src/or/control.c
index 948ac92bb1..5a2fae64e7 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -83,8 +83,6 @@
#include <sys/resource.h>
#endif
-#include <event2/event.h>
-
#include "crypto_s2k.h"
#include "procmon.h"
@@ -216,7 +214,7 @@ static void orconn_target_get_name(char *buf, size_t len,
static int get_cached_network_liveness(void);
static void set_cached_network_liveness(int liveness);
-static void flush_queued_events_cb(evutil_socket_t fd, short what, void *arg);
+static void flush_queued_events_cb(mainloop_event_t *event, void *arg);
static char * download_status_to_string(const download_status_t *dl);
@@ -691,7 +689,7 @@ static tor_mutex_t *queued_control_events_lock = NULL;
/** An event that should fire in order to flush the contents of
* queued_control_events. */
-static struct event *flush_queued_events_event = NULL;
+static mainloop_event_t *flush_queued_events_event = NULL;
void
control_initialize_event_queue(void)
@@ -703,9 +701,8 @@ control_initialize_event_queue(void)
if (flush_queued_events_event == NULL) {
struct event_base *b = tor_libevent_get_base();
if (b) {
- flush_queued_events_event = tor_event_new(b,
- -1, 0, flush_queued_events_cb,
- NULL);
+ flush_queued_events_event =
+ mainloop_event_new(flush_queued_events_cb, NULL);
tor_assert(flush_queued_events_event);
}
}
@@ -781,7 +778,7 @@ queue_control_event_string,(uint16_t event, char *msg))
*/
if (activate_event) {
tor_assert(flush_queued_events_event);
- event_active(flush_queued_events_event, EV_READ, 1);
+ mainloop_event_activate(flush_queued_events_event);
}
}
@@ -863,10 +860,9 @@ queued_events_flush_all(int force)
/** Libevent callback: Flushes pending events to controllers that are
* interested in them. */
static void
-flush_queued_events_cb(evutil_socket_t fd, short what, void *arg)
+flush_queued_events_cb(mainloop_event_t *event, void *arg)
{
- (void) fd;
- (void) what;
+ (void) event;
(void) arg;
queued_events_flush_all(0);
}
@@ -2252,7 +2248,7 @@ digest_list_to_string(const smartlist_t *sl)
static char *
download_status_to_string(const download_status_t *dl)
{
- char *rv = NULL, *tmp;
+ char *rv = NULL;
char tbuf[ISO_TIME_LEN+1];
const char *schedule_str, *want_authority_str;
const char *increment_on_str, *backoff_str;
@@ -2300,49 +2296,28 @@ download_status_to_string(const download_status_t *dl)
break;
}
- switch (dl->backoff) {
- case DL_SCHED_DETERMINISTIC:
- backoff_str = "DL_SCHED_DETERMINISTIC";
- break;
- case DL_SCHED_RANDOM_EXPONENTIAL:
- backoff_str = "DL_SCHED_RANDOM_EXPONENTIAL";
- break;
- default:
- backoff_str = "unknown";
- break;
- }
+ backoff_str = "DL_SCHED_RANDOM_EXPONENTIAL";
/* Now assemble them */
- tor_asprintf(&tmp,
+ tor_asprintf(&rv,
"next-attempt-at %s\n"
"n-download-failures %u\n"
"n-download-attempts %u\n"
"schedule %s\n"
"want-authority %s\n"
"increment-on %s\n"
- "backoff %s\n",
+ "backoff %s\n"
+ "last-backoff-position %u\n"
+ "last-delay-used %d\n",
tbuf,
dl->n_download_failures,
dl->n_download_attempts,
schedule_str,
want_authority_str,
increment_on_str,
- backoff_str);
-
- if (dl->backoff == DL_SCHED_RANDOM_EXPONENTIAL) {
- /* Additional fields become relevant in random-exponential mode */
- tor_asprintf(&rv,
- "%s"
- "last-backoff-position %u\n"
- "last-delay-used %d\n",
- tmp,
- dl->last_backoff_position,
- dl->last_delay_used);
- tor_free(tmp);
- } else {
- /* That was it */
- rv = tmp;
- }
+ backoff_str,
+ dl->last_backoff_position,
+ dl->last_delay_used);
}
return rv;
@@ -3551,6 +3526,9 @@ handle_control_extendcircuit(control_connection_t *conn, uint32_t len,
goto done;
}
circuit_append_new_exit(circ, info);
+ if (circ->build_state->desired_path_len > 1) {
+ circ->build_state->onehop_tunnel = 0;
+ }
extend_info_free(info);
first_node = 0;
});
@@ -7604,22 +7582,38 @@ control_event_hs_descriptor_upload_failed(const char *id_digest,
void
control_free_all(void)
{
+ smartlist_t *queued_events = NULL;
+
if (authentication_cookie) /* Free the auth cookie */
tor_free(authentication_cookie);
if (detached_onion_services) { /* Free the detached onion services */
SMARTLIST_FOREACH(detached_onion_services, char *, cp, tor_free(cp));
smartlist_free(detached_onion_services);
}
- if (queued_control_events) {
- SMARTLIST_FOREACH(queued_control_events, queued_event_t *, ev,
- queued_event_free(ev));
- smartlist_free(queued_control_events);
+
+ if (queued_control_events_lock) {
+ tor_mutex_acquire(queued_control_events_lock);
+ flush_queued_event_pending = 0;
+ queued_events = queued_control_events;
queued_control_events = NULL;
+ tor_mutex_release(queued_control_events_lock);
+ }
+ if (queued_events) {
+ SMARTLIST_FOREACH(queued_events, queued_event_t *, ev,
+ queued_event_free(ev));
+ smartlist_free(queued_events);
}
if (flush_queued_events_event) {
- tor_event_free(flush_queued_events_event);
+ mainloop_event_free(flush_queued_events_event);
flush_queued_events_event = NULL;
}
+ bootstrap_percent = BOOTSTRAP_STATUS_UNDEF;
+ notice_bootstrap_percent = 0;
+ bootstrap_problems = 0;
+ authentication_cookie_is_set = 0;
+ global_event_mask = 0;
+ disable_log_messages = 0;
+ memset(last_sent_bootstrap_message, 0, sizeof(last_sent_bootstrap_message));
}
#ifdef TOR_UNIT_TESTS
diff --git a/src/or/cpuworker.c b/src/or/cpuworker.c
index 50761dd4d3..083691c4f6 100644
--- a/src/or/cpuworker.c
+++ b/src/or/cpuworker.c
@@ -30,8 +30,6 @@
#include "router.h"
#include "workqueue.h"
-#include <event2/event.h>
-
static void queue_pending_tasks(void);
typedef struct worker_state_s {
@@ -69,22 +67,12 @@ worker_state_free_void(void *arg)
static replyqueue_t *replyqueue = NULL;
static threadpool_t *threadpool = NULL;
-static struct event *reply_event = NULL;
static tor_weak_rng_t request_sample_rng = TOR_WEAK_RNG_INIT;
static int total_pending_tasks = 0;
static int max_pending_tasks = 128;
-static void
-replyqueue_process_cb(evutil_socket_t sock, short events, void *arg)
-{
- replyqueue_t *rq = arg;
- (void) sock;
- (void) events;
- replyqueue_process(rq);
-}
-
/** Initialize the cpuworker subsystem. It is OK to call this more than once
* during Tor's lifetime.
*/
@@ -94,14 +82,6 @@ cpu_init(void)
if (!replyqueue) {
replyqueue = replyqueue_new(0);
}
- if (!reply_event) {
- reply_event = tor_event_new(tor_libevent_get_base(),
- replyqueue_get_socket(replyqueue),
- EV_READ|EV_PERSIST,
- replyqueue_process_cb,
- replyqueue);
- event_add(reply_event, NULL);
- }
if (!threadpool) {
/*
In our threadpool implementation, half the threads are permissive and
@@ -115,7 +95,12 @@ cpu_init(void)
worker_state_new,
worker_state_free_void,
NULL);
+
+ int r = threadpool_register_reply_event(threadpool, NULL);
+
+ tor_assert(r == 0);
}
+
/* Total voodoo. Can we make this more sensible? */
max_pending_tasks = get_num_cpus(get_options()) * 64;
crypto_seed_weak_rng(&request_sample_rng);
@@ -547,7 +532,7 @@ assign_onionskin_to_cpuworker(or_circuit_t *circ,
return 0;
}
- if (connection_or_digest_is_known_relay(circ->p_chan->identity_digest))
+ if (!channel_is_client(circ->p_chan))
rep_hist_note_circuit_handshake_assigned(onionskin->handshake_type);
should_time = should_time_request(onionskin->handshake_type);
diff --git a/src/or/directory.c b/src/or/directory.c
index 33d8573645..c419b61d02 100644
--- a/src/or/directory.c
+++ b/src/or/directory.c
@@ -5362,17 +5362,14 @@ find_dl_schedule(const download_status_t *dls, const or_options_t *options)
return NULL;
}
-/** Decide which minimum and maximum delay step we want to use based on
+/** Decide which minimum delay step we want to use based on
* descriptor type in <b>dls</b> and <b>options</b>.
* Helper function for download_status_schedule_get_delay(). */
-STATIC void
-find_dl_min_and_max_delay(download_status_t *dls, const or_options_t *options,
- int *min, int *max)
+STATIC int
+find_dl_min_delay(download_status_t *dls, const or_options_t *options)
{
tor_assert(dls);
tor_assert(options);
- tor_assert(min);
- tor_assert(max);
/*
* For now, just use the existing schedule config stuff and pick the
@@ -5380,13 +5377,7 @@ find_dl_min_and_max_delay(download_status_t *dls, const or_options_t *options,
*/
const smartlist_t *schedule = find_dl_schedule(dls, options);
tor_assert(schedule != NULL && smartlist_len(schedule) >= 2);
- *min = *((int *)(smartlist_get(schedule, 0)));
- /* Increment on failure schedules always use exponential backoff, but they
- * have a smaller limit when they're deterministic */
- if (dls->backoff == DL_SCHED_DETERMINISTIC)
- *max = *((int *)((smartlist_get(schedule, smartlist_len(schedule) - 1))));
- else
- *max = INT_MAX;
+ return *(int *)(smartlist_get(schedule, 0));
}
/** As next_random_exponential_delay() below, but does not compute a random
@@ -5424,55 +5415,39 @@ next_random_exponential_delay_range(int *low_bound_out,
* zero); the <b>backoff_position</b> parameter is the number of times we've
* generated a delay; and the <b>delay</b> argument is the most recently used
* delay.
- *
- * Requires that delay is less than INT_MAX, and delay is in [0,max_delay].
*/
STATIC int
next_random_exponential_delay(int delay,
- int base_delay,
- int max_delay)
+ int base_delay)
{
/* Check preconditions */
- if (BUG(max_delay < 0))
- max_delay = 0;
- if (BUG(delay > max_delay))
- delay = max_delay;
if (BUG(delay < 0))
delay = 0;
if (base_delay < 1)
base_delay = 1;
- int low_bound=0, high_bound=max_delay;
+ int low_bound=0, high_bound=INT_MAX;
next_random_exponential_delay_range(&low_bound, &high_bound,
delay, base_delay);
- int rand_delay = crypto_rand_int_range(low_bound, high_bound);
-
- return MIN(rand_delay, max_delay);
+ return crypto_rand_int_range(low_bound, high_bound);
}
-/** Find the current delay for dls based on schedule or min_delay/
- * max_delay if we're using exponential backoff. If dls->backoff is
- * DL_SCHED_RANDOM_EXPONENTIAL, we must have 0 <= min_delay <= max_delay <=
- * INT_MAX, but schedule may be set to NULL; otherwise schedule is required.
+/** Find the current delay for dls based on min_delay.
+ *
* This function sets dls->next_attempt_at based on now, and returns the delay.
* Helper for download_status_increment_failure and
* download_status_increment_attempt. */
STATIC int
download_status_schedule_get_delay(download_status_t *dls,
- const smartlist_t *schedule,
- int min_delay, int max_delay,
+ int min_delay,
time_t now)
{
tor_assert(dls);
- /* We don't need a schedule if we're using random exponential backoff */
- tor_assert(dls->backoff == DL_SCHED_RANDOM_EXPONENTIAL ||
- schedule != NULL);
/* If we're using random exponential backoff, we do need min/max delay */
- tor_assert(dls->backoff != DL_SCHED_RANDOM_EXPONENTIAL ||
- (min_delay >= 0 && max_delay >= min_delay));
+ tor_assert(min_delay >= 0);
int delay = INT_MAX;
uint8_t dls_schedule_position = (dls->increment_on
@@ -5480,42 +5455,32 @@ download_status_schedule_get_delay(download_status_t *dls,
? dls->n_download_attempts
: dls->n_download_failures);
- if (dls->backoff == DL_SCHED_DETERMINISTIC) {
- if (dls_schedule_position < smartlist_len(schedule))
- delay = *(int *)smartlist_get(schedule, dls_schedule_position);
- else if (dls_schedule_position == IMPOSSIBLE_TO_DOWNLOAD)
- delay = INT_MAX;
- else
- delay = *(int *)smartlist_get(schedule, smartlist_len(schedule) - 1);
- } else if (dls->backoff == DL_SCHED_RANDOM_EXPONENTIAL) {
- /* Check if we missed a reset somehow */
- IF_BUG_ONCE(dls->last_backoff_position > dls_schedule_position) {
- dls->last_backoff_position = 0;
- dls->last_delay_used = 0;
- }
+ /* Check if we missed a reset somehow */
+ IF_BUG_ONCE(dls->last_backoff_position > dls_schedule_position) {
+ dls->last_backoff_position = 0;
+ dls->last_delay_used = 0;
+ }
- if (dls_schedule_position > 0) {
- delay = dls->last_delay_used;
+ if (dls_schedule_position > 0) {
+ delay = dls->last_delay_used;
- while (dls->last_backoff_position < dls_schedule_position) {
- /* Do one increment step */
- delay = next_random_exponential_delay(delay, min_delay, max_delay);
- /* Update our position */
- ++(dls->last_backoff_position);
- }
- } else {
- /* If we're just starting out, use the minimum delay */
- delay = min_delay;
+ while (dls->last_backoff_position < dls_schedule_position) {
+ /* Do one increment step */
+ delay = next_random_exponential_delay(delay, min_delay);
+ /* Update our position */
+ ++(dls->last_backoff_position);
}
+ } else {
+ /* If we're just starting out, use the minimum delay */
+ delay = min_delay;
+ }
- /* Clamp it within min/max if we have them */
- if (min_delay >= 0 && delay < min_delay) delay = min_delay;
- if (max_delay != INT_MAX && delay > max_delay) delay = max_delay;
+ /* Clamp it within min/max if we have them */
+ if (min_delay >= 0 && delay < min_delay) delay = min_delay;
- /* Store it for next time */
- dls->last_backoff_position = dls_schedule_position;
- dls->last_delay_used = delay;
- }
+ /* Store it for next time */
+ dls->last_backoff_position = dls_schedule_position;
+ dls->last_delay_used = delay;
/* A negative delay makes no sense. Knowing that delay is
* non-negative allows us to safely do the wrapping check below. */
@@ -5578,7 +5543,7 @@ download_status_increment_failure(download_status_t *dls, int status_code,
(void) status_code; // XXXX no longer used.
(void) server; // XXXX no longer used.
int increment = -1;
- int min_delay = 0, max_delay = INT_MAX;
+ int min_delay = 0;
tor_assert(dls);
@@ -5603,10 +5568,8 @@ download_status_increment_failure(download_status_t *dls, int status_code,
/* only return a failure retry time if this schedule increments on failures
*/
- const smartlist_t *schedule = find_dl_schedule(dls, get_options());
- find_dl_min_and_max_delay(dls, get_options(), &min_delay, &max_delay);
- increment = download_status_schedule_get_delay(dls, schedule,
- min_delay, max_delay, now);
+ min_delay = find_dl_min_delay(dls, get_options());
+ increment = download_status_schedule_get_delay(dls, min_delay, now);
}
download_status_log_helper(item, !dls->increment_on, "failed",
@@ -5637,7 +5600,7 @@ download_status_increment_attempt(download_status_t *dls, const char *item,
time_t now)
{
int delay = -1;
- int min_delay = 0, max_delay = INT_MAX;
+ int min_delay = 0;
tor_assert(dls);
@@ -5657,10 +5620,8 @@ download_status_increment_attempt(download_status_t *dls, const char *item,
if (dls->n_download_attempts < IMPOSSIBLE_TO_DOWNLOAD-1)
++dls->n_download_attempts;
- const smartlist_t *schedule = find_dl_schedule(dls, get_options());
- find_dl_min_and_max_delay(dls, get_options(), &min_delay, &max_delay);
- delay = download_status_schedule_get_delay(dls, schedule,
- min_delay, max_delay, now);
+ min_delay = find_dl_min_delay(dls, get_options());
+ delay = download_status_schedule_get_delay(dls, min_delay, now);
download_status_log_helper(item, dls->increment_on, "attempted",
"on failure", dls->n_download_attempts,
@@ -5769,8 +5730,7 @@ dir_routerdesc_download_failed(smartlist_t *failed, int status_code,
} else {
dls = router_get_dl_status_by_descriptor_digest(digest);
}
- if (!dls || dls->n_download_failures >=
- get_options()->TestingDescriptorMaxDownloadTries)
+ if (!dls)
continue;
download_status_increment_failure(dls, status_code, cp, server, now);
} SMARTLIST_FOREACH_END(cp);
@@ -5807,10 +5767,6 @@ dir_microdesc_download_failed(smartlist_t *failed,
if (!rs)
continue;
dls = &rs->dl_status;
- if (dls->n_download_failures >=
- get_options()->TestingMicrodescMaxDownloadTries) {
- continue;
- }
{ /* Increment the failure count for this md fetch */
char buf[BASE64_DIGEST256_LEN+1];
diff --git a/src/or/directory.h b/src/or/directory.h
index edf75ffe13..aa4d29a5bb 100644
--- a/src/or/directory.h
+++ b/src/or/directory.h
@@ -132,29 +132,19 @@ time_t download_status_increment_attempt(download_status_t *dls,
time(NULL))
void download_status_reset(download_status_t *dls);
-static int download_status_is_ready(download_status_t *dls, time_t now,
- int max_failures);
+static int download_status_is_ready(download_status_t *dls, time_t now);
time_t download_status_get_next_attempt_at(const download_status_t *dls);
/** Return true iff, as of <b>now</b>, the resource tracked by <b>dls</b> is
* ready to get its download reattempted. */
static inline int
-download_status_is_ready(download_status_t *dls, time_t now,
- int max_failures)
+download_status_is_ready(download_status_t *dls, time_t now)
{
/* dls wasn't reset before it was used */
if (dls->next_attempt_at == 0) {
download_status_reset(dls);
}
- if (dls->backoff == DL_SCHED_DETERMINISTIC) {
- /* Deterministic schedules can hit an endpoint; exponential backoff
- * schedules just wait longer and longer. */
- int under_failure_limit = (dls->n_download_failures <= max_failures
- && dls->n_download_attempts <= max_failures);
- if (!under_failure_limit)
- return 0;
- }
return download_status_get_next_attempt_at(dls) <= now;
}
@@ -260,8 +250,7 @@ MOCK_DECL(STATIC int, directory_handle_command_post,(dir_connection_t *conn,
const char *body,
size_t body_len));
STATIC int download_status_schedule_get_delay(download_status_t *dls,
- const smartlist_t *schedule,
- int min_delay, int max_delay,
+ int min_delay,
time_t now);
STATIC int handle_post_hs_descriptor(const char *url, const char *body);
@@ -272,13 +261,11 @@ STATIC int should_use_directory_guards(const or_options_t *options);
STATIC compression_level_t choose_compression_level(ssize_t n_bytes);
STATIC const smartlist_t *find_dl_schedule(const download_status_t *dls,
const or_options_t *options);
-STATIC void find_dl_min_and_max_delay(download_status_t *dls,
- const or_options_t *options,
- int *min, int *max);
+STATIC int find_dl_min_delay(download_status_t *dls,
+ const or_options_t *options);
STATIC int next_random_exponential_delay(int delay,
- int base_delay,
- int max_delay);
+ int base_delay);
STATIC void next_random_exponential_delay_range(int *low_bound_out,
int *high_bound_out,
diff --git a/src/or/dirserv.c b/src/or/dirserv.c
index 7ccce50bc5..68727f0718 100644
--- a/src/or/dirserv.c
+++ b/src/or/dirserv.c
@@ -858,13 +858,13 @@ directory_remove_invalid(void)
SMARTLIST_FOREACH_BEGIN(nodes, node_t *, node) {
const char *msg = NULL;
+ const char *description;
routerinfo_t *ent = node->ri;
- char description[NODE_DESC_BUF_LEN];
uint32_t r;
if (!ent)
continue;
r = dirserv_router_get_status(ent, &msg, LOG_INFO);
- router_get_description(description, ent);
+ description = router_describe(ent);
if (r & FP_REJECT) {
log_info(LD_DIRSERV, "Router %s is now rejected: %s",
description, msg?msg:"");
@@ -2266,6 +2266,7 @@ set_routerstatus_from_routerinfo(routerstatus_t *rs,
rs->is_valid = node->is_valid;
if (node->is_fast && node->is_stable &&
+ ri->supports_tunnelled_dir_requests &&
((options->AuthDirGuardBWGuarantee &&
routerbw_kb >= options->AuthDirGuardBWGuarantee/1000) ||
routerbw_kb >= MIN(guard_bandwidth_including_exits_kb,
@@ -3392,7 +3393,8 @@ dirserv_single_reachability_test(time_t now, routerinfo_t *router)
tor_assert(node);
if (options->AuthDirTestEd25519LinkKeys &&
- node_supports_ed25519_link_authentication(node, 1)) {
+ node_supports_ed25519_link_authentication(node, 1) &&
+ router->cache_info.signing_key_cert) {
ed_id_key = &router->cache_info.signing_key_cert->signing_key;
} else {
ed_id_key = NULL;
diff --git a/src/or/dns.c b/src/or/dns.c
index e4dc8048ed..411e2d5aa6 100644
--- a/src/or/dns.c
+++ b/src/or/dns.c
@@ -1441,27 +1441,30 @@ configure_nameservers(int force)
// If we only have one nameserver, it does not make sense to back off
// from it for a timeout. Unfortunately, the value for max-timeouts is
// currently clamped by libevent to 255, but it does not hurt to set
- // it higher in case libevent gets a patch for this.
- // Reducing attempts in the case of just one name server too, because
- // it is very likely to be a local one where a network connectivity
- // issue should not cause an attempt to fail.
+ // it higher in case libevent gets a patch for this. Higher-than-
+ // default maximum of 3 with multiple nameservers to avoid spuriously
+ // marking one down on bursts of timeouts resulting from scans/attacks
+ // against non-responding authoritative DNS servers.
if (evdns_base_count_nameservers(the_evdns_base) == 1) {
SET("max-timeouts:", "1000000");
- SET("attempts:", "1");
} else {
- SET("max-timeouts:", "3");
+ SET("max-timeouts:", "10");
}
// Elongate the queue of maximum inflight dns requests, so if a bunch
- // time out at the resolver (happens commonly with unbound) we won't
+ // remain pending at the resolver (happens commonly with Unbound) we won't
// stall every other DNS request. This potentially means some wasted
// CPU as there's a walk over a linear queue involved, but this is a
// much better tradeoff compared to just failing DNS requests because
// of a full queue.
SET("max-inflight:", "8192");
- // Time out after 5 seconds if no reply.
+ // Two retries at 5 and 10 seconds for bind9/named which relies on
+ // clients to handle retries. Second retry for retried circuits with
+ // extended 15 second timeout. Superfluous with local-system Unbound
+ // instance--has its own elaborate retry scheme.
SET("timeout:", "5");
+ SET("attempts:","3");
if (options->ServerDNSRandomizeCase)
SET("randomize-case:", "1");
diff --git a/src/or/dnsserv.c b/src/or/dnsserv.c
index 9385561d99..7e344deeab 100644
--- a/src/or/dnsserv.c
+++ b/src/or/dnsserv.c
@@ -208,6 +208,7 @@ dnsserv_launch_request(const char *name, int reverse,
/* Make a new dummy AP connection, and attach the request to it. */
entry_conn = entry_connection_new(CONN_TYPE_AP, AF_INET);
+ entry_conn->entry_cfg.dns_request = 1;
conn = ENTRY_TO_EDGE_CONN(entry_conn);
CONNECTION_AP_EXPECT_NONPENDING(entry_conn);
conn->base_.state = AP_CONN_STATE_RESOLVE_WAIT;
diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c
index 2b6ff38c9c..88d1b94deb 100644
--- a/src/or/entrynodes.c
+++ b/src/or/entrynodes.c
@@ -2334,7 +2334,7 @@ entry_guard_cancel(circuit_guard_state_t **guard_state_p)
}
/**
- * Called by the circuit building module when a circuit has succeeded:
+ * Called by the circuit building module when a circuit has failed:
* informs the guards code that the guard in *<b>guard_state_p</b> is
* not working, and advances the state of the guard module.
*/
diff --git a/src/or/geoip.c b/src/or/geoip.c
index 0ff1c6ce0d..2c917c564d 100644
--- a/src/or/geoip.c
+++ b/src/or/geoip.c
@@ -628,8 +628,7 @@ geoip_note_client_seen(geoip_client_action_t action,
/* Only remember statistics if the DoS mitigation subsystem is enabled. If
* not, only if as entry guard or as bridge. */
if (!dos_enabled()) {
- if (!options->EntryStatistics &&
- (!(options->BridgeRelay && options->BridgeRecordUsageByCountry))) {
+ if (!options->EntryStatistics && !should_record_bridge_info(options)) {
return;
}
}
@@ -1881,5 +1880,8 @@ geoip_free_all(void)
clear_geoip_db();
tor_free(bridge_stats_extrainfo);
+
+ memset(geoip_digest, 0, sizeof(geoip_digest));
+ memset(geoip6_digest, 0, sizeof(geoip6_digest));
}
diff --git a/src/or/hs_cell.c b/src/or/hs_cell.c
index 5244cfa3dd..ad92521d34 100644
--- a/src/or/hs_cell.c
+++ b/src/or/hs_cell.c
@@ -369,7 +369,7 @@ introduce1_encrypt_and_encode(trn_cell_introduce1_t *cell,
crypto_cipher_free(cipher);
offset += encoded_enc_cell_len;
/* Compute MAC from the above and put it in the buffer. This function will
- * make the adjustment to the encryptled_len to ommit the MAC length. */
+ * make the adjustment to the encrypted_len to omit the MAC length. */
compute_introduce_mac(encoded_cell, encoded_cell_len,
encrypted, encrypted_len,
keys.mac_key, sizeof(keys.mac_key),
diff --git a/src/or/hs_service.c b/src/or/hs_service.c
index 220d3f5157..ba8abc4237 100644
--- a/src/or/hs_service.c
+++ b/src/or/hs_service.c
@@ -1512,7 +1512,9 @@ build_all_descriptors(time_t now)
* empty, we'll try to build it for the next time period. This only
* happens when we rotate meaning that we are guaranteed to have a new SRV
* at that point for the next time period. */
- tor_assert(service->desc_current);
+ if (BUG(service->desc_current == NULL)) {
+ continue;
+ }
if (service->desc_next == NULL) {
build_service_descriptor(service, now, hs_get_next_time_period_num(0),
@@ -1929,6 +1931,33 @@ should_rotate_descriptors(hs_service_t *service, time_t now)
}
if (ns->valid_after >= service->state.next_rotation_time) {
+ /* In theory, we should never get here with no descriptors. We can never
+ * have a NULL current descriptor except when tor starts up. The next
+ * descriptor can be NULL after a rotation but we build a new one right
+ * after.
+ *
+ * So, when tor starts, the next rotation time is set to the start of the
+ * next SRV period using the consensus valid after time so it should
+ * always be set to a future time value. This means that we should never
+ * reach this point at bootup that is this check safeguards tor in never
+ * allowing a rotation if the valid after time is smaller than the next
+ * rotation time.
+ *
+ * This is all good in theory but we've had a NULL descriptor issue here
+ * so this is why we BUG() on both with extra logging to try to understand
+ * how this can possibly happens. We'll simply ignore and tor should
+ * recover from this by skipping rotation and building the missing
+ * descriptors just after this. */
+ if (BUG(service->desc_current == NULL || service->desc_next == NULL)) {
+ log_warn(LD_BUG, "Service descriptor is NULL (%p/%p). Next rotation "
+ "time is %ld (now: %ld). Valid after time from "
+ "consensus is %ld",
+ service->desc_current, service->desc_next,
+ (long)service->state.next_rotation_time,
+ (long)now,
+ (long)ns->valid_after);
+ goto no_rotation;
+ }
goto rotation;
}
@@ -1981,9 +2010,6 @@ rotate_all_descriptors(time_t now)
continue;
}
- tor_assert(service->desc_current);
- tor_assert(service->desc_next);
-
log_info(LD_REND, "Time to rotate our descriptors (%p / %p) for %s",
service->desc_current, service->desc_next,
safe_str_client(service->onion_address));
diff --git a/src/or/include.am b/src/or/include.am
index e0366a0cac..9a68df5c3e 100644
--- a/src/or/include.am
+++ b/src/or/include.am
@@ -91,6 +91,7 @@ LIBTOR_A_SOURCES = \
src/or/policies.c \
src/or/reasons.c \
src/or/relay.c \
+ src/or/relay_crypto.c \
src/or/rendcache.c \
src/or/rendclient.c \
src/or/rendcommon.c \
@@ -161,6 +162,7 @@ endif
ORHEADERS = \
src/or/addressmap.h \
+ src/or/auth_dirs.inc \
src/or/bridges.h \
src/or/channel.h \
src/or/channelpadding.h \
@@ -237,6 +239,7 @@ ORHEADERS = \
src/or/proto_socks.h \
src/or/reasons.h \
src/or/relay.h \
+ src/or/relay_crypto.h \
src/or/rendcache.h \
src/or/rendclient.h \
src/or/rendcommon.h \
diff --git a/src/or/keypin.c b/src/or/keypin.c
index 52bdff816c..97e16c1f78 100644
--- a/src/or/keypin.c
+++ b/src/or/keypin.c
@@ -12,7 +12,7 @@
#include "orconfig.h"
#include "compat.h"
-#include "crypto.h"
+#include "crypto_digest.h"
#include "crypto_format.h"
#include "di_ops.h"
#include "ht.h"
diff --git a/src/or/main.c b/src/or/main.c
index 077d8f8823..4cc51de07b 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -133,7 +133,7 @@ void evdns_shutdown(int);
#ifdef HAVE_RUST
// helper function defined in Rust to output a log message indicating if tor is
// running with Rust enabled. See src/rust/tor_util
-char *rust_welcome_string(void);
+void rust_log_welcome_string(void);
#endif
/********* PROTOTYPES **********/
@@ -719,7 +719,7 @@ tell_event_loop_to_run_external_code(void)
{
if (!called_loop_once) {
struct timeval tv = { 0, 0 };
- tor_event_base_loopexit(tor_libevent_get_base(), &tv);
+ tor_libevent_exit_loop_after_delay(tor_libevent_get_base(), &tv);
called_loop_once = 1; /* hack to avoid adding more exit events */
}
}
@@ -779,8 +779,9 @@ tor_shutdown_event_loop_and_exit(int exitcode)
shutdown_did_not_work_callback, NULL);
event_add(shutdown_did_not_work_event, &ten_seconds);
- /* Unlike loopexit, loopbreak prevents other callbacks from running. */
- tor_event_base_loopbreak(tor_libevent_get_base());
+ /* Unlike exit_loop_after_delay(), exit_loop_after_callback
+ * prevents other callbacks from running. */
+ tor_libevent_exit_loop_after_callback(tor_libevent_get_base());
}
/** Return true iff tor_shutdown_event_loop_and_exit() has been called. */
@@ -1060,9 +1061,8 @@ conn_close_if_marked(int i)
* reason.
*/
static void
-directory_all_unreachable_cb(evutil_socket_t fd, short event, void *arg)
+directory_all_unreachable_cb(mainloop_event_t *event, void *arg)
{
- (void)fd;
(void)event;
(void)arg;
@@ -1082,7 +1082,7 @@ directory_all_unreachable_cb(evutil_socket_t fd, short event, void *arg)
control_event_general_error("DIR_ALL_UNREACHABLE");
}
-static struct event *directory_all_unreachable_cb_event = NULL;
+static mainloop_event_t *directory_all_unreachable_cb_event = NULL;
/** We've just tried every dirserver we know about, and none of
* them were reachable. Assume the network is down. Change state
@@ -1099,12 +1099,11 @@ directory_all_unreachable(time_t now)
if (!directory_all_unreachable_cb_event) {
directory_all_unreachable_cb_event =
- tor_event_new(tor_libevent_get_base(),
- -1, EV_READ, directory_all_unreachable_cb, NULL);
+ mainloop_event_new(directory_all_unreachable_cb, NULL);
tor_assert(directory_all_unreachable_cb_event);
}
- event_active(directory_all_unreachable_cb_event, EV_READ, 1);
+ mainloop_event_activate(directory_all_unreachable_cb_event);
}
/** This function is called whenever we successfully pull down some new
@@ -1336,7 +1335,6 @@ CALLBACK(retry_listeners);
CALLBACK(expire_old_ciruits_serverside);
CALLBACK(check_dns_honesty);
CALLBACK(write_bridge_ns);
-CALLBACK(check_fw_helper_app);
CALLBACK(heartbeat);
CALLBACK(clean_consdiffmgr);
CALLBACK(reset_padding_counts);
@@ -1372,7 +1370,6 @@ static periodic_event_item_t periodic_events[] = {
CALLBACK(expire_old_ciruits_serverside),
CALLBACK(check_dns_honesty),
CALLBACK(write_bridge_ns),
- CALLBACK(check_fw_helper_app),
CALLBACK(heartbeat),
CALLBACK(clean_consdiffmgr),
CALLBACK(reset_padding_counts),
@@ -1475,6 +1472,7 @@ teardown_periodic_events(void)
for (i = 0; periodic_events[i].name; ++i) {
periodic_event_destroy(&periodic_events[i]);
}
+ periodic_events_initialized = 0;
}
/**
@@ -1942,14 +1940,14 @@ reset_padding_counts_callback(time_t now, const or_options_t *options)
return REPHIST_CELL_PADDING_COUNTS_INTERVAL;
}
+static int should_init_bridge_stats = 1;
+
/**
* Periodic callback: Write bridge statistics to disk if appropriate.
*/
static int
record_bridge_stats_callback(time_t now, const or_options_t *options)
{
- static int should_init_bridge_stats = 1;
-
/* 1h. Check whether we should write bridge statistics to disk.
*/
if (should_record_bridge_info(options)) {
@@ -2142,6 +2140,8 @@ expire_old_ciruits_serverside_callback(time_t now, const or_options_t *options)
return 11;
}
+static int dns_honesty_first_time = 1;
+
/**
* Periodic event: if we're an exit, see if our DNS server is telling us
* obvious lies.
@@ -2157,10 +2157,9 @@ check_dns_honesty_callback(time_t now, const or_options_t *options)
router_my_exit_policy_is_reject_star())
return PERIODIC_EVENT_NO_UPDATE;
- static int first_time = 1;
- if (first_time) {
+ if (dns_honesty_first_time) {
/* Don't launch right when we start */
- first_time = 0;
+ dns_honesty_first_time = 0;
return crypto_rand_int_range(60, 180);
}
@@ -2184,32 +2183,7 @@ write_bridge_ns_callback(time_t now, const or_options_t *options)
return PERIODIC_EVENT_NO_UPDATE;
}
-/**
- * Periodic callback: poke the tor-fw-helper app if we're using one.
- */
-static int
-check_fw_helper_app_callback(time_t now, const or_options_t *options)
-{
- if (net_is_disabled() ||
- ! server_mode(options) ||
- ! options->PortForwarding ||
- options->NoExec) {
- return PERIODIC_EVENT_NO_UPDATE;
- }
- /* 11. check the port forwarding app */
-
-#define PORT_FORWARDING_CHECK_INTERVAL 5
- smartlist_t *ports_to_forward = get_list_of_ports_to_forward();
- if (ports_to_forward) {
- tor_check_port_forwarding(options->PortForwardingHelper,
- ports_to_forward,
- now);
-
- SMARTLIST_FOREACH(ports_to_forward, char *, cp, tor_free(cp));
- smartlist_free(ports_to_forward);
- }
- return PORT_FORWARDING_CHECK_INTERVAL;
-}
+static int heartbeat_callback_first_time = 1;
/**
* Periodic callback: write the heartbeat message in the logs.
@@ -2220,16 +2194,14 @@ check_fw_helper_app_callback(time_t now, const or_options_t *options)
static int
heartbeat_callback(time_t now, const or_options_t *options)
{
- static int first = 1;
-
/* Check if heartbeat is disabled */
if (!options->HeartbeatPeriod) {
return PERIODIC_EVENT_NO_UPDATE;
}
/* Skip the first one. */
- if (first) {
- first = 0;
+ if (heartbeat_callback_first_time) {
+ heartbeat_callback_first_time = 0;
return options->HeartbeatPeriod;
}
@@ -2281,6 +2253,8 @@ hs_service_callback(time_t now, const or_options_t *options)
static periodic_timer_t *second_timer = NULL;
/** Number of libevent errors in the last second: we die if we get too many. */
static int n_libevent_errors = 0;
+/** Last time that second_elapsed_callback was called. */
+static time_t current_second = 0;
/** Libevent callback: invoked once every second. */
static void
@@ -2289,7 +2263,6 @@ second_elapsed_callback(periodic_timer_t *timer, void *arg)
/* XXXX This could be sensibly refactored into multiple callbacks, and we
* could use Libevent's timers for this rather than checking the current
* time against a bunch of timeouts every second. */
- static time_t current_second = 0;
time_t now;
size_t bytes_written;
size_t bytes_read;
@@ -2384,12 +2357,14 @@ systemd_watchdog_callback(periodic_timer_t *timer, void *arg)
/** Timer: used to invoke refill_callback(). */
static periodic_timer_t *refill_timer = NULL;
+/** Millisecond when refall_callback was last invoked. */
+static struct timeval refill_timer_current_millisecond;
+
/** Libevent callback: invoked periodically to refill token buckets
* and count r/w bytes. */
static void
refill_callback(periodic_timer_t *timer, void *arg)
{
- static struct timeval current_millisecond;
struct timeval now;
size_t bytes_written;
@@ -2405,12 +2380,13 @@ refill_callback(periodic_timer_t *timer, void *arg)
tor_gettimeofday(&now);
/* If this is our first time, no time has passed. */
- if (current_millisecond.tv_sec) {
- long mdiff = tv_mdiff(&current_millisecond, &now);
+ if (refill_timer_current_millisecond.tv_sec) {
+ long mdiff = tv_mdiff(&refill_timer_current_millisecond, &now);
if (mdiff > INT_MAX)
mdiff = INT_MAX;
milliseconds_elapsed = (int)mdiff;
- seconds_rolled_over = (int)(now.tv_sec - current_millisecond.tv_sec);
+ seconds_rolled_over = (int)(now.tv_sec -
+ refill_timer_current_millisecond.tv_sec);
}
bytes_written = stats_prev_global_write_bucket - global_write_bucket;
@@ -2427,7 +2403,8 @@ refill_callback(periodic_timer_t *timer, void *arg)
stats_prev_global_read_bucket = global_read_bucket;
stats_prev_global_write_bucket = global_write_bucket;
- current_millisecond = now; /* remember what time it is, for next time */
+ /* remember what time it is, for next time */
+ refill_timer_current_millisecond = now;
}
#ifndef _WIN32
@@ -2826,8 +2803,8 @@ run_main_loop_once(void)
* an event, or the second ends, or until we have some active linked
* connections to trigger events for. Libevent will wait till one
* of these happens, then run all the appropriate callbacks. */
- loop_result = event_base_loop(tor_libevent_get_base(),
- called_loop_once ? EVLOOP_ONCE : 0);
+ loop_result = tor_libevent_run_event_loop(tor_libevent_get_base(),
+ called_loop_once);
if (get_options()->MainloopStats) {
/* Update our main loop counters. */
@@ -3337,11 +3314,7 @@ tor_init(int argc, char *argv[])
}
#ifdef HAVE_RUST
- char *rust_str = rust_welcome_string();
- if (rust_str != NULL && strlen(rust_str) > 0) {
- log_notice(LD_GENERAL, "%s", rust_str);
- }
- tor_free(rust_str);
+ rust_log_welcome_string();
#endif /* defined(HAVE_RUST) */
if (network_init()<0) {
@@ -3522,6 +3495,32 @@ tor_free_all(int postfork)
periodic_timer_free(refill_timer);
tor_event_free(shutdown_did_not_work_event);
tor_event_free(initialize_periodic_events_event);
+ mainloop_event_free(directory_all_unreachable_cb_event);
+
+#ifdef HAVE_SYSTEMD_209
+ periodic_timer_free(systemd_watchdog_timer);
+#endif
+
+ global_read_bucket = global_write_bucket = 0;
+ global_relayed_read_bucket = global_relayed_write_bucket = 0;
+ stats_prev_global_read_bucket = stats_prev_global_write_bucket = 0;
+ stats_prev_n_read = stats_prev_n_written = 0;
+ stats_n_bytes_read = stats_n_bytes_written = 0;
+ time_of_process_start = 0;
+ time_of_last_signewnym = 0;
+ signewnym_is_pending = 0;
+ newnym_epoch = 0;
+ called_loop_once = 0;
+ main_loop_should_exit = 0;
+ main_loop_exit_value = 0;
+ can_complete_circuits = 0;
+ quiet_level = 0;
+ should_init_bridge_stats = 1;
+ dns_honesty_first_time = 1;
+ heartbeat_callback_first_time = 1;
+ n_libevent_errors = 0;
+ current_second = 0;
+ memset(&refill_timer_current_millisecond, 0, sizeof(struct timeval));
if (!postfork) {
release_lockfile();
diff --git a/src/or/microdesc.c b/src/or/microdesc.c
index d8a4660af1..b4a934e095 100644
--- a/src/or/microdesc.c
+++ b/src/or/microdesc.c
@@ -920,8 +920,7 @@ microdesc_list_missing_digest256(networkstatus_t *ns, microdesc_cache_t *cache,
if (microdesc_cache_lookup_by_digest256(cache, rs->descriptor_digest))
continue;
if (downloadable_only &&
- !download_status_is_ready(&rs->dl_status, now,
- get_options()->TestingMicrodescMaxDownloadTries))
+ !download_status_is_ready(&rs->dl_status, now))
continue;
if (skip && digest256map_get(skip, (const uint8_t*)rs->descriptor_digest))
continue;
diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c
index 31ecb20985..235b95b704 100644
--- a/src/or/networkstatus.c
+++ b/src/or/networkstatus.c
@@ -107,9 +107,9 @@ static time_t time_to_download_next_consensus[N_CONSENSUS_FLAVORS];
static download_status_t consensus_dl_status[N_CONSENSUS_FLAVORS] =
{
{ 0, 0, 0, DL_SCHED_CONSENSUS, DL_WANT_ANY_DIRSERVER,
- DL_SCHED_INCREMENT_FAILURE, DL_SCHED_RANDOM_EXPONENTIAL, 0, 0 },
+ DL_SCHED_INCREMENT_FAILURE, 0, 0 },
{ 0, 0, 0, DL_SCHED_CONSENSUS, DL_WANT_ANY_DIRSERVER,
- DL_SCHED_INCREMENT_FAILURE, DL_SCHED_RANDOM_EXPONENTIAL, 0, 0 },
+ DL_SCHED_INCREMENT_FAILURE, 0, 0 },
};
#define N_CONSENSUS_BOOTSTRAP_SCHEDULES 2
@@ -126,10 +126,10 @@ static download_status_t
consensus_bootstrap_dl_status[N_CONSENSUS_BOOTSTRAP_SCHEDULES] =
{
{ 0, 0, 0, DL_SCHED_CONSENSUS, DL_WANT_AUTHORITY,
- DL_SCHED_INCREMENT_ATTEMPT, DL_SCHED_RANDOM_EXPONENTIAL, 0, 0 },
+ DL_SCHED_INCREMENT_ATTEMPT, 0, 0 },
/* During bootstrap, DL_WANT_ANY_DIRSERVER means "use fallbacks". */
{ 0, 0, 0, DL_SCHED_CONSENSUS, DL_WANT_ANY_DIRSERVER,
- DL_SCHED_INCREMENT_ATTEMPT, DL_SCHED_RANDOM_EXPONENTIAL, 0, 0 },
+ DL_SCHED_INCREMENT_ATTEMPT, 0, 0 },
};
/** True iff we have logged a warning about this OR's version being older than
@@ -237,7 +237,7 @@ router_reload_consensus_networkstatus(void)
s = networkstatus_read_cached_consensus_impl(flav, flavor, 1);
if (s) {
if (networkstatus_set_current_consensus(s, flavor,
- flags|NSSET_WAS_WAITING_FOR_CERTS,
+ flags | NSSET_WAS_WAITING_FOR_CERTS,
NULL)) {
log_info(LD_FS, "Couldn't load unverified consensus %s networkstatus "
"from cache", flavor);
@@ -943,20 +943,20 @@ update_consensus_networkstatus_downloads(time_t now)
update_consensus_bootstrap_multiple_downloads(now, options);
} else {
/* Check if we failed downloading a consensus too recently */
- int max_dl_tries = options->TestingConsensusMaxDownloadTries;
/* Let's make sure we remembered to update consensus_dl_status */
tor_assert(consensus_dl_status[i].schedule == DL_SCHED_CONSENSUS);
- if (!download_status_is_ready(&consensus_dl_status[i],
- now,
- max_dl_tries)) {
+ if (!download_status_is_ready(&consensus_dl_status[i], now)) {
continue;
}
- /* Check if we're waiting for certificates to download */
- if (check_consensus_waiting_for_certs(i, now, &consensus_dl_status[i]))
+ /** Check if we're waiting for certificates to download. If we are,
+ * launch download for missing directory authority certificates. */
+ if (check_consensus_waiting_for_certs(i, now, &consensus_dl_status[i])) {
+ update_certificate_downloads(now);
continue;
+ }
/* Try the requested attempt */
log_info(LD_DIR, "Launching %s standard networkstatus consensus "
@@ -977,17 +977,9 @@ update_consensus_networkstatus_downloads(time_t now)
static void
update_consensus_bootstrap_attempt_downloads(
time_t now,
- const or_options_t *options,
download_status_t *dls,
download_want_authority_t want_authority)
{
- int use_fallbacks = networkstatus_consensus_can_use_extra_fallbacks(options);
- int max_dl_tries = options->ClientBootstrapConsensusMaxDownloadTries;
- if (!use_fallbacks) {
- max_dl_tries =
- options->ClientBootstrapConsensusAuthorityOnlyMaxDownloadTries;
- }
-
const char *resource = networkstatus_get_flavor_name(
usable_consensus_flavor());
@@ -996,7 +988,7 @@ update_consensus_bootstrap_attempt_downloads(
/* Allow for multiple connections in the same second, if the schedule value
* is 0. */
- while (download_status_is_ready(dls, now, max_dl_tries)) {
+ while (download_status_is_ready(dls, now)) {
log_info(LD_DIR, "Launching %s bootstrap %s networkstatus consensus "
"download.", resource, (want_authority == DL_WANT_AUTHORITY
? "authority"
@@ -1047,7 +1039,7 @@ update_consensus_bootstrap_multiple_downloads(time_t now,
if (!check_consensus_waiting_for_certs(usable_flavor, now, dls_f)) {
/* During bootstrap, DL_WANT_ANY_DIRSERVER means "use fallbacks". */
- update_consensus_bootstrap_attempt_downloads(now, options, dls_f,
+ update_consensus_bootstrap_attempt_downloads(now, dls_f,
DL_WANT_ANY_DIRSERVER);
}
}
@@ -1057,7 +1049,7 @@ update_consensus_bootstrap_multiple_downloads(time_t now,
&consensus_bootstrap_dl_status[CONSENSUS_BOOTSTRAP_SOURCE_AUTHORITY];
if (!check_consensus_waiting_for_certs(usable_flavor, now, dls_a)) {
- update_consensus_bootstrap_attempt_downloads(now, options, dls_a,
+ update_consensus_bootstrap_attempt_downloads(now, dls_a,
DL_WANT_AUTHORITY);
}
}
@@ -1241,16 +1233,20 @@ should_delay_dir_fetches(const or_options_t *options, const char **msg_out)
return 0;
}
-/** Launch requests for networkstatus documents and authority certificates as
- * appropriate. */
+/** Launch requests for networkstatus documents as appropriate. This is called
+ * when we retry all the connections on a SIGHUP and periodically by a Periodic
+ * event which checks whether we want to download any networkstatus documents.
+ */
void
update_networkstatus_downloads(time_t now)
{
const or_options_t *options = get_options();
if (should_delay_dir_fetches(options, NULL))
return;
+ /** Launch a consensus download request, we will wait for the consensus to
+ * download and when it completes we will launch a certificate download
+ * request. */
update_consensus_networkstatus_downloads(now);
- update_certificate_downloads(now);
}
/** Launch requests as appropriate for missing directory authority
@@ -1779,7 +1775,6 @@ networkstatus_set_current_consensus(const char *consensus,
consensus_waiting_for_certs_t *waiting = NULL;
time_t current_valid_after = 0;
int free_consensus = 1; /* Free 'c' at the end of the function */
- int old_ewma_enabled;
int checked_protocols_already = 0;
if (flav < 0) {
@@ -1928,6 +1923,15 @@ networkstatus_set_current_consensus(const char *consensus,
}
}
+ /* Signatures from the consensus are verified */
+ if (from_cache && was_waiting_for_certs) {
+ /* We check if the consensus is loaded from disk cache and that it
+ * it is an unverified consensus. If it is unverified, rename it to
+ * cached-*-consensus since it has been verified. */
+ log_info(LD_DIR, "Unverified consensus signatures verified.");
+ tor_rename(unverified_fname, consensus_fname);
+ }
+
if (!from_cache && flav == usable_consensus_flavor())
control_event_client_status(LOG_NOTICE, "CONSENSUS_ARRIVED");
@@ -2003,17 +2007,8 @@ networkstatus_set_current_consensus(const char *consensus,
/* XXXXNM Microdescs: needs a non-ns variant. ???? NM*/
update_consensus_networkstatus_fetch_time(now);
- /* Update ewma and adjust policy if needed; first cache the old value */
- old_ewma_enabled = cell_ewma_enabled();
/* Change the cell EWMA settings */
- cell_ewma_set_scale_factor(options, c);
- /* If we just enabled ewma, set the cmux policy on all active channels */
- if (cell_ewma_enabled() && !old_ewma_enabled) {
- channel_set_cmux_policy_everywhere(&ewma_policy);
- } else if (!cell_ewma_enabled() && old_ewma_enabled) {
- /* Turn it off everywhere */
- channel_set_cmux_policy_everywhere(NULL);
- }
+ cmux_ewma_set_options(options, c);
/* XXXX this call might be unnecessary here: can changing the
* current consensus really alter our view of any OR's rate limits? */
diff --git a/src/or/nodelist.c b/src/or/nodelist.c
index 40b56f3d1d..71eee3fa21 100644
--- a/src/or/nodelist.c
+++ b/src/or/nodelist.c
@@ -161,8 +161,8 @@ init_nodelist(void)
}
/** As node_get_by_id, but returns a non-const pointer */
-node_t *
-node_get_mutable_by_id(const char *identity_digest)
+MOCK_IMPL(node_t *,
+node_get_mutable_by_id,(const char *identity_digest))
{
node_t search, *node;
if (PREDICT_UNLIKELY(the_nodelist == NULL))
@@ -507,22 +507,22 @@ nodelist_add_microdesc(microdesc_t *md)
if (rs == NULL)
return NULL;
node = node_get_mutable_by_id(rs->identity_digest);
- if (node) {
- node_remove_from_ed25519_map(node);
- if (node->md)
- node->md->held_by_nodes--;
+ if (node == NULL)
+ return NULL;
- node->md = md;
- md->held_by_nodes++;
- /* Setting the HSDir index requires the ed25519 identity key which can
- * only be found either in the ri or md. This is why this is called here.
- * Only nodes supporting HSDir=2 protocol version needs this index. */
- if (rs->pv.supports_v3_hsdir) {
- node_set_hsdir_index(node, ns);
- }
- node_add_to_ed25519_map(node);
- }
+ node_remove_from_ed25519_map(node);
+ if (node->md)
+ node->md->held_by_nodes--;
+ node->md = md;
+ md->held_by_nodes++;
+ /* Setting the HSDir index requires the ed25519 identity key which can
+ * only be found either in the ri or md. This is why this is called here.
+ * Only nodes supporting HSDir=2 protocol version needs this index. */
+ if (rs->pv.supports_v3_hsdir) {
+ node_set_hsdir_index(node, ns);
+ }
+ node_add_to_ed25519_map(node);
node_add_to_address_set(node);
return node;
diff --git a/src/or/nodelist.h b/src/or/nodelist.h
index ff26c8cc76..53b18ab48a 100644
--- a/src/or/nodelist.h
+++ b/src/or/nodelist.h
@@ -16,7 +16,7 @@
tor_assert((n)->ri || (n)->rs); \
} STMT_END
-node_t *node_get_mutable_by_id(const char *identity_digest);
+MOCK_DECL(node_t *, node_get_mutable_by_id,(const char *identity_digest));
MOCK_DECL(const node_t *, node_get_by_id, (const char *identity_digest));
node_t *node_get_mutable_by_ed25519_id(const ed25519_public_key_t *ed_id);
MOCK_DECL(const node_t *, node_get_by_ed25519_id,
diff --git a/src/or/ntmain.c b/src/or/ntmain.c
index ebbe0018bd..e9a299807a 100644
--- a/src/or/ntmain.c
+++ b/src/or/ntmain.c
@@ -24,8 +24,6 @@
#include "main.h"
#include "ntmain.h"
-#include <event2/event.h>
-
#include <windows.h>
#define GENSRV_SERVICENAME "tor"
#define GENSRV_DISPLAYNAME "Tor Win32 Service"
@@ -245,7 +243,8 @@ nt_service_control(DWORD request)
log_notice(LD_GENERAL,
"Got stop/shutdown request; shutting down cleanly.");
service_status.dwCurrentState = SERVICE_STOP_PENDING;
- event_base_loopexit(tor_libevent_get_base(), &exit_now);
+ tor_libevent_exit_loop_after_delay(tor_libevent_get_base(),
+ &exit_now);
return;
}
service_fns.SetServiceStatus_fn(hStatus, &service_status);
diff --git a/src/or/onion_ntor.c b/src/or/onion_ntor.c
index b167cb61fb..8ad876a587 100644
--- a/src/or/onion_ntor.c
+++ b/src/or/onion_ntor.c
@@ -22,6 +22,7 @@
#define ONION_NTOR_PRIVATE
#include "crypto.h"
+#include "crypto_digest.h"
#include "onion_ntor.h"
#include "torlog.h"
#include "util.h"
diff --git a/src/or/or.h b/src/or/or.h
index 502cea0fe2..541b709d89 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -2070,15 +2070,6 @@ typedef enum {
#define download_schedule_increment_bitfield_t \
ENUM_BF(download_schedule_increment_t)
-/** Enumeration: do we want to use the random exponential backoff
- * mechanism? */
-typedef enum {
- DL_SCHED_DETERMINISTIC = 0,
- DL_SCHED_RANDOM_EXPONENTIAL = 1,
-} download_schedule_backoff_t;
-#define download_schedule_backoff_bitfield_t \
- ENUM_BF(download_schedule_backoff_t)
-
/** Information about our plans for retrying downloads for a downloadable
* directory object.
* Each type of downloadable directory object has a corresponding retry
@@ -2125,11 +2116,6 @@ typedef struct download_status_t {
download_schedule_increment_bitfield_t increment_on : 1; /**< does this
* schedule increment on each attempt,
* or after each failure? */
- download_schedule_backoff_bitfield_t backoff : 1; /**< do we use the
- * deterministic schedule, or random
- * exponential backoffs?
- * Increment on failure schedules
- * always use exponential backoff. */
uint8_t last_backoff_position; /**< number of attempts/failures, depending
* on increment_on, when we last recalculated
* the delay. Only updated if backoff
@@ -2357,10 +2343,10 @@ typedef struct routerstatus_t {
* If it's a descriptor, we only use the first DIGEST_LEN bytes. */
char descriptor_digest[DIGEST256_LEN];
uint32_t addr; /**< IPv4 address for this router, in host order. */
- uint16_t or_port; /**< OR port for this router. */
+ uint16_t or_port; /**< IPv4 OR port for this router. */
uint16_t dir_port; /**< Directory port for this router. */
tor_addr_t ipv6_addr; /**< IPv6 address for this router. */
- uint16_t ipv6_orport; /**<IPV6 OR port for this router. */
+ uint16_t ipv6_orport; /**< IPv6 OR port for this router. */
unsigned int is_authority:1; /**< True iff this router is an authority. */
unsigned int is_exit:1; /**< True iff this router is a good exit. */
unsigned int is_stable:1; /**< True iff this router stays up a long time. */
@@ -2913,11 +2899,7 @@ typedef struct {
} u;
} onion_handshake_state_t;
-/** Holds accounting information for a single step in the layered encryption
- * performed by a circuit. Used only at the client edge of a circuit. */
-typedef struct crypt_path_t {
- uint32_t magic;
-
+typedef struct relay_crypto_t {
/* crypto environments */
/** Encryption key and counter for cells heading towards the OR at this
* step. */
@@ -2931,6 +2913,17 @@ typedef struct crypt_path_t {
/** Digest state for cells heading away from the OR at this step. */
crypto_digest_t *b_digest;
+} relay_crypto_t;
+
+/** Holds accounting information for a single step in the layered encryption
+ * performed by a circuit. Used only at the client edge of a circuit. */
+typedef struct crypt_path_t {
+ uint32_t magic;
+
+ /** Cryptographic state used for encrypting and authenticating relay
+ * cells to and from this hop. */
+ relay_crypto_t crypto;
+
/** Current state of the handshake as performed with the OR at this
* step. */
onion_handshake_state_t handshake_state;
@@ -3176,15 +3169,6 @@ typedef struct circuit_t {
/** Index in smartlist of all circuits (global_circuitlist). */
int global_circuitlist_idx;
- /** Next circuit in the doubly-linked ring of circuits waiting to add
- * cells to n_conn. NULL if we have no cells pending, or if we're not
- * linked to an OR connection. */
- struct circuit_t *next_active_on_n_chan;
- /** Previous circuit in the doubly-linked ring of circuits waiting to add
- * cells to n_conn. NULL if we have no cells pending, or if we're not
- * linked to an OR connection. */
- struct circuit_t *prev_active_on_n_chan;
-
/** Various statistics about cells being added to or removed from this
* circuit's queues; used only if CELL_STATS events are enabled and
* cleared after being sent to control port. */
@@ -3464,14 +3448,6 @@ struct onion_queue_t;
typedef struct or_circuit_t {
circuit_t base_;
- /** Next circuit in the doubly-linked ring of circuits waiting to add
- * cells to p_chan. NULL if we have no cells pending, or if we're not
- * linked to an OR connection. */
- struct circuit_t *next_active_on_p_chan;
- /** Previous circuit in the doubly-linked ring of circuits waiting to add
- * cells to p_chan. NULL if we have no cells pending, or if we're not
- * linked to an OR connection. */
- struct circuit_t *prev_active_on_p_chan;
/** Pointer to an entry on the onion queue, if this circuit is waiting for a
* chance to give an onionskin to a cpuworker. Used only in onion.c */
struct onion_queue_t *onionqueue_entry;
@@ -3496,21 +3472,10 @@ typedef struct or_circuit_t {
/** Linked list of Exit streams associated with this circuit that are
* still being resolved. */
edge_connection_t *resolving_streams;
- /** The cipher used by intermediate hops for cells heading toward the
- * OP. */
- crypto_cipher_t *p_crypto;
- /** The cipher used by intermediate hops for cells heading away from
- * the OP. */
- crypto_cipher_t *n_crypto;
-
- /** The integrity-checking digest used by intermediate hops, for
- * cells packaged here and heading towards the OP.
- */
- crypto_digest_t *p_digest;
- /** The integrity-checking digest used by intermediate hops, for
- * cells packaged at the OP and arriving here.
- */
- crypto_digest_t *n_digest;
+
+ /** Cryptographic state used for encrypting and authenticating relay
+ * cells to and from this hop. */
+ relay_crypto_t crypto;
/** Points to spliced circuit if purpose is REND_ESTABLISHED, and circuit
* is not marked for close. */
@@ -4235,10 +4200,6 @@ typedef struct {
* testing our DNS server. */
int EnforceDistinctSubnets; /**< If true, don't allow multiple routers in the
* same network zone in the same circuit. */
- int PortForwarding; /**< If true, use NAT-PMP or UPnP to automatically
- * forward the DirPort and ORPort on the NAT device */
- char *PortForwardingHelper; /** < Filename or full path of the port
- forwarding helper executable */
int AllowNonRFC953Hostnames; /**< If true, we allow connections to hostnames
* with weird characters. */
/** If true, we try resolving hostnames with weird characters. */
@@ -4425,37 +4386,11 @@ typedef struct {
* it? Only altered on testing networks. */
int TestingDirConnectionMaxStall;
- /** How many times will we try to fetch a consensus before we give
- * up? Only altered on testing networks. */
- int TestingConsensusMaxDownloadTries;
-
- /** How many times will a client try to fetch a consensus while
- * bootstrapping using a list of fallback directories, before it gives up?
- * Only altered on testing networks. */
- int ClientBootstrapConsensusMaxDownloadTries;
-
- /** How many times will a client try to fetch a consensus while
- * bootstrapping using only a list of authorities, before it gives up?
- * Only altered on testing networks. */
- int ClientBootstrapConsensusAuthorityOnlyMaxDownloadTries;
-
/** How many simultaneous in-progress connections will we make when trying
* to fetch a consensus before we wait for one to complete, timeout, or
* error out? Only altered on testing networks. */
int ClientBootstrapConsensusMaxInProgressTries;
- /** How many times will we try to download a router's descriptor before
- * giving up? Only altered on testing networks. */
- int TestingDescriptorMaxDownloadTries;
-
- /** How many times will we try to download a microdescriptor before
- * giving up? Only altered on testing networks. */
- int TestingMicrodescMaxDownloadTries;
-
- /** How many times will we try to fetch a certificate before giving
- * up? Only altered on testing networks. */
- int TestingCertMaxDownloadTries;
-
/** If true, we take part in a testing network. Change the defaults of a
* couple of other configuration options and allow to change the values
* of certain configuration options. */
diff --git a/src/or/periodic.c b/src/or/periodic.c
index 6896b41c86..fa40965de1 100644
--- a/src/or/periodic.c
+++ b/src/or/periodic.c
@@ -16,8 +16,6 @@
#include "config.h"
#include "periodic.h"
-#include <event2/event.h>
-
/** We disable any interval greater than this number of seconds, on the
* grounds that it is probably an absolute time mistakenly passed in as a
* relative time.
@@ -34,17 +32,16 @@ periodic_event_set_interval(periodic_event_item_t *event,
struct timeval tv;
tv.tv_sec = next_interval;
tv.tv_usec = 0;
- event_add(event->ev, &tv);
+ mainloop_event_schedule(event->ev, &tv);
}
/** Wraps dispatches for periodic events, <b>data</b> will be a pointer to the
* event that needs to be called */
static void
-periodic_event_dispatch(evutil_socket_t fd, short what, void *data)
+periodic_event_dispatch(mainloop_event_t *ev, void *data)
{
- (void)fd;
- (void)what;
periodic_event_item_t *event = data;
+ tor_assert(ev == event->ev);
time_t now = time(NULL);
const or_options_t *options = get_options();
@@ -74,7 +71,7 @@ periodic_event_dispatch(evutil_socket_t fd, short what, void *data)
// log_debug(LD_GENERAL, "Scheduling %s for %d seconds", event->name,
// next_interval);
struct timeval tv = { next_interval , 0 };
- event_add(event->ev, &tv);
+ mainloop_event_schedule(ev, &tv);
}
/** Schedules <b>event</b> to run as soon as possible from now. */
@@ -93,10 +90,8 @@ periodic_event_setup(periodic_event_item_t *event)
tor_assert(0);
}
- event->ev = tor_event_new(tor_libevent_get_base(),
- -1, 0,
- periodic_event_dispatch,
- event);
+ event->ev = mainloop_event_new(periodic_event_dispatch,
+ event);
tor_assert(event->ev);
}
@@ -111,7 +106,7 @@ periodic_event_launch(periodic_event_item_t *event)
}
// Initial dispatch
- periodic_event_dispatch(-1, EV_TIMEOUT, event);
+ periodic_event_dispatch(event->ev, event);
}
/** Release all storage associated with <b>event</b> */
@@ -120,7 +115,7 @@ periodic_event_destroy(periodic_event_item_t *event)
{
if (!event)
return;
- tor_event_free(event->ev);
+ mainloop_event_free(event->ev);
event->last_action_time = 0;
}
diff --git a/src/or/periodic.h b/src/or/periodic.h
index 8baf3994eb..285400b8bb 100644
--- a/src/or/periodic.h
+++ b/src/or/periodic.h
@@ -14,13 +14,14 @@
typedef int (*periodic_event_helper_t)(time_t now,
const or_options_t *options);
-struct event;
+struct mainloop_event_t;
/** A single item for the periodic-events-function table. */
typedef struct periodic_event_item_t {
periodic_event_helper_t fn; /**< The function to run the event */
time_t last_action_time; /**< The last time the function did something */
- struct event *ev; /**< Libevent callback we're using to implement this */
+ struct mainloop_event_t *ev; /**< Libevent callback we're using to implement
+ * this */
const char *name; /**< Name of the function -- for debug */
} periodic_event_item_t;
diff --git a/src/or/proto_socks.c b/src/or/proto_socks.c
index 91633d02af..8700fe1269 100644
--- a/src/or/proto_socks.c
+++ b/src/or/proto_socks.c
@@ -393,7 +393,7 @@ parse_socks(const char *data, size_t datalen, socks_request_t *req,
req->port = ntohs(get_uint16(data+5+len));
*drain_out = 5+len+2;
- if (!string_is_valid_hostname(req->address)) {
+ if (!string_is_valid_dest(req->address)) {
socks_request_set_socks5_error(req, SOCKS5_GENERAL_ERROR);
log_warn(LD_PROTOCOL,
@@ -518,7 +518,7 @@ parse_socks(const char *data, size_t datalen, socks_request_t *req,
log_debug(LD_APP,"socks4: Everything is here. Success.");
strlcpy(req->address, startaddr ? startaddr : tmpbuf,
sizeof(req->address));
- if (!string_is_valid_hostname(req->address)) {
+ if (!string_is_valid_dest(req->address)) {
log_warn(LD_PROTOCOL,
"Your application (using socks4 to port %d) gave Tor "
"a malformed hostname: %s. Rejecting the connection.",
diff --git a/src/or/protover.c b/src/or/protover.c
index 41b50df87f..6532f09c2f 100644
--- a/src/or/protover.c
+++ b/src/or/protover.c
@@ -106,6 +106,9 @@ proto_entry_free_(proto_entry_t *entry)
tor_free(entry);
}
+/** The largest possible protocol version. */
+#define MAX_PROTOCOL_VERSION (UINT32_MAX-1)
+
/**
* Given a string <b>s</b> and optional end-of-string pointer
* <b>end_of_range</b>, parse the protocol range and store it in
@@ -126,9 +129,14 @@ parse_version_range(const char *s, const char *end_of_range,
if (BUG(!end_of_range))
end_of_range = s + strlen(s); // LCOV_EXCL_LINE
+ /* A range must start with a digit. */
+ if (!TOR_ISDIGIT(*s)) {
+ goto error;
+ }
+
/* Note that this wouldn't be safe if we didn't know that eventually,
* we'd hit a NUL */
- low = (uint32_t) tor_parse_ulong(s, 10, 0, UINT32_MAX, &ok, &next);
+ low = (uint32_t) tor_parse_ulong(s, 10, 0, MAX_PROTOCOL_VERSION, &ok, &next);
if (!ok)
goto error;
if (next > end_of_range)
@@ -141,13 +149,21 @@ parse_version_range(const char *s, const char *end_of_range,
if (*next != '-')
goto error;
s = next+1;
+
/* ibid */
- high = (uint32_t) tor_parse_ulong(s, 10, 0, UINT32_MAX, &ok, &next);
+ if (!TOR_ISDIGIT(*s)) {
+ goto error;
+ }
+ high = (uint32_t) tor_parse_ulong(s, 10, 0,
+ MAX_PROTOCOL_VERSION, &ok, &next);
if (!ok)
goto error;
if (next != end_of_range)
goto error;
+ if (low > high)
+ goto error;
+
done:
*high_out = high;
*low_out = low;
@@ -198,10 +214,6 @@ parse_single_entry(const char *s, const char *end_of_entry)
goto error;
}
- if (range->low > range->high) {
- goto error;
- }
-
s = comma;
while (*s == ',' && s < end_of_entry)
++s;
@@ -596,6 +608,12 @@ protover_compute_vote(const smartlist_t *list_of_proto_strings,
// First, parse the inputs and break them into singleton entries.
SMARTLIST_FOREACH_BEGIN(list_of_proto_strings, const char *, vote) {
smartlist_t *unexpanded = parse_protocol_list(vote);
+ if (! unexpanded) {
+ log_warn(LD_NET, "I failed with parsing a protocol list from "
+ "an authority. The offending string was: %s",
+ escaped(vote));
+ continue;
+ }
smartlist_t *this_vote = expand_protocol_list(unexpanded);
if (this_vote == NULL) {
log_warn(LD_NET, "When expanding a protocol list from an authority, I "
@@ -653,15 +671,23 @@ int
protover_all_supported(const char *s, char **missing_out)
{
int all_supported = 1;
- smartlist_t *missing;
+ smartlist_t *missing_some;
+ smartlist_t *missing_completely;
+ smartlist_t *missing_all;
if (!s) {
return 1;
}
smartlist_t *entries = parse_protocol_list(s);
+ if (BUG(entries == NULL)) {
+ log_warn(LD_NET, "Received an unparseable protocol list %s"
+ " from the consensus", escaped(s));
+ return 1;
+ }
- missing = smartlist_new();
+ missing_some = smartlist_new();
+ missing_completely = smartlist_new();
SMARTLIST_FOREACH_BEGIN(entries, const proto_entry_t *, ent) {
protocol_type_t tp;
@@ -673,26 +699,86 @@ protover_all_supported(const char *s, char **missing_out)
}
SMARTLIST_FOREACH_BEGIN(ent->ranges, const proto_range_t *, range) {
+ proto_entry_t *unsupported = tor_malloc_zero(sizeof(proto_entry_t));
+ proto_range_t *versions = tor_malloc_zero(sizeof(proto_range_t));
uint32_t i;
+
+ unsupported->name = tor_strdup(ent->name);
+ unsupported->ranges = smartlist_new();
+
for (i = range->low; i <= range->high; ++i) {
if (!protover_is_supported_here(tp, i)) {
- goto unsupported;
+ if (versions->low == 0 && versions->high == 0) {
+ versions->low = i;
+ /* Pre-emptively add the high now, just in case we're in a single
+ * version range (e.g. "Link=999"). */
+ versions->high = i;
+ }
+ /* If the last one to be unsupported is one less than the current
+ * one, we're in a continous range, so set the high field. */
+ if ((versions->high && versions->high == i - 1) ||
+ /* Similarly, if the last high wasn't set and we're currently
+ * one higher than the low, add current index as the highest
+ * known high. */
+ (!versions->high && versions->low == i - 1)) {
+ versions->high = i;
+ continue;
+ }
+ } else {
+ /* If we hit a supported version, and we previously had a range,
+ * we've hit a non-continuity. Copy the previous range and add it to
+ * the unsupported->ranges list and zero-out the previous range for
+ * the next iteration. */
+ if (versions->low != 0 && versions->high != 0) {
+ proto_range_t *versions_to_add = tor_malloc(sizeof(proto_range_t));
+
+ versions_to_add->low = versions->low;
+ versions_to_add->high = versions->high;
+ smartlist_add(unsupported->ranges, versions_to_add);
+
+ versions->low = 0;
+ versions->high = 0;
+ }
}
}
+ /* Once we've run out of versions to check, see if we had any unsupported
+ * ones and, if so, add them to unsupported->ranges. */
+ if (versions->low != 0 && versions->high != 0) {
+ smartlist_add(unsupported->ranges, versions);
+ }
+ /* Finally, if we had something unsupported, add it to the list of
+ * missing_some things and mark that there was something missing. */
+ if (smartlist_len(unsupported->ranges) != 0) {
+ smartlist_add(missing_some, (void*) unsupported);
+ all_supported = 0;
+ } else {
+ proto_entry_free(unsupported);
+ tor_free(versions);
+ }
} SMARTLIST_FOREACH_END(range);
continue;
unsupported:
all_supported = 0;
- smartlist_add(missing, (void*) ent);
+ smartlist_add(missing_completely, (void*) ent);
} SMARTLIST_FOREACH_END(ent);
+ /* We keep the two smartlists separate so that we can free the proto_entry_t
+ * we created and put in missing_some, so here we add them together to build
+ * the string. */
+ missing_all = smartlist_new();
+ smartlist_add_all(missing_all, missing_some);
+ smartlist_add_all(missing_all, missing_completely);
+
if (missing_out && !all_supported) {
- tor_assert(0 != smartlist_len(missing));
- *missing_out = encode_protocol_list(missing);
+ tor_assert(smartlist_len(missing_all) != 0);
+ *missing_out = encode_protocol_list(missing_all);
}
- smartlist_free(missing);
+ SMARTLIST_FOREACH(missing_some, proto_entry_t *, ent, proto_entry_free(ent));
+ smartlist_free(missing_some);
+ smartlist_free(missing_completely);
+ smartlist_free(missing_all);
SMARTLIST_FOREACH(entries, proto_entry_t *, ent, proto_entry_free(ent));
smartlist_free(entries);
diff --git a/src/or/relay.c b/src/or/relay.c
index 7c21839a86..c6f030945b 100644
--- a/src/or/relay.c
+++ b/src/or/relay.c
@@ -70,6 +70,7 @@
#include "policies.h"
#include "reasons.h"
#include "relay.h"
+#include "relay_crypto.h"
#include "rendcache.h"
#include "rendcommon.h"
#include "router.h"
@@ -122,79 +123,6 @@ uint64_t stats_n_relay_cells_delivered = 0;
/** Used to tell which stream to read from first on a circuit. */
static tor_weak_rng_t stream_choice_rng = TOR_WEAK_RNG_INIT;
-/** Update digest from the payload of cell. Assign integrity part to
- * cell.
- */
-static void
-relay_set_digest(crypto_digest_t *digest, cell_t *cell)
-{
- char integrity[4];
- relay_header_t rh;
-
- crypto_digest_add_bytes(digest, (char*)cell->payload, CELL_PAYLOAD_SIZE);
- crypto_digest_get_digest(digest, integrity, 4);
-// log_fn(LOG_DEBUG,"Putting digest of %u %u %u %u into relay cell.",
-// integrity[0], integrity[1], integrity[2], integrity[3]);
- relay_header_unpack(&rh, cell->payload);
- memcpy(rh.integrity, integrity, 4);
- relay_header_pack(cell->payload, &rh);
-}
-
-/** Does the digest for this circuit indicate that this cell is for us?
- *
- * Update digest from the payload of cell (with the integrity part set
- * to 0). If the integrity part is valid, return 1, else restore digest
- * and cell to their original state and return 0.
- */
-static int
-relay_digest_matches(crypto_digest_t *digest, cell_t *cell)
-{
- uint32_t received_integrity, calculated_integrity;
- relay_header_t rh;
- crypto_digest_checkpoint_t backup_digest;
-
- crypto_digest_checkpoint(&backup_digest, digest);
-
- relay_header_unpack(&rh, cell->payload);
- memcpy(&received_integrity, rh.integrity, 4);
- memset(rh.integrity, 0, 4);
- relay_header_pack(cell->payload, &rh);
-
-// log_fn(LOG_DEBUG,"Reading digest of %u %u %u %u from relay cell.",
-// received_integrity[0], received_integrity[1],
-// received_integrity[2], received_integrity[3]);
-
- crypto_digest_add_bytes(digest, (char*) cell->payload, CELL_PAYLOAD_SIZE);
- crypto_digest_get_digest(digest, (char*) &calculated_integrity, 4);
-
- int rv = 1;
-
- if (calculated_integrity != received_integrity) {
-// log_fn(LOG_INFO,"Recognized=0 but bad digest. Not recognizing.");
-// (%d vs %d).", received_integrity, calculated_integrity);
- /* restore digest to its old form */
- crypto_digest_restore(digest, &backup_digest);
- /* restore the relay header */
- memcpy(rh.integrity, &received_integrity, 4);
- relay_header_pack(cell->payload, &rh);
- rv = 0;
- }
-
- memwipe(&backup_digest, 0, sizeof(backup_digest));
- return rv;
-}
-
-/** Apply <b>cipher</b> to CELL_PAYLOAD_SIZE bytes of <b>in</b>
- * (in place).
- *
- * Note that we use the same operation for encrypting and for decrypting.
- */
-static void
-relay_crypt_one_payload(crypto_cipher_t *cipher, uint8_t *in)
-{
- crypto_cipher_crypt_inplace(cipher, (char*) in, CELL_PAYLOAD_SIZE);
-}
-
/**
* Update channel usage state based on the type of relay cell and
* circuit properties.
@@ -299,7 +227,8 @@ circuit_receive_relay_cell(cell_t *cell, circuit_t *circ,
if (circ->marked_for_close)
return 0;
- if (relay_crypt(circ, cell, cell_direction, &layer_hint, &recognized) < 0) {
+ if (relay_decrypt_cell(circ, cell, cell_direction, &layer_hint, &recognized)
+ < 0) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"relay crypt failed. Dropping connection.");
return -END_CIRC_REASON_INTERNAL;
@@ -404,87 +333,6 @@ circuit_receive_relay_cell(cell_t *cell, circuit_t *circ,
return 0;
}
-/** Do the appropriate en/decryptions for <b>cell</b> arriving on
- * <b>circ</b> in direction <b>cell_direction</b>.
- *
- * If cell_direction == CELL_DIRECTION_IN:
- * - If we're at the origin (we're the OP), for hops 1..N,
- * decrypt cell. If recognized, stop.
- * - Else (we're not the OP), encrypt one hop. Cell is not recognized.
- *
- * If cell_direction == CELL_DIRECTION_OUT:
- * - decrypt one hop. Check if recognized.
- *
- * If cell is recognized, set *recognized to 1, and set
- * *layer_hint to the hop that recognized it.
- *
- * Return -1 to indicate that we should mark the circuit for close,
- * else return 0.
- */
-int
-relay_crypt(circuit_t *circ, cell_t *cell, cell_direction_t cell_direction,
- crypt_path_t **layer_hint, char *recognized)
-{
- relay_header_t rh;
-
- tor_assert(circ);
- tor_assert(cell);
- tor_assert(recognized);
- tor_assert(cell_direction == CELL_DIRECTION_IN ||
- cell_direction == CELL_DIRECTION_OUT);
-
- if (cell_direction == CELL_DIRECTION_IN) {
- if (CIRCUIT_IS_ORIGIN(circ)) { /* We're at the beginning of the circuit.
- * We'll want to do layered decrypts. */
- crypt_path_t *thishop, *cpath = TO_ORIGIN_CIRCUIT(circ)->cpath;
- thishop = cpath;
- if (thishop->state != CPATH_STATE_OPEN) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Relay cell before first created cell? Closing.");
- return -1;
- }
- do { /* Remember: cpath is in forward order, that is, first hop first. */
- tor_assert(thishop);
-
- /* decrypt one layer */
- relay_crypt_one_payload(thishop->b_crypto, cell->payload);
-
- relay_header_unpack(&rh, cell->payload);
- if (rh.recognized == 0) {
- /* it's possibly recognized. have to check digest to be sure. */
- if (relay_digest_matches(thishop->b_digest, cell)) {
- *recognized = 1;
- *layer_hint = thishop;
- return 0;
- }
- }
-
- thishop = thishop->next;
- } while (thishop != cpath && thishop->state == CPATH_STATE_OPEN);
- log_fn(LOG_PROTOCOL_WARN, LD_OR,
- "Incoming cell at client not recognized. Closing.");
- return -1;
- } else {
- /* We're in the middle. Encrypt one layer. */
- relay_crypt_one_payload(TO_OR_CIRCUIT(circ)->p_crypto, cell->payload);
- }
- } else /* cell_direction == CELL_DIRECTION_OUT */ {
- /* We're in the middle. Decrypt one layer. */
-
- relay_crypt_one_payload(TO_OR_CIRCUIT(circ)->n_crypto, cell->payload);
-
- relay_header_unpack(&rh, cell->payload);
- if (rh.recognized == 0) {
- /* it's possibly recognized. have to check digest to be sure. */
- if (relay_digest_matches(TO_OR_CIRCUIT(circ)->n_digest, cell)) {
- *recognized = 1;
- return 0;
- }
- }
- }
- return 0;
-}
-
/** Package a relay cell from an edge:
* - Encrypt it to the right layer
* - Append it to the appropriate cell_queue on <b>circ</b>.
@@ -503,7 +351,6 @@ circuit_package_relay_cell(cell_t *cell, circuit_t *circ,
}
if (cell_direction == CELL_DIRECTION_OUT) {
- crypt_path_t *thishop; /* counter for repeated crypts */
chan = circ->n_chan;
if (!chan) {
log_warn(LD_BUG,"outgoing relay cell sent from %s:%d has n_chan==NULL."
@@ -526,20 +373,8 @@ circuit_package_relay_cell(cell_t *cell, circuit_t *circ,
return 0; /* just drop it */
}
- relay_set_digest(layer_hint->f_digest, cell);
-
- thishop = layer_hint;
- /* moving from farthest to nearest hop */
- do {
- tor_assert(thishop);
- log_debug(LD_OR,"encrypting a layer of the relay cell.");
- relay_crypt_one_payload(thishop->f_crypto, cell->payload);
-
- thishop = thishop->prev;
- } while (thishop != TO_ORIGIN_CIRCUIT(circ)->cpath->prev);
-
+ relay_encrypt_cell_outbound(cell, TO_ORIGIN_CIRCUIT(circ), layer_hint);
} else { /* incoming cell */
- or_circuit_t *or_circ;
if (CIRCUIT_IS_ORIGIN(circ)) {
/* We should never package an _incoming_ cell from the circuit
* origin; that means we messed up somewhere. */
@@ -547,11 +382,9 @@ circuit_package_relay_cell(cell_t *cell, circuit_t *circ,
assert_circuit_ok(circ);
return 0; /* just drop it */
}
- or_circ = TO_OR_CIRCUIT(circ);
+ or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
+ relay_encrypt_cell_inbound(cell, or_circ);
chan = or_circ->p_chan;
- relay_set_digest(or_circ->p_digest, cell);
- /* encrypt one layer */
- relay_crypt_one_payload(or_circ->p_crypto, cell->payload);
}
++stats_n_relay_cells_relayed;
@@ -2399,13 +2232,6 @@ circuit_consider_sending_sendme(circuit_t *circ, crypt_path_t *layer_hint)
}
}
-#ifdef ACTIVE_CIRCUITS_PARANOIA
-#define assert_cmux_ok_paranoid(chan) \
- assert_circuit_mux_okay(chan)
-#else
-#define assert_cmux_ok_paranoid(chan)
-#endif /* defined(ACTIVE_CIRCUITS_PARANOIA) */
-
/** The total number of cells we have allocated. */
static size_t total_cells_allocated = 0;
@@ -2693,16 +2519,12 @@ update_circuit_on_cmux_(circuit_t *circ, cell_direction_t direction,
}
tor_assert(circuitmux_attached_circuit_direction(cmux, circ) == direction);
- assert_cmux_ok_paranoid(chan);
-
/* Update the number of cells we have for the circuit mux */
if (direction == CELL_DIRECTION_OUT) {
circuitmux_set_num_cells(cmux, circ, circ->n_chan_cells.n);
} else {
circuitmux_set_num_cells(cmux, circ, or_circ->p_chan_cells.n);
}
-
- assert_cmux_ok_paranoid(chan);
}
/** Remove all circuits from the cmux on <b>chan</b>.
@@ -2847,7 +2669,6 @@ channel_flush_from_first_active_circuit, (channel_t *chan, int max))
}
/* If it returns NULL, no cells left to send */
if (!circ) break;
- assert_cmux_ok_paranoid(chan);
if (circ->n_chan == chan) {
queue = &circ->n_chan_cells;
@@ -2951,15 +2772,13 @@ channel_flush_from_first_active_circuit, (channel_t *chan, int max))
}
/* Okay, we're done sending now */
- assert_cmux_ok_paranoid(chan);
-
return n_flushed;
}
/** Add <b>cell</b> to the queue of <b>circ</b> writing to <b>chan</b>
* transmitting in <b>direction</b>.
*
- * The given <b>cell</b> is copied over the circuit queue so the caller must
+ * The given <b>cell</b> is copied onto the circuit queue so the caller must
* cleanup the memory.
*
* This function is part of the fast path. */
@@ -3103,17 +2922,6 @@ circuit_clear_cell_queue(circuit_t *circ, channel_t *chan)
update_circuit_on_cmux(circ, direction);
}
-/** Fail with an assert if the circuit mux on chan is corrupt
- */
-void
-assert_circuit_mux_okay(channel_t *chan)
-{
- tor_assert(chan);
- tor_assert(chan->cmux);
-
- circuitmux_assert_okay(chan->cmux);
-}
-
/** Return 1 if we shouldn't restart reading on this circuit, even if
* we get a SENDME. Else return 0.
*/
diff --git a/src/or/relay.h b/src/or/relay.h
index f0fa7e9870..cc78758883 100644
--- a/src/or/relay.h
+++ b/src/or/relay.h
@@ -76,7 +76,6 @@ void destroy_cell_queue_append(destroy_cell_queue_t *queue,
void channel_unlink_all_circuits(channel_t *chan, smartlist_t *detached_out);
MOCK_DECL(int, channel_flush_from_first_active_circuit,
(channel_t *chan, int max));
-void assert_circuit_mux_okay(channel_t *chan);
void update_circuit_on_cmux_(circuit_t *circ, cell_direction_t direction,
const char *file, int lineno);
#define update_circuit_on_cmux(circ, direction) \
@@ -90,9 +89,6 @@ void circuit_clear_cell_queue(circuit_t *circ, channel_t *chan);
void stream_choice_seed_weak_rng(void);
-int relay_crypt(circuit_t *circ, cell_t *cell, cell_direction_t cell_direction,
- crypt_path_t **layer_hint, char *recognized);
-
circid_t packed_cell_get_circid(const packed_cell_t *cell, int wide_circ_ids);
#ifdef RELAY_PRIVATE
diff --git a/src/or/relay_crypto.c b/src/or/relay_crypto.c
new file mode 100644
index 0000000000..c42a4f9cca
--- /dev/null
+++ b/src/or/relay_crypto.c
@@ -0,0 +1,326 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "or.h"
+#include "config.h"
+#include "hs_ntor.h" // for HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN
+#include "relay_crypto.h"
+#include "relay.h"
+
+/** Update digest from the payload of cell. Assign integrity part to
+ * cell.
+ */
+static void
+relay_set_digest(crypto_digest_t *digest, cell_t *cell)
+{
+ char integrity[4];
+ relay_header_t rh;
+
+ crypto_digest_add_bytes(digest, (char*)cell->payload, CELL_PAYLOAD_SIZE);
+ crypto_digest_get_digest(digest, integrity, 4);
+// log_fn(LOG_DEBUG,"Putting digest of %u %u %u %u into relay cell.",
+// integrity[0], integrity[1], integrity[2], integrity[3]);
+ relay_header_unpack(&rh, cell->payload);
+ memcpy(rh.integrity, integrity, 4);
+ relay_header_pack(cell->payload, &rh);
+}
+
+/** Does the digest for this circuit indicate that this cell is for us?
+ *
+ * Update digest from the payload of cell (with the integrity part set
+ * to 0). If the integrity part is valid, return 1, else restore digest
+ * and cell to their original state and return 0.
+ */
+static int
+relay_digest_matches(crypto_digest_t *digest, cell_t *cell)
+{
+ uint32_t received_integrity, calculated_integrity;
+ relay_header_t rh;
+ crypto_digest_checkpoint_t backup_digest;
+
+ crypto_digest_checkpoint(&backup_digest, digest);
+
+ relay_header_unpack(&rh, cell->payload);
+ memcpy(&received_integrity, rh.integrity, 4);
+ memset(rh.integrity, 0, 4);
+ relay_header_pack(cell->payload, &rh);
+
+// log_fn(LOG_DEBUG,"Reading digest of %u %u %u %u from relay cell.",
+// received_integrity[0], received_integrity[1],
+// received_integrity[2], received_integrity[3]);
+
+ crypto_digest_add_bytes(digest, (char*) cell->payload, CELL_PAYLOAD_SIZE);
+ crypto_digest_get_digest(digest, (char*) &calculated_integrity, 4);
+
+ int rv = 1;
+
+ if (calculated_integrity != received_integrity) {
+// log_fn(LOG_INFO,"Recognized=0 but bad digest. Not recognizing.");
+// (%d vs %d).", received_integrity, calculated_integrity);
+ /* restore digest to its old form */
+ crypto_digest_restore(digest, &backup_digest);
+ /* restore the relay header */
+ memcpy(rh.integrity, &received_integrity, 4);
+ relay_header_pack(cell->payload, &rh);
+ rv = 0;
+ }
+
+ memwipe(&backup_digest, 0, sizeof(backup_digest));
+ return rv;
+}
+
+/** Apply <b>cipher</b> to CELL_PAYLOAD_SIZE bytes of <b>in</b>
+ * (in place).
+ *
+ * Note that we use the same operation for encrypting and for decrypting.
+ */
+static void
+relay_crypt_one_payload(crypto_cipher_t *cipher, uint8_t *in)
+{
+ crypto_cipher_crypt_inplace(cipher, (char*) in, CELL_PAYLOAD_SIZE);
+}
+
+/** Do the appropriate en/decryptions for <b>cell</b> arriving on
+ * <b>circ</b> in direction <b>cell_direction</b>.
+ *
+ * If cell_direction == CELL_DIRECTION_IN:
+ * - If we're at the origin (we're the OP), for hops 1..N,
+ * decrypt cell. If recognized, stop.
+ * - Else (we're not the OP), encrypt one hop. Cell is not recognized.
+ *
+ * If cell_direction == CELL_DIRECTION_OUT:
+ * - decrypt one hop. Check if recognized.
+ *
+ * If cell is recognized, set *recognized to 1, and set
+ * *layer_hint to the hop that recognized it.
+ *
+ * Return -1 to indicate that we should mark the circuit for close,
+ * else return 0.
+ */
+int
+relay_decrypt_cell(circuit_t *circ, cell_t *cell,
+ cell_direction_t cell_direction,
+ crypt_path_t **layer_hint, char *recognized)
+{
+ relay_header_t rh;
+
+ tor_assert(circ);
+ tor_assert(cell);
+ tor_assert(recognized);
+ tor_assert(cell_direction == CELL_DIRECTION_IN ||
+ cell_direction == CELL_DIRECTION_OUT);
+
+ if (cell_direction == CELL_DIRECTION_IN) {
+ if (CIRCUIT_IS_ORIGIN(circ)) { /* We're at the beginning of the circuit.
+ * We'll want to do layered decrypts. */
+ crypt_path_t *thishop, *cpath = TO_ORIGIN_CIRCUIT(circ)->cpath;
+ thishop = cpath;
+ if (thishop->state != CPATH_STATE_OPEN) {
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Relay cell before first created cell? Closing.");
+ return -1;
+ }
+ do { /* Remember: cpath is in forward order, that is, first hop first. */
+ tor_assert(thishop);
+
+ /* decrypt one layer */
+ relay_crypt_one_payload(thishop->crypto.b_crypto, cell->payload);
+
+ relay_header_unpack(&rh, cell->payload);
+ if (rh.recognized == 0) {
+ /* it's possibly recognized. have to check digest to be sure. */
+ if (relay_digest_matches(thishop->crypto.b_digest, cell)) {
+ *recognized = 1;
+ *layer_hint = thishop;
+ return 0;
+ }
+ }
+
+ thishop = thishop->next;
+ } while (thishop != cpath && thishop->state == CPATH_STATE_OPEN);
+ log_fn(LOG_PROTOCOL_WARN, LD_OR,
+ "Incoming cell at client not recognized. Closing.");
+ return -1;
+ } else {
+ relay_crypto_t *crypto = &TO_OR_CIRCUIT(circ)->crypto;
+ /* We're in the middle. Encrypt one layer. */
+ relay_crypt_one_payload(crypto->b_crypto, cell->payload);
+ }
+ } else /* cell_direction == CELL_DIRECTION_OUT */ {
+ /* We're in the middle. Decrypt one layer. */
+ relay_crypto_t *crypto = &TO_OR_CIRCUIT(circ)->crypto;
+
+ relay_crypt_one_payload(crypto->f_crypto, cell->payload);
+
+ relay_header_unpack(&rh, cell->payload);
+ if (rh.recognized == 0) {
+ /* it's possibly recognized. have to check digest to be sure. */
+ if (relay_digest_matches(crypto->f_digest, cell)) {
+ *recognized = 1;
+ return 0;
+ }
+ }
+ }
+ return 0;
+}
+
+/**
+ * Encrypt a cell <b>cell</b> that we are creating, and sending outbound on
+ * <b>circ</b> until the hop corresponding to <b>layer_hint</b>.
+ *
+ * The integrity field and recognized field of <b>cell</b>'s relay headers
+ * must be set to zero.
+ */
+void
+relay_encrypt_cell_outbound(cell_t *cell,
+ origin_circuit_t *circ,
+ crypt_path_t *layer_hint)
+{
+ crypt_path_t *thishop; /* counter for repeated crypts */
+ relay_set_digest(layer_hint->crypto.f_digest, cell);
+
+ thishop = layer_hint;
+ /* moving from farthest to nearest hop */
+ do {
+ tor_assert(thishop);
+ log_debug(LD_OR,"encrypting a layer of the relay cell.");
+ relay_crypt_one_payload(thishop->crypto.f_crypto, cell->payload);
+
+ thishop = thishop->prev;
+ } while (thishop != circ->cpath->prev);
+}
+
+/**
+ * Encrypt a cell <b>cell</b> that we are creating, and sending on
+ * <b>circuit</b> to the origin.
+ *
+ * The integrity field and recognized field of <b>cell</b>'s relay headers
+ * must be set to zero.
+ */
+void
+relay_encrypt_cell_inbound(cell_t *cell,
+ or_circuit_t *or_circ)
+{
+ relay_set_digest(or_circ->crypto.b_digest, cell);
+ /* encrypt one layer */
+ relay_crypt_one_payload(or_circ->crypto.b_crypto, cell->payload);
+}
+
+/**
+ * Release all storage held inside <b>crypto</b>, but do not free
+ * <b>crypto</b> itself: it lives inside another object.
+ */
+void
+relay_crypto_clear(relay_crypto_t *crypto)
+{
+ if (BUG(!crypto))
+ return;
+ crypto_cipher_free(crypto->f_crypto);
+ crypto_cipher_free(crypto->b_crypto);
+ crypto_digest_free(crypto->f_digest);
+ crypto_digest_free(crypto->b_digest);
+}
+
+/** Initialize <b>crypto</b> from the key material in key_data.
+ *
+ * If <b>is_hs_v3</b> is set, this cpath will be used for next gen hidden
+ * service circuits and <b>key_data</b> must be at least
+ * HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN bytes in length.
+ *
+ * If <b>is_hs_v3</b> is not set, key_data must contain CPATH_KEY_MATERIAL_LEN
+ * bytes, which are used as follows:
+ * - 20 to initialize f_digest
+ * - 20 to initialize b_digest
+ * - 16 to key f_crypto
+ * - 16 to key b_crypto
+ *
+ * (If 'reverse' is true, then f_XX and b_XX are swapped.)
+ *
+ * Return 0 if init was successful, else -1 if it failed.
+ */
+int
+relay_crypto_init(relay_crypto_t *crypto,
+ const char *key_data, size_t key_data_len,
+ int reverse, int is_hs_v3)
+{
+ crypto_digest_t *tmp_digest;
+ crypto_cipher_t *tmp_crypto;
+ size_t digest_len = 0;
+ size_t cipher_key_len = 0;
+
+ tor_assert(crypto);
+ tor_assert(key_data);
+ tor_assert(!(crypto->f_crypto || crypto->b_crypto ||
+ crypto->f_digest || crypto->b_digest));
+
+ /* Basic key size validation */
+ if (is_hs_v3 && BUG(key_data_len != HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN)) {
+ goto err;
+ } else if (!is_hs_v3 && BUG(key_data_len != CPATH_KEY_MATERIAL_LEN)) {
+ goto err;
+ }
+
+ /* If we are using this crypto for next gen onion services use SHA3-256,
+ otherwise use good ol' SHA1 */
+ if (is_hs_v3) {
+ digest_len = DIGEST256_LEN;
+ cipher_key_len = CIPHER256_KEY_LEN;
+ crypto->f_digest = crypto_digest256_new(DIGEST_SHA3_256);
+ crypto->b_digest = crypto_digest256_new(DIGEST_SHA3_256);
+ } else {
+ digest_len = DIGEST_LEN;
+ cipher_key_len = CIPHER_KEY_LEN;
+ crypto->f_digest = crypto_digest_new();
+ crypto->b_digest = crypto_digest_new();
+ }
+
+ tor_assert(digest_len != 0);
+ tor_assert(cipher_key_len != 0);
+ const int cipher_key_bits = (int) cipher_key_len * 8;
+
+ crypto_digest_add_bytes(crypto->f_digest, key_data, digest_len);
+ crypto_digest_add_bytes(crypto->b_digest, key_data+digest_len, digest_len);
+
+ crypto->f_crypto = crypto_cipher_new_with_bits(key_data+(2*digest_len),
+ cipher_key_bits);
+ if (!crypto->f_crypto) {
+ log_warn(LD_BUG,"Forward cipher initialization failed.");
+ goto err;
+ }
+
+ crypto->b_crypto = crypto_cipher_new_with_bits(
+ key_data+(2*digest_len)+cipher_key_len,
+ cipher_key_bits);
+ if (!crypto->b_crypto) {
+ log_warn(LD_BUG,"Backward cipher initialization failed.");
+ goto err;
+ }
+
+ if (reverse) {
+ tmp_digest = crypto->f_digest;
+ crypto->f_digest = crypto->b_digest;
+ crypto->b_digest = tmp_digest;
+ tmp_crypto = crypto->f_crypto;
+ crypto->f_crypto = crypto->b_crypto;
+ crypto->b_crypto = tmp_crypto;
+ }
+
+ return 0;
+ err:
+ relay_crypto_clear(crypto);
+ return -1;
+}
+
+/** Assert that <b>crypto</b> is valid and set. */
+void
+relay_crypto_assert_ok(const relay_crypto_t *crypto)
+{
+ tor_assert(crypto->f_crypto);
+ tor_assert(crypto->b_crypto);
+ tor_assert(crypto->f_digest);
+ tor_assert(crypto->b_digest);
+}
+
diff --git a/src/or/relay_crypto.h b/src/or/relay_crypto.h
new file mode 100644
index 0000000000..66ae02cee9
--- /dev/null
+++ b/src/or/relay_crypto.h
@@ -0,0 +1,31 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file relay.h
+ * \brief Header file for relay.c.
+ **/
+
+#ifndef TOR_RELAY_CRYPTO_H
+#define TOR_RELAY_CRYPTO_H
+
+int relay_crypto_init(relay_crypto_t *crypto,
+ const char *key_data, size_t key_data_len,
+ int reverse, int is_hs_v3);
+
+int relay_decrypt_cell(circuit_t *circ, cell_t *cell,
+ cell_direction_t cell_direction,
+ crypt_path_t **layer_hint, char *recognized);
+void relay_encrypt_cell_outbound(cell_t *cell, origin_circuit_t *or_circ,
+ crypt_path_t *layer_hint);
+void relay_encrypt_cell_inbound(cell_t *cell, or_circuit_t *or_circ);
+
+void relay_crypto_clear(relay_crypto_t *crypto);
+
+void relay_crypto_assert_ok(const relay_crypto_t *crypto);
+
+#endif /* !defined(TOR_RELAY_CRYPTO_H) */
+
diff --git a/src/or/router.c b/src/or/router.c
index 991c7138c8..e5996f665e 100644
--- a/src/or/router.c
+++ b/src/or/router.c
@@ -103,6 +103,13 @@ static authority_cert_t *legacy_key_certificate = NULL;
* used by tor-gencert to sign new signing keys and make new key
* certificates. */
+const char *format_node_description(char *buf,
+ const char *id_digest,
+ int is_named,
+ const char *nickname,
+ const tor_addr_t *addr,
+ uint32_t addr32h);
+
/** Replace the current onion key with <b>k</b>. Does not affect
* lastonionkey; to update lastonionkey correctly, call rotate_onion_key().
*/
@@ -3453,6 +3460,15 @@ is_legal_hexdigest(const char *s)
strspn(s,HEX_CHARACTERS)==HEX_DIGEST_LEN);
}
+/**
+ * Longest allowed output of format_node_description, plus 1 character for
+ * NUL. This allows space for:
+ * "$FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF~xxxxxxxxxxxxxxxxxxx at"
+ * " [ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255]"
+ * plus a terminating NUL.
+ */
+#define NODE_DESC_BUF_LEN (MAX_VERBOSE_NICKNAME_LEN+4+TOR_ADDR_BUF_LEN)
+
/** Use <b>buf</b> (which must be at least NODE_DESC_BUF_LEN bytes long) to
* hold a human-readable description of a node with identity digest
* <b>id_digest</b>, named-status <b>is_named</b>, nickname <b>nickname</b>,
@@ -3498,15 +3514,16 @@ format_node_description(char *buf,
return buf;
}
-/** Use <b>buf</b> (which must be at least NODE_DESC_BUF_LEN bytes long) to
- * hold a human-readable description of <b>ri</b>.
- *
+/** Return a human-readable description of the routerinfo_t <b>ri</b>.
*
- * Return a pointer to the front of <b>buf</b>.
+ * This function is not thread-safe. Each call to this function invalidates
+ * previous values returned by this function.
*/
const char *
-router_get_description(char *buf, const routerinfo_t *ri)
+router_describe(const routerinfo_t *ri)
{
+ static char buf[NODE_DESC_BUF_LEN];
+
if (!ri)
return "<null>";
return format_node_description(buf,
@@ -3517,14 +3534,15 @@ router_get_description(char *buf, const routerinfo_t *ri)
ri->addr);
}
-/** Use <b>buf</b> (which must be at least NODE_DESC_BUF_LEN bytes long) to
- * hold a human-readable description of <b>node</b>.
+/** Return a human-readable description of the node_t <b>node</b>.
*
- * Return a pointer to the front of <b>buf</b>.
+ * This function is not thread-safe. Each call to this function invalidates
+ * previous values returned by this function.
*/
const char *
-node_get_description(char *buf, const node_t *node)
+node_describe(const node_t *node)
{
+ static char buf[NODE_DESC_BUF_LEN];
const char *nickname = NULL;
uint32_t addr32h = 0;
int is_named = 0;
@@ -3549,14 +3567,16 @@ node_get_description(char *buf, const node_t *node)
addr32h);
}
-/** Use <b>buf</b> (which must be at least NODE_DESC_BUF_LEN bytes long) to
- * hold a human-readable description of <b>rs</b>.
+/** Return a human-readable description of the routerstatus_t <b>rs</b>.
*
- * Return a pointer to the front of <b>buf</b>.
+ * This function is not thread-safe. Each call to this function invalidates
+ * previous values returned by this function.
*/
const char *
-routerstatus_get_description(char *buf, const routerstatus_t *rs)
+routerstatus_describe(const routerstatus_t *rs)
{
+ static char buf[NODE_DESC_BUF_LEN];
+
if (!rs)
return "<null>";
return format_node_description(buf,
@@ -3567,14 +3587,16 @@ routerstatus_get_description(char *buf, const routerstatus_t *rs)
rs->addr);
}
-/** Use <b>buf</b> (which must be at least NODE_DESC_BUF_LEN bytes long) to
- * hold a human-readable description of <b>ei</b>.
+/** Return a human-readable description of the extend_info_t <b>ei</b>.
*
- * Return a pointer to the front of <b>buf</b>.
+ * This function is not thread-safe. Each call to this function invalidates
+ * previous values returned by this function.
*/
const char *
-extend_info_get_description(char *buf, const extend_info_t *ei)
+extend_info_describe(const extend_info_t *ei)
{
+ static char buf[NODE_DESC_BUF_LEN];
+
if (!ei)
return "<null>";
return format_node_description(buf,
@@ -3585,54 +3607,6 @@ extend_info_get_description(char *buf, const extend_info_t *ei)
0);
}
-/** Return a human-readable description of the routerinfo_t <b>ri</b>.
- *
- * This function is not thread-safe. Each call to this function invalidates
- * previous values returned by this function.
- */
-const char *
-router_describe(const routerinfo_t *ri)
-{
- static char buf[NODE_DESC_BUF_LEN];
- return router_get_description(buf, ri);
-}
-
-/** Return a human-readable description of the node_t <b>node</b>.
- *
- * This function is not thread-safe. Each call to this function invalidates
- * previous values returned by this function.
- */
-const char *
-node_describe(const node_t *node)
-{
- static char buf[NODE_DESC_BUF_LEN];
- return node_get_description(buf, node);
-}
-
-/** Return a human-readable description of the routerstatus_t <b>rs</b>.
- *
- * This function is not thread-safe. Each call to this function invalidates
- * previous values returned by this function.
- */
-const char *
-routerstatus_describe(const routerstatus_t *rs)
-{
- static char buf[NODE_DESC_BUF_LEN];
- return routerstatus_get_description(buf, rs);
-}
-
-/** Return a human-readable description of the extend_info_t <b>ei</b>.
- *
- * This function is not thread-safe. Each call to this function invalidates
- * previous values returned by this function.
- */
-const char *
-extend_info_describe(const extend_info_t *ei)
-{
- static char buf[NODE_DESC_BUF_LEN];
- return extend_info_get_description(buf, ei);
-}
-
/** Set <b>buf</b> (which must have MAX_VERBOSE_NICKNAME_LEN+1 bytes) to the
* verbose representation of the identity of <b>router</b>. The format is:
* A dollar sign.
diff --git a/src/or/router.h b/src/or/router.h
index 7f50308956..e5efe577e3 100644
--- a/src/or/router.h
+++ b/src/or/router.h
@@ -123,24 +123,6 @@ int is_legal_nickname(const char *s);
int is_legal_nickname_or_hexdigest(const char *s);
int is_legal_hexdigest(const char *s);
-/**
- * Longest allowed output of format_node_description, plus 1 character for
- * NUL. This allows space for:
- * "$FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF~xxxxxxxxxxxxxxxxxxx at"
- * " [ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255]"
- * plus a terminating NUL.
- */
-#define NODE_DESC_BUF_LEN (MAX_VERBOSE_NICKNAME_LEN+4+TOR_ADDR_BUF_LEN)
-const char *format_node_description(char *buf,
- const char *id_digest,
- int is_named,
- const char *nickname,
- const tor_addr_t *addr,
- uint32_t addr32h);
-const char *router_get_description(char *buf, const routerinfo_t *ri);
-const char *node_get_description(char *buf, const node_t *node);
-const char *routerstatus_get_description(char *buf, const routerstatus_t *rs);
-const char *extend_info_get_description(char *buf, const extend_info_t *ei);
const char *router_describe(const routerinfo_t *ri);
const char *node_describe(const node_t *node);
const char *routerstatus_describe(const routerstatus_t *ri);
diff --git a/src/or/routerlist.c b/src/or/routerlist.c
index 696bb454ff..bc3abb236f 100644
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@ -177,7 +177,7 @@ static void download_status_reset_by_sk_in_cl(cert_list_t *cl,
const char *digest);
static int download_status_is_ready_by_sk_in_cl(cert_list_t *cl,
const char *digest,
- time_t now, int max_failures);
+ time_t now);
/****************************************************************************/
@@ -246,7 +246,6 @@ download_status_cert_init(download_status_t *dlstatus)
dlstatus->schedule = DL_SCHED_CONSENSUS;
dlstatus->want_authority = DL_WANT_ANY_DIRSERVER;
dlstatus->increment_on = DL_SCHED_INCREMENT_FAILURE;
- dlstatus->backoff = DL_SCHED_RANDOM_EXPONENTIAL;
dlstatus->last_backoff_position = 0;
dlstatus->last_delay_used = 0;
@@ -288,7 +287,7 @@ download_status_reset_by_sk_in_cl(cert_list_t *cl, const char *digest)
static int
download_status_is_ready_by_sk_in_cl(cert_list_t *cl,
const char *digest,
- time_t now, int max_failures)
+ time_t now)
{
int rv = 0;
download_status_t *dlstatus = NULL;
@@ -305,7 +304,7 @@ download_status_is_ready_by_sk_in_cl(cert_list_t *cl,
/* Got one? */
if (dlstatus) {
/* Use download_status_is_ready() */
- rv = download_status_is_ready(dlstatus, now, max_failures);
+ rv = download_status_is_ready(dlstatus, now);
} else {
/*
* If we don't know anything about it, return 1, since we haven't
@@ -1068,8 +1067,7 @@ authority_certs_fetch_missing(networkstatus_t *status, time_t now,
}
} SMARTLIST_FOREACH_END(cert);
if (!found &&
- download_status_is_ready(&(cl->dl_status_by_id), now,
- options->TestingCertMaxDownloadTries) &&
+ download_status_is_ready(&(cl->dl_status_by_id), now) &&
!digestmap_get(pending_id, ds->v3_identity_digest)) {
log_info(LD_DIR,
"No current certificate known for authority %s "
@@ -1132,8 +1130,7 @@ authority_certs_fetch_missing(networkstatus_t *status, time_t now,
continue;
}
if (download_status_is_ready_by_sk_in_cl(
- cl, sig->signing_key_digest,
- now, options->TestingCertMaxDownloadTries) &&
+ cl, sig->signing_key_digest, now) &&
!fp_pair_map_get_by_digests(pending_cert,
voter->identity_digest,
sig->signing_key_digest)) {
@@ -5167,8 +5164,7 @@ update_consensus_router_descriptor_downloads(time_t now, int is_vote,
++n_inprogress;
continue; /* We have an in-progress download. */
}
- if (!download_status_is_ready(&rs->dl_status, now,
- options->TestingDescriptorMaxDownloadTries)) {
+ if (!download_status_is_ready(&rs->dl_status, now)) {
++n_delayed; /* Not ready for retry. */
continue;
}
@@ -5344,8 +5340,7 @@ update_extrainfo_downloads(time_t now)
++n_have;
continue;
}
- if (!download_status_is_ready(&sd->ei_dl_status, now,
- options->TestingDescriptorMaxDownloadTries)) {
+ if (!download_status_is_ready(&sd->ei_dl_status, now)) {
++n_delay;
continue;
}
diff --git a/src/or/routerparse.c b/src/or/routerparse.c
index 1b79a6fe24..79499f2e6f 100644
--- a/src/or/routerparse.c
+++ b/src/or/routerparse.c
@@ -3809,7 +3809,6 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
ns->consensus_method,
flav))) {
/* Use exponential-backoff scheduling when downloading microdescs */
- rs->dl_status.backoff = DL_SCHED_RANDOM_EXPONENTIAL;
smartlist_add(ns->routerstatus_list, rs);
}
}
diff --git a/src/or/scheduler.c b/src/or/scheduler.c
index 382b3e3ca9..da894294bf 100644
--- a/src/or/scheduler.c
+++ b/src/or/scheduler.c
@@ -13,8 +13,6 @@
#define TOR_CHANNEL_INTERNAL_
#include "channeltls.h"
-#include <event2/event.h>
-
/**
* \file scheduler.c
* \brief Channel scheduling system: decides which channels should send and
@@ -169,7 +167,7 @@ STATIC smartlist_t *channels_pending = NULL;
* This event runs the scheduler from its callback, and is manually
* activated whenever a channel enters open for writes/cells to send.
*/
-STATIC struct event *run_sched_ev = NULL;
+STATIC struct mainloop_event_t *run_sched_ev = NULL;
static int have_logged_kist_suddenly_disabled = 0;
@@ -203,10 +201,9 @@ get_scheduler_type_string(scheduler_types_t type)
* if any scheduling work was created during the event loop.
*/
static void
-scheduler_evt_callback(evutil_socket_t fd, short events, void *arg)
+scheduler_evt_callback(mainloop_event_t *event, void *arg)
{
- (void) fd;
- (void) events;
+ (void) event;
(void) arg;
log_debug(LD_SCHED, "Scheduler event callback called");
@@ -487,10 +484,7 @@ scheduler_free_all(void)
log_debug(LD_SCHED, "Shutting down scheduler");
if (run_sched_ev) {
- if (event_del(run_sched_ev) < 0) {
- log_warn(LD_BUG, "Problem deleting run_sched_ev");
- }
- tor_event_free(run_sched_ev);
+ mainloop_event_free(run_sched_ev);
run_sched_ev = NULL;
}
@@ -589,7 +583,7 @@ scheduler_ev_add(const struct timeval *next_run)
{
tor_assert(run_sched_ev);
tor_assert(next_run);
- if (BUG(event_add(run_sched_ev, next_run) < 0)) {
+ if (BUG(mainloop_event_schedule(run_sched_ev, next_run) < 0)) {
log_warn(LD_SCHED, "Adding to libevent failed. Next run time was set to: "
"%ld.%06ld", next_run->tv_sec, (long)next_run->tv_usec);
return;
@@ -598,10 +592,10 @@ scheduler_ev_add(const struct timeval *next_run)
/** Make the scheduler event active with the given flags. */
void
-scheduler_ev_active(int flags)
+scheduler_ev_active(void)
{
tor_assert(run_sched_ev);
- event_active(run_sched_ev, flags, 1);
+ mainloop_event_activate(run_sched_ev);
}
/*
@@ -618,11 +612,10 @@ scheduler_init(void)
IF_BUG_ONCE(!!run_sched_ev) {
log_warn(LD_SCHED, "We should not already have a libevent scheduler event."
"I'll clean the old one up, but this is odd.");
- tor_event_free(run_sched_ev);
+ mainloop_event_free(run_sched_ev);
run_sched_ev = NULL;
}
- run_sched_ev = tor_event_new(tor_libevent_get_base(), -1,
- 0, scheduler_evt_callback, NULL);
+ run_sched_ev = mainloop_event_new(scheduler_evt_callback, NULL);
channels_pending = smartlist_new();
set_scheduler();
diff --git a/src/or/scheduler.h b/src/or/scheduler.h
index aeba9e2b75..08b02e286f 100644
--- a/src/or/scheduler.h
+++ b/src/or/scheduler.h
@@ -155,12 +155,12 @@ void scheduler_bug_occurred(const channel_t *chan);
smartlist_t *get_channels_pending(void);
MOCK_DECL(int, scheduler_compare_channels,
(const void *c1_v, const void *c2_v));
-void scheduler_ev_active(int flags);
+void scheduler_ev_active(void);
void scheduler_ev_add(const struct timeval *next_run);
#ifdef TOR_UNIT_TESTS
extern smartlist_t *channels_pending;
-extern struct event *run_sched_ev;
+extern struct mainloop_event_t *run_sched_ev;
extern const scheduler_t *the_scheduler;
void scheduler_touch_channel(channel_t *chan);
#endif /* defined(TOR_UNIT_TESTS) */
diff --git a/src/or/scheduler_kist.c b/src/or/scheduler_kist.c
index 6d6490077d..c6e9b72c48 100644
--- a/src/or/scheduler_kist.c
+++ b/src/or/scheduler_kist.c
@@ -3,8 +3,6 @@
#define SCHEDULER_KIST_PRIVATE
-#include <event2/event.h>
-
#include "or.h"
#include "buffers.h"
#include "config.h"
@@ -553,7 +551,7 @@ kist_scheduler_schedule(void)
/* Re-adding an event reschedules it. It does not duplicate it. */
scheduler_ev_add(&next_run);
} else {
- scheduler_ev_active(EV_TIMEOUT);
+ scheduler_ev_active();
}
}
diff --git a/src/or/scheduler_vanilla.c b/src/or/scheduler_vanilla.c
index 7a83b9da18..b674d8256c 100644
--- a/src/or/scheduler_vanilla.c
+++ b/src/or/scheduler_vanilla.c
@@ -1,8 +1,6 @@
/* Copyright (c) 2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-#include <event2/event.h>
-
#include "or.h"
#include "config.h"
#define TOR_CHANNEL_INTERNAL_
@@ -42,7 +40,7 @@ vanilla_scheduler_schedule(void)
}
/* Activate our event so it can process channels. */
- scheduler_ev_active(EV_TIMEOUT);
+ scheduler_ev_active();
}
static void
diff --git a/src/or/tor_api.h b/src/or/tor_api.h
index 7e86c7fec5..6d4a9518e0 100644
--- a/src/or/tor_api.h
+++ b/src/or/tor_api.h
@@ -66,14 +66,12 @@ void tor_main_configuration_free(tor_main_configuration_t *cfg);
* This function will not return until Tor is done running. It returns zero
* on success, and nonzero on failure.
*
- * BUG 23848: In many cases, tor_main will call exit() or abort() instead of
- * returning. This is not the intended long-term behavior; we are trying to
- * fix it.
- *
- * BUG 23847: You can only call tor_main() once in a single process; if it
- * returns and you call it again, you may crash, or you may encounter other
- * unexpected behavior, including possible security issues. This is not
- * intended long-term behavior; we are trying to fix it.
+ * If you want to control when Tor exits, make sure to configure a control
+ * socket. The OwningControllerFD option may be helpful there.
+ *
+ * BUG 23847: Sometimes, if you call tor_main a second time (after it has
+ * returned), Tor may crash or behave strangely. We have fixed all issues of
+ * this type that we could find, but more may remain.
*
* LIMITATION: You cannot run more than one instance of Tor in the same
* process at the same time. Concurrent calls will cause undefined behavior.
diff --git a/src/or/transports.c b/src/or/transports.c
index fb6c29de7e..614fc81da8 100644
--- a/src/or/transports.c
+++ b/src/or/transports.c
@@ -1025,48 +1025,71 @@ parse_method_error(const char *line, int is_server)
line+strlen(error)+1);
}
-/** Parses an SMETHOD <b>line</b> and if well-formed it registers the
- * new transport in <b>mp</b>. */
-STATIC int
-parse_smethod_line(const char *line, managed_proxy_t *mp)
+/** A helper for parse_{c,s}method_line(), bootstraps its
+ * functionalities. If <b>is_smethod</b> is true then the
+ * the line to parse is a SMETHOD line otherwise it is a
+ * CMETHOD line*/
+static int
+parse_method_line_helper(const char *line,
+ managed_proxy_t *mp,
+ int is_smethod)
{
+ int item_index = 0;
int r;
- smartlist_t *items = NULL;
- char *method_name=NULL;
+ char *transport_name=NULL;
char *args_string=NULL;
char *addrport=NULL;
- tor_addr_t tor_addr;
+ int socks_ver=PROXY_NONE;
char *address=NULL;
uint16_t port = 0;
+ const char *method_str = is_smethod ? PROTO_SMETHOD : PROTO_CMETHOD;
+ const int min_args_count = is_smethod ? 3 : 4;
+
+ tor_addr_t tor_addr;
transport_t *transport=NULL;
+ smartlist_t *items= smartlist_new();
- items = smartlist_new();
smartlist_split_string(items, line, NULL,
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
- if (smartlist_len(items) < 3) {
- log_warn(LD_CONFIG, "Server managed proxy sent us a SMETHOD line "
- "with too few arguments.");
+ if (smartlist_len(items) < min_args_count) {
+ log_warn(LD_CONFIG, "Managed proxy sent us a %s line "
+ "with too few arguments.", method_str);
goto err;
}
- /* Example of legit SMETHOD line:
- SMETHOD obfs2 0.0.0.0:25612 ARGS:secret=supersekrit,key=superkey */
-
- tor_assert(!strcmp(smartlist_get(items,0),PROTO_SMETHOD));
+ tor_assert(!strcmp(smartlist_get(items, item_index),method_str));
+ ++item_index;
- method_name = smartlist_get(items,1);
- if (!string_is_C_identifier(method_name)) {
+ transport_name = smartlist_get(items,item_index);
+ ++item_index;
+ if (!string_is_C_identifier(transport_name)) {
log_warn(LD_CONFIG, "Transport name is not a C identifier (%s).",
- method_name);
+ transport_name);
goto err;
}
- addrport = smartlist_get(items, 2);
+ /** Check for the proxy method sent to us in CMETHOD line. */
+ if (!is_smethod) {
+ const char *socks_ver_str = smartlist_get(items,item_index);
+ ++item_index;
+
+ if (!strcmp(socks_ver_str,"socks4")) {
+ socks_ver = PROXY_SOCKS4;
+ } else if (!strcmp(socks_ver_str,"socks5")) {
+ socks_ver = PROXY_SOCKS5;
+ } else {
+ log_warn(LD_CONFIG, "Client managed proxy sent us a proxy protocol "
+ "we don't recognize. (%s)", socks_ver_str);
+ goto err;
+ }
+ }
+
+ addrport = smartlist_get(items, item_index);
+ ++item_index;
if (tor_addr_port_split(LOG_WARN, addrport, &address, &port)<0) {
- log_warn(LD_CONFIG, "Error parsing transport "
- "address '%s'", addrport);
+ log_warn(LD_CONFIG, "Error parsing transport address '%s'", addrport);
goto err;
}
@@ -1081,10 +1104,11 @@ parse_smethod_line(const char *line, managed_proxy_t *mp)
goto err;
}
- if (smartlist_len(items) > 3) {
+ /** Check for options in the SMETHOD line. */
+ if (is_smethod && smartlist_len(items) > min_args_count) {
/* Seems like there are also some [options] in the SMETHOD line.
Let's see if we can parse them. */
- char *options_string = smartlist_get(items, 3);
+ char *options_string = smartlist_get(items, item_index);
log_debug(LD_CONFIG, "Got options_string: %s", options_string);
if (!strcmpstart(options_string, "ARGS:")) {
args_string = options_string+strlen("ARGS:");
@@ -1092,15 +1116,20 @@ parse_smethod_line(const char *line, managed_proxy_t *mp)
}
}
- transport = transport_new(&tor_addr, port, method_name,
- PROXY_NONE, args_string);
+ transport = transport_new(&tor_addr, port, transport_name,
+ socks_ver, args_string);
smartlist_add(mp->transports, transport);
- /* For now, notify the user so that they know where the server
- transport is listening. */
- log_info(LD_CONFIG, "Server transport %s at %s:%d.",
- method_name, address, (int)port);
+ /** Logs info about line parsing success for client or server */
+ if (is_smethod) {
+ log_info(LD_CONFIG, "Server transport %s at %s:%d.",
+ transport_name, address, (int)port);
+ } else {
+ log_info(LD_CONFIG, "Transport %s at %s:%d with SOCKS %d. "
+ "Attached to managed proxy.",
+ transport_name, address, (int)port, socks_ver);
+ }
r=0;
goto done;
@@ -1115,93 +1144,24 @@ parse_smethod_line(const char *line, managed_proxy_t *mp)
return r;
}
+/** Parses an SMETHOD <b>line</b> and if well-formed it registers the
+ * new transport in <b>mp</b>. */
+STATIC int
+parse_smethod_line(const char *line, managed_proxy_t *mp)
+{
+ /* Example of legit SMETHOD line:
+ SMETHOD obfs2 0.0.0.0:25612 ARGS:secret=supersekrit,key=superkey */
+ return parse_method_line_helper(line, mp, 1);
+}
+
/** Parses a CMETHOD <b>line</b>, and if well-formed it registers
* the new transport in <b>mp</b>. */
STATIC int
parse_cmethod_line(const char *line, managed_proxy_t *mp)
{
- int r;
- smartlist_t *items = NULL;
-
- char *method_name=NULL;
-
- char *socks_ver_str=NULL;
- int socks_ver=PROXY_NONE;
-
- char *addrport=NULL;
- tor_addr_t tor_addr;
- char *address=NULL;
- uint16_t port = 0;
-
- transport_t *transport=NULL;
-
- items = smartlist_new();
- smartlist_split_string(items, line, NULL,
- SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
- if (smartlist_len(items) < 4) {
- log_warn(LD_CONFIG, "Client managed proxy sent us a CMETHOD line "
- "with too few arguments.");
- goto err;
- }
-
- tor_assert(!strcmp(smartlist_get(items,0),PROTO_CMETHOD));
-
- method_name = smartlist_get(items,1);
- if (!string_is_C_identifier(method_name)) {
- log_warn(LD_CONFIG, "Transport name is not a C identifier (%s).",
- method_name);
- goto err;
- }
-
- socks_ver_str = smartlist_get(items,2);
-
- if (!strcmp(socks_ver_str,"socks4")) {
- socks_ver = PROXY_SOCKS4;
- } else if (!strcmp(socks_ver_str,"socks5")) {
- socks_ver = PROXY_SOCKS5;
- } else {
- log_warn(LD_CONFIG, "Client managed proxy sent us a proxy protocol "
- "we don't recognize. (%s)", socks_ver_str);
- goto err;
- }
-
- addrport = smartlist_get(items, 3);
- if (tor_addr_port_split(LOG_WARN, addrport, &address, &port)<0) {
- log_warn(LD_CONFIG, "Error parsing transport "
- "address '%s'", addrport);
- goto err;
- }
-
- if (!port) {
- log_warn(LD_CONFIG,
- "Transport address '%s' has no port.", addrport);
- goto err;
- }
-
- if (tor_addr_parse(&tor_addr, address) < 0) {
- log_warn(LD_CONFIG, "Error parsing transport address '%s'", address);
- goto err;
- }
-
- transport = transport_new(&tor_addr, port, method_name, socks_ver, NULL);
-
- smartlist_add(mp->transports, transport);
-
- log_info(LD_CONFIG, "Transport %s at %s:%d with SOCKS %d. "
- "Attached to managed proxy.",
- method_name, address, (int)port, socks_ver);
-
- r=0;
- goto done;
-
- err:
- r = -1;
-
- done:
- SMARTLIST_FOREACH(items, char*, s, tor_free(s));
- smartlist_free(items);
- tor_free(address);
- return r;
+ /* Example of legit CMETHOD line:
+ CMETHOD obfs2 socks5 127.0.0.1:35713 */
+ return parse_method_line_helper(line, mp, 0);
}
/** Parses an PROXY-ERROR <b>line</b> and warns the user accordingly. */