summaryrefslogtreecommitdiff
path: root/src/or
diff options
context:
space:
mode:
Diffstat (limited to 'src/or')
-rw-r--r--src/or/addressmap.c35
-rw-r--r--src/or/bridges.c7
-rw-r--r--src/or/channel.c1680
-rw-r--r--src/or/channel.h100
-rw-r--r--src/or/channeltls.c13
-rw-r--r--src/or/circuitbuild.c17
-rw-r--r--src/or/circuitbuild.h4
-rw-r--r--src/or/circuitlist.c64
-rw-r--r--src/or/circuitlist.h3
-rw-r--r--src/or/circuitmux.c2
-rw-r--r--src/or/circuitmux.h4
-rw-r--r--src/or/circuitstats.c11
-rw-r--r--src/or/circuituse.c24
-rw-r--r--src/or/config.c350
-rw-r--r--src/or/config.h82
-rw-r--r--src/or/confparse.c2
-rw-r--r--src/or/confparse.h13
-rw-r--r--src/or/connection.c25
-rw-r--r--src/or/connection.h7
-rw-r--r--src/or/connection_edge.c21
-rw-r--r--src/or/connection_or.c56
-rw-r--r--src/or/connection_or.h10
-rw-r--r--src/or/conscache.c21
-rw-r--r--src/or/conscache.h7
-rw-r--r--src/or/consdiffmgr.c30
-rw-r--r--src/or/control.c548
-rw-r--r--src/or/control.h65
-rw-r--r--src/or/cpuworker.c19
-rw-r--r--src/or/dircollate.c7
-rw-r--r--src/or/dircollate.h4
-rw-r--r--src/or/directory.c141
-rw-r--r--src/or/directory.h48
-rw-r--r--src/or/dirserv.c43
-rw-r--r--src/or/dirserv.h5
-rw-r--r--src/or/dirvote.c34
-rw-r--r--src/or/dirvote.h18
-rw-r--r--src/or/dns.c19
-rw-r--r--src/or/dnsserv.c4
-rw-r--r--src/or/entrynodes.c132
-rw-r--r--src/or/entrynodes.h54
-rw-r--r--src/or/ext_orport.c2
-rw-r--r--src/or/ext_orport.h6
-rw-r--r--src/or/fp_pair.c2
-rw-r--r--src/or/fp_pair.h7
-rw-r--r--src/or/geoip.c5
-rw-r--r--src/or/git_revision.h2
-rw-r--r--src/or/hs_cache.c62
-rw-r--r--src/or/hs_cache.h2
-rw-r--r--src/or/hs_circuit.c92
-rw-r--r--src/or/hs_circuit.h2
-rw-r--r--src/or/hs_circuitmap.c5
-rw-r--r--src/or/hs_client.c5
-rw-r--r--src/or/hs_common.c4
-rw-r--r--src/or/hs_common.h15
-rw-r--r--src/or/hs_control.c258
-rw-r--r--src/or/hs_control.h52
-rw-r--r--src/or/hs_descriptor.c10
-rw-r--r--src/or/hs_descriptor.h21
-rw-r--r--src/or/hs_ident.c6
-rw-r--r--src/or/hs_ident.h12
-rw-r--r--src/or/hs_service.c259
-rw-r--r--src/or/hs_service.h38
-rw-r--r--src/or/include.am4
-rw-r--r--src/or/main.c175
-rw-r--r--src/or/microdesc.c105
-rw-r--r--src/or/microdesc.h10
-rw-r--r--src/or/networkstatus.c49
-rw-r--r--src/or/networkstatus.h16
-rw-r--r--src/or/nodelist.c38
-rw-r--r--src/or/nodelist.h5
-rw-r--r--src/or/onion.c2
-rw-r--r--src/or/onion.h4
-rw-r--r--src/or/onion_fast.c2
-rw-r--r--src/or/onion_fast.h4
-rw-r--r--src/or/onion_ntor.c2
-rw-r--r--src/or/onion_ntor.h4
-rw-r--r--src/or/or.h27
-rw-r--r--src/or/policies.c10
-rw-r--r--src/or/policies.h12
-rw-r--r--src/or/proto_socks.c2
-rw-r--r--src/or/proto_socks.h4
-rw-r--r--src/or/protover.c50
-rw-r--r--src/or/protover.h13
-rw-r--r--src/or/protover_rust.c2
-rw-r--r--src/or/relay.c142
-rw-r--r--src/or/relay.h8
-rw-r--r--src/or/rendcache.c32
-rw-r--r--src/or/rendcache.h18
-rw-r--r--src/or/rendclient.c24
-rw-r--r--src/or/rendcommon.c6
-rw-r--r--src/or/rendcommon.h14
-rw-r--r--src/or/rendservice.c34
-rw-r--r--src/or/rendservice.h35
-rw-r--r--src/or/rephist.c24
-rw-r--r--src/or/replaycache.c2
-rw-r--r--src/or/replaycache.h4
-rw-r--r--src/or/router.c48
-rw-r--r--src/or/router.h4
-rw-r--r--src/or/routerkeys.c31
-rw-r--r--src/or/routerlist.c83
-rw-r--r--src/or/routerlist.h14
-rw-r--r--src/or/routerparse.c4
-rw-r--r--src/or/routerset.c2
-rw-r--r--src/or/routerset.h3
-rw-r--r--src/or/scheduler.c25
-rw-r--r--src/or/scheduler_kist.c17
-rw-r--r--src/or/shared_random.c4
-rw-r--r--src/or/shared_random.h3
-rw-r--r--src/or/shared_random_state.c14
-rw-r--r--src/or/shared_random_state.h2
-rw-r--r--src/or/statefile.c2
-rw-r--r--src/or/statefile.h3
-rw-r--r--src/or/tor_api_internal.h2
-rw-r--r--src/or/torcert.c4
-rw-r--r--src/or/torcert.h7
-rw-r--r--src/or/transports.c2
-rw-r--r--src/or/transports.h3
117 files changed, 3027 insertions, 2729 deletions
diff --git a/src/or/addressmap.c b/src/or/addressmap.c
index 9a2cc26b3b..96ce275578 100644
--- a/src/or/addressmap.c
+++ b/src/or/addressmap.c
@@ -90,34 +90,47 @@ addressmap_init(void)
virtaddress_reversemap = strmap_new();
}
+#define addressmap_ent_free(ent) \
+ FREE_AND_NULL(addressmap_entry_t, addressmap_ent_free_, (ent))
+
/** Free the memory associated with the addressmap entry <b>_ent</b>. */
static void
-addressmap_ent_free(void *_ent)
+addressmap_ent_free_(addressmap_entry_t *ent)
{
- addressmap_entry_t *ent;
- if (!_ent)
+ if (!ent)
return;
- ent = _ent;
tor_free(ent->new_address);
tor_free(ent);
}
+static void
+addressmap_ent_free_void(void *ent)
+{
+ addressmap_ent_free_(ent);
+}
+
+#define addressmap_virtaddress_ent_free(ent) \
+ FREE_AND_NULL(virtaddress_entry_t, addressmap_virtaddress_ent_free_, (ent))
+
/** Free storage held by a virtaddress_entry_t* entry in <b>_ent</b>. */
static void
-addressmap_virtaddress_ent_free(void *_ent)
+addressmap_virtaddress_ent_free_(virtaddress_entry_t *ent)
{
- virtaddress_entry_t *ent;
- if (!_ent)
+ if (!ent)
return;
-
- ent = _ent;
tor_free(ent->ipv4_address);
tor_free(ent->ipv6_address);
tor_free(ent->hostname_address);
tor_free(ent);
}
+static void
+addressmap_virtaddress_ent_free_void(void *ent)
+{
+ addressmap_virtaddress_ent_free_(ent);
+}
+
/** Remove <b>address</b> (which must map to <b>ent</b>) from the
* virtual address map. */
static void
@@ -311,10 +324,10 @@ addressmap_clean(time_t now)
void
addressmap_free_all(void)
{
- strmap_free(addressmap, addressmap_ent_free);
+ strmap_free(addressmap, addressmap_ent_free_void);
addressmap = NULL;
- strmap_free(virtaddress_reversemap, addressmap_virtaddress_ent_free);
+ strmap_free(virtaddress_reversemap, addressmap_virtaddress_ent_free_void);
virtaddress_reversemap = NULL;
}
diff --git a/src/or/bridges.c b/src/or/bridges.c
index 320f5ee632..f6e3e419d3 100644
--- a/src/or/bridges.c
+++ b/src/or/bridges.c
@@ -53,7 +53,10 @@ struct bridge_info_t {
smartlist_t *socks_args;
};
-static void bridge_free(bridge_info_t *bridge);
+#define bridge_free(bridge) \
+ FREE_AND_NULL(bridge_info_t, bridge_free_, (bridge))
+
+static void bridge_free_(bridge_info_t *bridge);
static void rewrite_node_address_for_bridge(const bridge_info_t *bridge,
node_t *node);
@@ -101,7 +104,7 @@ clear_bridge_list(void)
/** Free the bridge <b>bridge</b>. */
static void
-bridge_free(bridge_info_t *bridge)
+bridge_free_(bridge_info_t *bridge)
{
if (!bridge)
return;
diff --git a/src/or/channel.c b/src/or/channel.c
index 0b5a7fde90..7fa9768171 100644
--- a/src/or/channel.c
+++ b/src/or/channel.c
@@ -1,3 +1,4 @@
+
/* * Copyright (c) 2012-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
@@ -5,9 +6,8 @@
* \file channel.c
*
* \brief OR/OP-to-OR channel abstraction layer. A channel's job is to
- * transfer cells from Tor instance to Tor instance.
- * Currently, there is only one implementation of the channel abstraction: in
- * channeltls.c.
+ * transfer cells from Tor instance to Tor instance. Currently, there is only
+ * one implementation of the channel abstraction: in channeltls.c.
*
* Channels are a higher-level abstraction than or_connection_t: In general,
* any means that two Tor relays use to exchange cells, or any means that a
@@ -24,16 +24,28 @@
* connection.
*
* Every channel implementation is responsible for being able to transmit
- * cells that are added to it with channel_write_cell() and related functions,
- * and to receive incoming cells with the channel_queue_cell() and related
- * functions. See the channel_t documentation for more information.
- *
- * When new cells arrive on a channel, they are passed to cell handler
- * functions, which can be set by channel_set_cell_handlers()
- * functions. (Tor's cell handlers are in command.c.)
- *
- * Tor flushes cells to channels from relay.c in
- * channel_flush_from_first_active_circuit().
+ * cells that are passed to it
+ *
+ * For *inbound* cells, the entry point is: channel_process_cell(). It takes a
+ * cell and will pass it to the cell handler set by
+ * channel_set_cell_handlers(). Currently, this is passed back to the command
+ * subsystem which is command_process_cell().
+ *
+ * NOTE: For now, the seperation between channels and specialized channels
+ * (like channeltls) is not that well defined. So the channeltls layer calls
+ * channel_process_cell() which originally comes from the connection subsytem.
+ * This should be hopefully be fixed with #23993.
+ *
+ * For *outbound* cells, the entry point is: channel_write_packed_cell().
+ * Only packed cells are dequeued from the circuit queue by the scheduler
+ * which uses channel_flush_from_first_active_circuit() to decide which cells
+ * to flush from which circuit on the channel. They are then passed down to
+ * the channel subsystem. This calls the low layer with the function pointer
+ * .write_packed_cell().
+ *
+ * Each specialized channel (currently only channeltls_t) MUST implement a
+ * series of function found in channel_t. See channel.h for more
+ * documentation.
**/
/*
@@ -112,59 +124,6 @@ HANDLE_IMPL(channel, channel_s,)
/* Counter for ID numbers */
static uint64_t n_channels_allocated = 0;
-/*
- * Channel global byte/cell counters, for statistics and for scheduler high
- * /low-water marks.
- */
-
-/*
- * Total number of cells ever given to any channel with the
- * channel_write_*_cell() functions.
- */
-
-static uint64_t n_channel_cells_queued = 0;
-
-/*
- * Total number of cells ever passed to a channel lower layer with the
- * write_*_cell() methods.
- */
-
-static uint64_t n_channel_cells_passed_to_lower_layer = 0;
-
-/*
- * Current number of cells in all channel queues; should be
- * n_channel_cells_queued - n_channel_cells_passed_to_lower_layer.
- */
-
-static uint64_t n_channel_cells_in_queues = 0;
-
-/*
- * Total number of bytes for all cells ever queued to a channel and
- * counted in n_channel_cells_queued.
- */
-
-static uint64_t n_channel_bytes_queued = 0;
-
-/*
- * Total number of bytes for all cells ever passed to a channel lower layer
- * and counted in n_channel_cells_passed_to_lower_layer.
- */
-
-static uint64_t n_channel_bytes_passed_to_lower_layer = 0;
-
-/*
- * Current number of bytes in all channel queues; should be
- * n_channel_bytes_queued - n_channel_bytes_passed_to_lower_layer.
- */
-
-static uint64_t n_channel_bytes_in_queues = 0;
-
-/*
- * Current total estimated queue size *including lower layer queues and
- * transmit overhead*
- */
-
-STATIC uint64_t estimated_total_queue_size = 0;
/* Digest->channel map
*
@@ -201,40 +160,15 @@ HT_PROTOTYPE(channel_idmap, channel_idmap_entry_s, node, channel_idmap_hash,
HT_GENERATE2(channel_idmap, channel_idmap_entry_s, node, channel_idmap_hash,
channel_idmap_eq, 0.5, tor_reallocarray_, tor_free_)
-static cell_queue_entry_t * cell_queue_entry_dup(cell_queue_entry_t *q);
-#if 0
-static int cell_queue_entry_is_padding(cell_queue_entry_t *q);
-#endif
-static cell_queue_entry_t *
-cell_queue_entry_new_fixed(cell_t *cell);
-static cell_queue_entry_t *
-cell_queue_entry_new_var(var_cell_t *var_cell);
-static int is_destroy_cell(channel_t *chan,
- const cell_queue_entry_t *q, circid_t *circid_out);
-
-static void channel_assert_counter_consistency(void);
-
/* Functions to maintain the digest map */
-static void channel_add_to_digest_map(channel_t *chan);
static void channel_remove_from_digest_map(channel_t *chan);
-/*
- * Flush cells from just the outgoing queue without trying to get them
- * from circuits; used internall by channel_flush_some_cells().
- */
-static ssize_t
-channel_flush_some_cells_from_outgoing_queue(channel_t *chan,
- ssize_t num_cells);
-static void channel_force_free(channel_t *chan);
-static void
-channel_free_list(smartlist_t *channels, int mark_for_close);
-static void
-channel_listener_free_list(smartlist_t *channels, int mark_for_close);
-static void channel_listener_force_free(channel_listener_t *chan_l);
-static size_t channel_get_cell_queue_entry_size(channel_t *chan,
- cell_queue_entry_t *q);
-static void
-channel_write_cell_queue_entry(channel_t *chan, cell_queue_entry_t *q);
+static void channel_force_xfree(channel_t *chan);
+static void channel_free_list(smartlist_t *channels,
+ int mark_for_close);
+static void channel_listener_free_list(smartlist_t *channels,
+ int mark_for_close);
+static void channel_listener_force_xfree(channel_listener_t *chan_l);
/***********************************
* Channel state utility functions *
@@ -628,7 +562,7 @@ channel_listener_unregister(channel_listener_t *chan_l)
* already exist.
*/
-static void
+STATIC void
channel_add_to_digest_map(channel_t *chan)
{
channel_idmap_entry_t *ent, search;
@@ -676,33 +610,6 @@ channel_remove_from_digest_map(channel_t *chan)
/* Assert that there is a digest */
tor_assert(!tor_digest_is_zero(chan->identity_digest));
-#if 0
- /* Make sure we have a map */
- if (!channel_identity_map) {
- /*
- * No identity map, so we can't find it by definition. This
- * case is similar to digestmap_get() failing below.
- */
- log_warn(LD_BUG,
- "Trying to remove channel %p (global ID " U64_FORMAT ") "
- "with digest %s from identity map, but didn't have any identity "
- "map",
- chan, U64_PRINTF_ARG(chan->global_identifier),
- hex_str(chan->identity_digest, DIGEST_LEN));
- /* Clear out its next/prev pointers */
- if (chan->next_with_same_id) {
- chan->next_with_same_id->prev_with_same_id = chan->prev_with_same_id;
- }
- if (chan->prev_with_same_id) {
- chan->prev_with_same_id->next_with_same_id = chan->next_with_same_id;
- }
- chan->next_with_same_id = NULL;
- chan->prev_with_same_id = NULL;
-
- return;
- }
-#endif /* 0 */
-
/* Pull it out of its list, wherever that list is */
TOR_LIST_REMOVE(chan, next_with_same_id);
@@ -936,10 +843,6 @@ channel_init(channel_t *chan)
/* Warn about exhausted circuit IDs no more than hourly. */
chan->last_warned_circ_ids_exhausted.rate = 3600;
- /* Initialize queues. */
- TOR_SIMPLEQ_INIT(&chan->incoming_queue);
- TOR_SIMPLEQ_INIT(&chan->outgoing_queue);
-
/* Initialize list entries. */
memset(&chan->next_with_same_id, 0, sizeof(chan->next_with_same_id));
@@ -979,7 +882,7 @@ channel_init_listener(channel_listener_t *chan_l)
*/
void
-channel_free(channel_t *chan)
+channel_free_(channel_t *chan)
{
if (!chan) return;
@@ -1022,8 +925,6 @@ channel_free(channel_t *chan)
chan->cmux = NULL;
}
- /* We're in CLOSED or ERROR, so the cell queue is already empty */
-
tor_free(chan);
}
@@ -1034,7 +935,7 @@ channel_free(channel_t *chan)
*/
void
-channel_listener_free(channel_listener_t *chan_l)
+channel_listener_free_(channel_listener_t *chan_l)
{
if (!chan_l) return;
@@ -1052,11 +953,6 @@ channel_listener_free(channel_listener_t *chan_l)
/* Call a free method if there is one */
if (chan_l->free_fn) chan_l->free_fn(chan_l);
- /*
- * We're in CLOSED or ERROR, so the incoming channel queue is already
- * empty.
- */
-
tor_free(chan_l);
}
@@ -1067,9 +963,8 @@ channel_listener_free(channel_listener_t *chan_l)
*/
static void
-channel_force_free(channel_t *chan)
+channel_force_xfree(channel_t *chan)
{
- cell_queue_entry_t *cell, *cell_tmp;
tor_assert(chan);
log_debug(LD_CHANNEL,
@@ -1103,18 +998,6 @@ channel_force_free(channel_t *chan)
chan->cmux = NULL;
}
- /* We might still have a cell queue; kill it */
- TOR_SIMPLEQ_FOREACH_SAFE(cell, &chan->incoming_queue, next, cell_tmp) {
- cell_queue_entry_free(cell, 0);
- }
- TOR_SIMPLEQ_INIT(&chan->incoming_queue);
-
- /* Outgoing cell queue is similar, but we can have to free packed cells */
- TOR_SIMPLEQ_FOREACH_SAFE(cell, &chan->outgoing_queue, next, cell_tmp) {
- cell_queue_entry_free(cell, 0);
- }
- TOR_SIMPLEQ_INIT(&chan->outgoing_queue);
-
tor_free(chan);
}
@@ -1125,7 +1008,7 @@ channel_force_free(channel_t *chan)
*/
static void
-channel_listener_force_free(channel_listener_t *chan_l)
+channel_listener_force_xfree(channel_listener_t *chan_l)
{
tor_assert(chan_l);
@@ -1156,24 +1039,6 @@ channel_listener_force_free(channel_listener_t *chan_l)
}
/**
- * Return the current registered listener for a channel listener
- *
- * This function returns a function pointer to the current registered
- * handler for new incoming channels on a channel listener.
- */
-
-channel_listener_fn_ptr
-channel_listener_get_listener_fn(channel_listener_t *chan_l)
-{
- tor_assert(chan_l);
-
- if (chan_l->state == CHANNEL_LISTENER_STATE_LISTENING)
- return chan_l->listener;
-
- return NULL;
-}
-
-/**
* Set the listener for a channel listener
*
* This function sets the handler for new incoming channels on a channel
@@ -1237,8 +1102,7 @@ channel_get_var_cell_handler(channel_t *chan)
* Set both cell handlers for a channel
*
* This function sets both the fixed-length and variable length cell handlers
- * for a channel and processes any incoming cells that had been blocked in the
- * queue because none were available.
+ * for a channel.
*/
void
@@ -1247,8 +1111,6 @@ channel_set_cell_handlers(channel_t *chan,
channel_var_cell_handler_fn_ptr
var_cell_handler)
{
- int try_again = 0;
-
tor_assert(chan);
tor_assert(CHANNEL_CAN_HANDLE_CELLS(chan));
@@ -1259,21 +1121,9 @@ channel_set_cell_handlers(channel_t *chan,
"Setting var_cell_handler callback for channel %p to %p",
chan, var_cell_handler);
- /* Should we try the queue? */
- if (cell_handler &&
- cell_handler != chan->cell_handler) try_again = 1;
- if (var_cell_handler &&
- var_cell_handler != chan->var_cell_handler) try_again = 1;
-
/* Change them */
chan->cell_handler = cell_handler;
chan->var_cell_handler = var_cell_handler;
-
- /* Re-run the queue if we have one and there's any reason to */
- if (! TOR_SIMPLEQ_EMPTY(&chan->incoming_queue) &&
- try_again &&
- (chan->cell_handler ||
- chan->var_cell_handler)) channel_process_cells(chan);
}
/*
@@ -1400,36 +1250,6 @@ channel_close_from_lower_layer(channel_t *chan)
}
/**
- * Close a channel listener from the lower layer
- *
- * Notify the channel code that the channel listener is being closed due to a
- * non-error condition in the lower layer. This does not call the close()
- * method, since the lower layer already knows.
- */
-
-void
-channel_listener_close_from_lower_layer(channel_listener_t *chan_l)
-{
- tor_assert(chan_l != NULL);
-
- /* If it's already in CLOSING, CLOSED or ERROR, this is a no-op */
- if (chan_l->state == CHANNEL_LISTENER_STATE_CLOSING ||
- chan_l->state == CHANNEL_LISTENER_STATE_CLOSED ||
- chan_l->state == CHANNEL_LISTENER_STATE_ERROR) return;
-
- log_debug(LD_CHANNEL,
- "Closing channel listener %p (global ID " U64_FORMAT ") "
- "due to lower-layer event",
- chan_l, U64_PRINTF_ARG(chan_l->global_identifier));
-
- /* Note closing by event from below */
- chan_l->reason_for_closing = CHANNEL_LISTENER_CLOSE_FROM_BELOW;
-
- /* Change state to CLOSING */
- channel_listener_change_state(chan_l, CHANNEL_LISTENER_STATE_CLOSING);
-}
-
-/**
* Notify that the channel is being closed due to an error condition
*
* This function is called by the lower layer implementing the transport
@@ -1458,37 +1278,6 @@ channel_close_for_error(channel_t *chan)
}
/**
- * Notify that the channel listener is being closed due to an error condition
- *
- * This function is called by the lower layer implementing the transport
- * when a channel listener must be closed due to an error condition. This
- * does not call the channel listener's close method, since the lower layer
- * already knows.
- */
-
-void
-channel_listener_close_for_error(channel_listener_t *chan_l)
-{
- tor_assert(chan_l != NULL);
-
- /* If it's already in CLOSING, CLOSED or ERROR, this is a no-op */
- if (chan_l->state == CHANNEL_LISTENER_STATE_CLOSING ||
- chan_l->state == CHANNEL_LISTENER_STATE_CLOSED ||
- chan_l->state == CHANNEL_LISTENER_STATE_ERROR) return;
-
- log_debug(LD_CHANNEL,
- "Closing channel listener %p (global ID " U64_FORMAT ") "
- "due to lower-layer error",
- chan_l, U64_PRINTF_ARG(chan_l->global_identifier));
-
- /* Note closing by event from below */
- chan_l->reason_for_closing = CHANNEL_LISTENER_CLOSE_FOR_ERROR;
-
- /* Change state to CLOSING */
- channel_listener_change_state(chan_l, CHANNEL_LISTENER_STATE_CLOSING);
-}
-
-/**
* Notify that the lower layer is finished closing the channel
*
* This function should be called by the lower layer when a channel
@@ -1522,33 +1311,6 @@ channel_closed(channel_t *chan)
}
/**
- * Notify that the lower layer is finished closing the channel listener
- *
- * This function should be called by the lower layer when a channel listener
- * is finished closing and it should be regarded as inactive and
- * freed by the channel code.
- */
-
-void
-channel_listener_closed(channel_listener_t *chan_l)
-{
- tor_assert(chan_l);
- tor_assert(chan_l->state == CHANNEL_LISTENER_STATE_CLOSING ||
- chan_l->state == CHANNEL_LISTENER_STATE_CLOSED ||
- chan_l->state == CHANNEL_LISTENER_STATE_ERROR);
-
- /* No-op if already inactive */
- if (chan_l->state == CHANNEL_LISTENER_STATE_CLOSED ||
- chan_l->state == CHANNEL_LISTENER_STATE_ERROR) return;
-
- if (chan_l->reason_for_closing != CHANNEL_LISTENER_CLOSE_FOR_ERROR) {
- channel_listener_change_state(chan_l, CHANNEL_LISTENER_STATE_CLOSED);
- } else {
- channel_listener_change_state(chan_l, CHANNEL_LISTENER_STATE_ERROR);
- }
-}
-
-/**
* Clear the identity_digest of a channel
*
* This function clears the identity digest of the remote endpoint for a
@@ -1638,7 +1400,7 @@ channel_set_identity_digest(channel_t *chan,
}
/**
- * Clear the remote end metadata (identity_digest/nickname) of a channel
+ * Clear the remote end metadata (identity_digest) of a channel
*
* This function clears all the remote end info from a channel; this is
* intended for use by the lower layer.
@@ -1665,419 +1427,95 @@ channel_clear_remote_end(channel_t *chan)
memset(chan->identity_digest, 0,
sizeof(chan->identity_digest));
- tor_free(chan->nickname);
}
/**
- * Set the remote end metadata (identity_digest/nickname) of a channel
+ * Write to a channel the given packed cell.
*
- * This function sets new remote end info on a channel; this is intended
- * for use by the lower layer.
- */
-
-void
-channel_set_remote_end(channel_t *chan,
- const char *identity_digest,
- const char *nickname)
-{
- int was_in_digest_map, should_be_in_digest_map, state_not_in_map;
-
- tor_assert(chan);
-
- log_debug(LD_CHANNEL,
- "Setting remote endpoint identity on channel %p with "
- "global ID " U64_FORMAT " to nickname %s, digest %s",
- chan, U64_PRINTF_ARG(chan->global_identifier),
- nickname ? nickname : "(null)",
- identity_digest ?
- hex_str(identity_digest, DIGEST_LEN) : "(null)");
-
- state_not_in_map = CHANNEL_CONDEMNED(chan);
-
- was_in_digest_map =
- !state_not_in_map &&
- chan->registered &&
- !tor_digest_is_zero(chan->identity_digest);
- should_be_in_digest_map =
- !state_not_in_map &&
- chan->registered &&
- (identity_digest &&
- !tor_digest_is_zero(identity_digest));
-
- if (was_in_digest_map)
- /* We should always remove it; we'll add it back if we're writing
- * in a new digest.
- */
- channel_remove_from_digest_map(chan);
-
- if (identity_digest) {
- memcpy(chan->identity_digest,
- identity_digest,
- sizeof(chan->identity_digest));
-
- } else {
- memset(chan->identity_digest, 0,
- sizeof(chan->identity_digest));
- }
-
- tor_free(chan->nickname);
- if (nickname)
- chan->nickname = tor_strdup(nickname);
-
- /* Put it in the digest map if we should */
- if (should_be_in_digest_map)
- channel_add_to_digest_map(chan);
-}
-
-/**
- * Duplicate a cell queue entry; this is a shallow copy intended for use
- * in channel_write_cell_queue_entry().
- */
-
-static cell_queue_entry_t *
-cell_queue_entry_dup(cell_queue_entry_t *q)
-{
- cell_queue_entry_t *rv = NULL;
-
- tor_assert(q);
-
- rv = tor_malloc(sizeof(*rv));
- memcpy(rv, q, sizeof(*rv));
-
- return rv;
-}
-
-/**
- * Free a cell_queue_entry_t; the handed_off parameter indicates whether
- * the contents were passed to the lower layer (it is responsible for
- * them) or not (we should free).
- */
-
-STATIC void
-cell_queue_entry_free(cell_queue_entry_t *q, int handed_off)
-{
- if (!q) return;
-
- if (!handed_off) {
- /*
- * If we handed it off, the recipient becomes responsible (or
- * with packed cells the channel_t subclass calls packed_cell
- * free after writing out its contents; see, e.g.,
- * channel_tls_write_packed_cell_method(). Otherwise, we have
- * to take care of it here if possible.
- */
- switch (q->type) {
- case CELL_QUEUE_FIXED:
- if (q->u.fixed.cell) {
- /*
- * There doesn't seem to be a cell_free() function anywhere in the
- * pre-channel code; just use tor_free()
- */
- tor_free(q->u.fixed.cell);
- }
- break;
- case CELL_QUEUE_PACKED:
- if (q->u.packed.packed_cell) {
- packed_cell_free(q->u.packed.packed_cell);
- }
- break;
- case CELL_QUEUE_VAR:
- if (q->u.var.var_cell) {
- /*
- * This one's in connection_or.c; it'd be nice to figure out the
- * whole flow of cells from one end to the other and factor the
- * cell memory management functions like this out of the specific
- * TLS lower layer.
- */
- var_cell_free(q->u.var.var_cell);
- }
- break;
- default:
- /*
- * Nothing we can do if we don't know the type; this will
- * have been warned about elsewhere.
- */
- break;
- }
- }
- tor_free(q);
-}
-
-#if 0
-/**
- * Check whether a cell queue entry is padding; this is a helper function
- * for channel_write_cell_queue_entry()
- */
-
-static int
-cell_queue_entry_is_padding(cell_queue_entry_t *q)
-{
- tor_assert(q);
-
- if (q->type == CELL_QUEUE_FIXED) {
- if (q->u.fixed.cell) {
- if (q->u.fixed.cell->command == CELL_PADDING ||
- q->u.fixed.cell->command == CELL_VPADDING) {
- return 1;
- }
- }
- } else if (q->type == CELL_QUEUE_VAR) {
- if (q->u.var.var_cell) {
- if (q->u.var.var_cell->command == CELL_PADDING ||
- q->u.var.var_cell->command == CELL_VPADDING) {
- return 1;
- }
- }
- }
-
- return 0;
-}
-#endif /* 0 */
-
-/**
- * Allocate a new cell queue entry for a fixed-size cell
- */
-
-static cell_queue_entry_t *
-cell_queue_entry_new_fixed(cell_t *cell)
-{
- cell_queue_entry_t *q = NULL;
-
- tor_assert(cell);
-
- q = tor_malloc(sizeof(*q));
- q->type = CELL_QUEUE_FIXED;
- q->u.fixed.cell = cell;
-
- return q;
-}
-
-/**
- * Allocate a new cell queue entry for a variable-size cell
- */
-
-static cell_queue_entry_t *
-cell_queue_entry_new_var(var_cell_t *var_cell)
-{
- cell_queue_entry_t *q = NULL;
-
- tor_assert(var_cell);
-
- q = tor_malloc(sizeof(*q));
- q->type = CELL_QUEUE_VAR;
- q->u.var.var_cell = var_cell;
-
- return q;
-}
-
-/**
- * Ask how big the cell contained in a cell_queue_entry_t is
- */
-
-static size_t
-channel_get_cell_queue_entry_size(channel_t *chan, cell_queue_entry_t *q)
-{
- size_t rv = 0;
-
- tor_assert(chan);
- tor_assert(q);
-
- switch (q->type) {
- case CELL_QUEUE_FIXED:
- rv = get_cell_network_size(chan->wide_circ_ids);
- break;
- case CELL_QUEUE_VAR:
- rv = get_var_cell_header_size(chan->wide_circ_ids) +
- (q->u.var.var_cell ? q->u.var.var_cell->payload_len : 0);
- break;
- case CELL_QUEUE_PACKED:
- rv = get_cell_network_size(chan->wide_circ_ids);
- break;
- default:
- tor_assert_nonfatal_unreached_once();
- }
-
- return rv;
-}
-
-/**
- * Write to a channel based on a cell_queue_entry_t
*
- * Given a cell_queue_entry_t filled out by the caller, try to send the cell
- * and queue it if we can't.
+ * Two possible errors can happen. Either the channel is not opened or the
+ * lower layer (specialized channel) failed to write it. In both cases, it is
+ * the caller responsability to free the cell.
*/
-
-static void
-channel_write_cell_queue_entry(channel_t *chan, cell_queue_entry_t *q)
+static int
+write_packed_cell(channel_t *chan, packed_cell_t *cell)
{
- int result = 0, sent = 0;
- cell_queue_entry_t *tmp = NULL;
+ int ret = -1;
size_t cell_bytes;
tor_assert(chan);
- tor_assert(q);
+ tor_assert(cell);
/* Assert that the state makes sense for a cell write */
tor_assert(CHANNEL_CAN_HANDLE_CELLS(chan));
{
circid_t circ_id;
- if (is_destroy_cell(chan, q, &circ_id)) {
+ if (packed_cell_is_destroy(chan, cell, &circ_id)) {
channel_note_destroy_not_pending(chan, circ_id);
}
}
/* For statistical purposes, figure out how big this cell is */
- cell_bytes = channel_get_cell_queue_entry_size(chan, q);
+ cell_bytes = get_cell_network_size(chan->wide_circ_ids);
/* Can we send it right out? If so, try */
- if (TOR_SIMPLEQ_EMPTY(&chan->outgoing_queue) &&
- CHANNEL_IS_OPEN(chan)) {
- /* Pick the right write function for this cell type and save the result */
- switch (q->type) {
- case CELL_QUEUE_FIXED:
- tor_assert(chan->write_cell);
- tor_assert(q->u.fixed.cell);
- result = chan->write_cell(chan, q->u.fixed.cell);
- break;
- case CELL_QUEUE_PACKED:
- tor_assert(chan->write_packed_cell);
- tor_assert(q->u.packed.packed_cell);
- result = chan->write_packed_cell(chan, q->u.packed.packed_cell);
- break;
- case CELL_QUEUE_VAR:
- tor_assert(chan->write_var_cell);
- tor_assert(q->u.var.var_cell);
- result = chan->write_var_cell(chan, q->u.var.var_cell);
- break;
- default:
- tor_assert(1);
- }
-
- /* Check if we got it out */
- if (result > 0) {
- sent = 1;
- /* Timestamp for transmission */
- channel_timestamp_xmit(chan);
- /* If we're here the queue is empty, so it's drained too */
- channel_timestamp_drained(chan);
- /* Update the counter */
- ++(chan->n_cells_xmitted);
- chan->n_bytes_xmitted += cell_bytes;
- /* Update global counters */
- ++n_channel_cells_queued;
- ++n_channel_cells_passed_to_lower_layer;
- n_channel_bytes_queued += cell_bytes;
- n_channel_bytes_passed_to_lower_layer += cell_bytes;
- channel_assert_counter_consistency();
- }
+ if (!CHANNEL_IS_OPEN(chan)) {
+ goto done;
}
- if (!sent) {
- /* Not sent, queue it */
- /*
- * We have to copy the queue entry passed in, since the caller probably
- * used the stack.
- */
- tmp = cell_queue_entry_dup(q);
- TOR_SIMPLEQ_INSERT_TAIL(&chan->outgoing_queue, tmp, next);
- /* Update global counters */
- ++n_channel_cells_queued;
- ++n_channel_cells_in_queues;
- n_channel_bytes_queued += cell_bytes;
- n_channel_bytes_in_queues += cell_bytes;
- channel_assert_counter_consistency();
- /* Update channel queue size */
- chan->bytes_in_queue += cell_bytes;
- /* Try to process the queue? */
- if (CHANNEL_IS_OPEN(chan)) channel_flush_cells(chan);
+ /* Write the cell on the connection's outbuf. */
+ if (chan->write_packed_cell(chan, cell) < 0) {
+ goto done;
}
+ /* Timestamp for transmission */
+ channel_timestamp_xmit(chan);
+ /* Update the counter */
+ ++(chan->n_cells_xmitted);
+ chan->n_bytes_xmitted += cell_bytes;
+ /* Successfully sent the cell. */
+ ret = 0;
+
+ done:
+ return ret;
}
-/** Write a generic cell type to a channel
+/**
+ * Write a packed cell to a channel
+ *
+ * Write a packed cell to a channel using the write_cell() method. This is
+ * called by the transport-independent code to deliver a packed cell to a
+ * channel for transmission.
*
- * Write a generic cell to a channel. It is called by channel_write_cell(),
- * channel_write_var_cell() and channel_write_packed_cell() in order to reduce
- * code duplication. Notice that it takes cell as pointer of type void,
- * this can be dangerous because no type check is performed.
+ * Return 0 on success else a negative value. In both cases, the caller should
+ * not access the cell anymore, it is freed both on success and error.
*/
-
-void
-channel_write_cell_generic_(channel_t *chan, const char *cell_type,
- void *cell, cell_queue_entry_t *q)
+int
+channel_write_packed_cell(channel_t *chan, packed_cell_t *cell)
{
+ int ret = -1;
tor_assert(chan);
tor_assert(cell);
if (CHANNEL_IS_CLOSING(chan)) {
- log_debug(LD_CHANNEL, "Discarding %c %p on closing channel %p with "
- "global ID "U64_FORMAT, *cell_type, cell, chan,
+ log_debug(LD_CHANNEL, "Discarding %p on closing channel %p with "
+ "global ID "U64_FORMAT, cell, chan,
U64_PRINTF_ARG(chan->global_identifier));
- tor_free(cell);
- return;
+ goto end;
}
log_debug(LD_CHANNEL,
- "Writing %c %p to channel %p with global ID "
- U64_FORMAT, *cell_type,
- cell, chan, U64_PRINTF_ARG(chan->global_identifier));
-
- channel_write_cell_queue_entry(chan, q);
- /* Update the queue size estimate */
- channel_update_xmit_queue_size(chan);
-}
-
-/**
- * Write a cell to a channel
- *
- * Write a fixed-length cell to a channel using the write_cell() method.
- * This is equivalent to the pre-channels connection_or_write_cell_to_buf();
- * it is called by the transport-independent code to deliver a cell to a
- * channel for transmission.
- */
+ "Writing %p to channel %p with global ID "
+ U64_FORMAT, cell, chan, U64_PRINTF_ARG(chan->global_identifier));
-void
-channel_write_cell(channel_t *chan, cell_t *cell)
-{
- cell_queue_entry_t q;
- q.type = CELL_QUEUE_FIXED;
- q.u.fixed.cell = cell;
- channel_write_cell_generic_(chan, "cell_t", cell, &q);
-}
+ ret = write_packed_cell(chan, cell);
-/**
- * Write a packed cell to a channel
- *
- * Write a packed cell to a channel using the write_cell() method. This is
- * called by the transport-independent code to deliver a packed cell to a
- * channel for transmission.
- */
-
-void
-channel_write_packed_cell(channel_t *chan, packed_cell_t *packed_cell)
-{
- cell_queue_entry_t q;
- q.type = CELL_QUEUE_PACKED;
- q.u.packed.packed_cell = packed_cell;
- channel_write_cell_generic_(chan, "packed_cell_t", packed_cell, &q);
-}
-
-/**
- * Write a variable-length cell to a channel
- *
- * Write a variable-length cell to a channel using the write_cell() method.
- * This is equivalent to the pre-channels
- * connection_or_write_var_cell_to_buf(); it's called by the transport-
- * independent code to deliver a var_cell to a channel for transmission.
- */
-
-void
-channel_write_var_cell(channel_t *chan, var_cell_t *var_cell)
-{
- cell_queue_entry_t q;
- q.type = CELL_QUEUE_VAR;
- q.u.var.var_cell = var_cell;
- channel_write_cell_generic_(chan, "var_cell_t", var_cell, &q);
+ end:
+ /* Whatever happens, we free the cell. Either an error occured or the cell
+ * was put on the connection outbuf, both cases we have ownership of the
+ * cell and we free it. */
+ packed_cell_free(cell);
+ return ret;
}
/**
@@ -2119,15 +1557,6 @@ channel_change_state_(channel_t *chan, channel_state_t to_state)
tor_assert(chan->reason_for_closing != CHANNEL_NOT_CLOSING);
}
- /*
- * We need to maintain the queues here for some transitions:
- * when we enter CHANNEL_STATE_OPEN (especially from CHANNEL_STATE_MAINT)
- * we may have a backlog of cells to transmit, so drain the queues in
- * that case, and when going to CHANNEL_STATE_CLOSED the subclass
- * should have made sure to finish sending things (or gone to
- * CHANNEL_STATE_ERROR if not possible), so we assert for that here.
- */
-
log_debug(LD_CHANNEL,
"Changing state of channel %p (global ID " U64_FORMAT
") from \"%s\" to \"%s\"",
@@ -2184,36 +1613,6 @@ channel_change_state_(channel_t *chan, channel_state_t to_state)
} else if (to_state == CHANNEL_STATE_MAINT) {
scheduler_channel_doesnt_want_writes(chan);
}
-
- /*
- * If we're closing, this channel no longer counts toward the global
- * estimated queue size; if we're open, it now does.
- */
- if ((to_state == CHANNEL_STATE_CLOSING ||
- to_state == CHANNEL_STATE_CLOSED ||
- to_state == CHANNEL_STATE_ERROR) &&
- (from_state == CHANNEL_STATE_OPEN ||
- from_state == CHANNEL_STATE_MAINT)) {
- estimated_total_queue_size -= chan->bytes_in_queue;
- }
-
- /*
- * If we're opening, this channel now does count toward the global
- * estimated queue size.
- */
- if ((to_state == CHANNEL_STATE_OPEN ||
- to_state == CHANNEL_STATE_MAINT) &&
- !(from_state == CHANNEL_STATE_OPEN ||
- from_state == CHANNEL_STATE_MAINT)) {
- estimated_total_queue_size += chan->bytes_in_queue;
- }
-
- if (to_state == CHANNEL_STATE_CLOSED ||
- to_state == CHANNEL_STATE_ERROR) {
- /* Assert that all queues are empty */
- tor_assert(TOR_SIMPLEQ_EMPTY(&chan->incoming_queue));
- tor_assert(TOR_SIMPLEQ_EMPTY(&chan->outgoing_queue));
- }
}
/**
@@ -2237,12 +1636,6 @@ channel_change_state_open(channel_t *chan)
/* Tell circuits if we opened and stuff */
channel_do_open_actions(chan);
chan->has_been_open = 1;
-
- /* Check for queued cells to process */
- if (! TOR_SIMPLEQ_EMPTY(&chan->incoming_queue))
- channel_process_cells(chan);
- if (! TOR_SIMPLEQ_EMPTY(&chan->outgoing_queue))
- channel_flush_cells(chan);
}
/**
@@ -2284,15 +1677,6 @@ channel_listener_change_state(channel_listener_t *chan_l,
tor_assert(chan_l->reason_for_closing != CHANNEL_LISTENER_NOT_CLOSING);
}
- /*
- * We need to maintain the queues here for some transitions:
- * when we enter CHANNEL_STATE_OPEN (especially from CHANNEL_STATE_MAINT)
- * we may have a backlog of cells to transmit, so drain the queues in
- * that case, and when going to CHANNEL_STATE_CLOSED the subclass
- * should have made sure to finish sending things (or gone to
- * CHANNEL_STATE_ERROR if not possible), so we assert for that here.
- */
-
log_debug(LD_CHANNEL,
"Changing state of channel listener %p (global ID " U64_FORMAT
"from \"%s\" to \"%s\"",
@@ -2325,30 +1709,38 @@ channel_listener_change_state(channel_listener_t *chan_l,
if (to_state == CHANNEL_LISTENER_STATE_CLOSED ||
to_state == CHANNEL_LISTENER_STATE_ERROR) {
- /* Assert that the queue is empty */
tor_assert(!(chan_l->incoming_list) ||
smartlist_len(chan_l->incoming_list) == 0);
}
}
-/**
- * Try to flush cells to the lower layer
- *
- * this is called by the lower layer to indicate that it wants more cells;
- * it will try to write up to num_cells cells from the channel's cell queue or
- * from circuits active on that channel, or as many as it has available if
- * num_cells == -1.
- */
-
+/* Maximum number of cells that is allowed to flush at once withing
+ * channel_flush_some_cells(). */
#define MAX_CELLS_TO_GET_FROM_CIRCUITS_FOR_UNLIMITED 256
+/* Try to flush cells of the given channel chan up to a maximum of num_cells.
+ *
+ * This is called by the scheduler when it wants to flush cells from the
+ * channel's circuit queue(s) to the connection outbuf (not yet on the wire).
+ *
+ * If the channel is not in state CHANNEL_STATE_OPEN, this does nothing and
+ * will return 0 meaning no cells were flushed.
+ *
+ * If num_cells is -1, we'll try to flush up to the maximum cells allowed
+ * defined in MAX_CELLS_TO_GET_FROM_CIRCUITS_FOR_UNLIMITED.
+ *
+ * On success, the number of flushed cells are returned and it can never be
+ * above num_cells. If 0 is returned, no cells were flushed either because the
+ * channel was not opened or we had no cells on the channel. A negative number
+ * can NOT be sent back.
+ *
+ * This function is part of the fast path. */
MOCK_IMPL(ssize_t,
channel_flush_some_cells, (channel_t *chan, ssize_t num_cells))
{
unsigned int unlimited = 0;
ssize_t flushed = 0;
- int num_cells_from_circs, clamped_num_cells;
- int q_len_before, q_len_after;
+ int clamped_num_cells;
tor_assert(chan);
@@ -2357,11 +1749,6 @@ channel_flush_some_cells, (channel_t *chan, ssize_t num_cells))
/* If we aren't in CHANNEL_STATE_OPEN, nothing goes through */
if (CHANNEL_IS_OPEN(chan)) {
- /* Try to flush as much as we can that's already queued */
- flushed += channel_flush_some_cells_from_outgoing_queue(chan,
- (unlimited ? -1 : num_cells - flushed));
- if (!unlimited && num_cells <= flushed) goto done;
-
if (circuitmux_num_cells(chan->cmux) > 0) {
/* Calculate number of cells, including clamp */
if (unlimited) {
@@ -2375,45 +1762,9 @@ channel_flush_some_cells, (channel_t *chan, ssize_t num_cells))
}
}
- /*
- * Keep track of the change in queue size; we have to count cells
- * channel_flush_from_first_active_circuit() writes out directly,
- * but not double-count ones we might get later in
- * channel_flush_some_cells_from_outgoing_queue()
- */
- q_len_before = chan_cell_queue_len(&(chan->outgoing_queue));
-
/* Try to get more cells from any active circuits */
- num_cells_from_circs = channel_flush_from_first_active_circuit(
+ flushed = channel_flush_from_first_active_circuit(
chan, clamped_num_cells);
-
- q_len_after = chan_cell_queue_len(&(chan->outgoing_queue));
-
- /*
- * If it claims we got some, adjust the flushed counter and consider
- * processing the queue again
- */
- if (num_cells_from_circs > 0) {
- /*
- * Adjust flushed by the number of cells counted in
- * num_cells_from_circs that didn't go to the cell queue.
- */
-
- if (q_len_after > q_len_before) {
- num_cells_from_circs -= (q_len_after - q_len_before);
- if (num_cells_from_circs < 0) num_cells_from_circs = 0;
- }
-
- flushed += num_cells_from_circs;
-
- /* Now process the queue if necessary */
-
- if ((q_len_after > q_len_before) &&
- (unlimited || (flushed < num_cells))) {
- flushed += channel_flush_some_cells_from_outgoing_queue(chan,
- (unlimited ? -1 : num_cells - flushed));
- }
- }
}
}
@@ -2422,197 +1773,16 @@ channel_flush_some_cells, (channel_t *chan, ssize_t num_cells))
}
/**
- * Flush cells from just the channel's outgoing cell queue
- *
- * This gets called from channel_flush_some_cells() above to flush cells
- * just from the queue without trying for active_circuits.
- */
-
-static ssize_t
-channel_flush_some_cells_from_outgoing_queue(channel_t *chan,
- ssize_t num_cells)
-{
- unsigned int unlimited = 0;
- ssize_t flushed = 0;
- cell_queue_entry_t *q = NULL;
- size_t cell_size;
- int free_q = 0, handed_off = 0;
-
- tor_assert(chan);
- tor_assert(chan->write_cell);
- tor_assert(chan->write_packed_cell);
- tor_assert(chan->write_var_cell);
-
- if (num_cells < 0) unlimited = 1;
- if (!unlimited && num_cells <= flushed) return 0;
-
- /* If we aren't in CHANNEL_STATE_OPEN, nothing goes through */
- if (CHANNEL_IS_OPEN(chan)) {
- while ((unlimited || num_cells > flushed) &&
- NULL != (q = TOR_SIMPLEQ_FIRST(&chan->outgoing_queue))) {
- free_q = 0;
- handed_off = 0;
-
- /* Figure out how big it is for statistical purposes */
- cell_size = channel_get_cell_queue_entry_size(chan, q);
- /*
- * Okay, we have a good queue entry, try to give it to the lower
- * layer.
- */
- switch (q->type) {
- case CELL_QUEUE_FIXED:
- if (q->u.fixed.cell) {
- if (chan->write_cell(chan,
- q->u.fixed.cell)) {
- ++flushed;
- channel_timestamp_xmit(chan);
- ++(chan->n_cells_xmitted);
- chan->n_bytes_xmitted += cell_size;
- free_q = 1;
- handed_off = 1;
- }
- /* Else couldn't write it; leave it on the queue */
- } else {
- /* This shouldn't happen */
- log_info(LD_CHANNEL,
- "Saw broken cell queue entry of type CELL_QUEUE_FIXED "
- "with no cell on channel %p "
- "(global ID " U64_FORMAT ").",
- chan, U64_PRINTF_ARG(chan->global_identifier));
- /* Throw it away */
- free_q = 1;
- handed_off = 0;
- }
- break;
- case CELL_QUEUE_PACKED:
- if (q->u.packed.packed_cell) {
- if (chan->write_packed_cell(chan,
- q->u.packed.packed_cell)) {
- ++flushed;
- channel_timestamp_xmit(chan);
- ++(chan->n_cells_xmitted);
- chan->n_bytes_xmitted += cell_size;
- free_q = 1;
- handed_off = 1;
- }
- /* Else couldn't write it; leave it on the queue */
- } else {
- /* This shouldn't happen */
- log_info(LD_CHANNEL,
- "Saw broken cell queue entry of type CELL_QUEUE_PACKED "
- "with no cell on channel %p "
- "(global ID " U64_FORMAT ").",
- chan, U64_PRINTF_ARG(chan->global_identifier));
- /* Throw it away */
- free_q = 1;
- handed_off = 0;
- }
- break;
- case CELL_QUEUE_VAR:
- if (q->u.var.var_cell) {
- if (chan->write_var_cell(chan,
- q->u.var.var_cell)) {
- ++flushed;
- channel_timestamp_xmit(chan);
- ++(chan->n_cells_xmitted);
- chan->n_bytes_xmitted += cell_size;
- free_q = 1;
- handed_off = 1;
- }
- /* Else couldn't write it; leave it on the queue */
- } else {
- /* This shouldn't happen */
- log_info(LD_CHANNEL,
- "Saw broken cell queue entry of type CELL_QUEUE_VAR "
- "with no cell on channel %p "
- "(global ID " U64_FORMAT ").",
- chan, U64_PRINTF_ARG(chan->global_identifier));
- /* Throw it away */
- free_q = 1;
- handed_off = 0;
- }
- break;
- default:
- /* Unknown type, log and free it */
- log_info(LD_CHANNEL,
- "Saw an unknown cell queue entry type %d on channel %p "
- "(global ID " U64_FORMAT "; ignoring it."
- " Someone should fix this.",
- q->type, chan, U64_PRINTF_ARG(chan->global_identifier));
- free_q = 1;
- handed_off = 0;
- }
-
- /*
- * if free_q is set, we used it and should remove the queue entry;
- * we have to do the free down here so TOR_SIMPLEQ_REMOVE_HEAD isn't
- * accessing freed memory
- */
- if (free_q) {
- TOR_SIMPLEQ_REMOVE_HEAD(&chan->outgoing_queue, next);
- /*
- * ...and we handed a cell off to the lower layer, so we should
- * update the counters.
- */
- ++n_channel_cells_passed_to_lower_layer;
- --n_channel_cells_in_queues;
- n_channel_bytes_passed_to_lower_layer += cell_size;
- n_channel_bytes_in_queues -= cell_size;
- channel_assert_counter_consistency();
- /* Update the channel's queue size too */
- chan->bytes_in_queue -= cell_size;
- /* Finally, free q */
- cell_queue_entry_free(q, handed_off);
- q = NULL;
- } else {
- /* No cell removed from list, so we can't go on any further */
- break;
- }
- }
- }
-
- /* Did we drain the queue? */
- if (TOR_SIMPLEQ_EMPTY(&chan->outgoing_queue)) {
- channel_timestamp_drained(chan);
- }
-
- /* Update the estimate queue size */
- channel_update_xmit_queue_size(chan);
-
- return flushed;
-}
-
-/**
- * Flush as many cells as we possibly can from the queue
- *
- * This tries to flush as many cells from the queue as the lower layer
- * will take. It just calls channel_flush_some_cells_from_outgoing_queue()
- * in unlimited mode.
- */
-
-void
-channel_flush_cells(channel_t *chan)
-{
- channel_flush_some_cells_from_outgoing_queue(chan, -1);
-}
-
-/**
* Check if any cells are available
*
- * This gets used from the lower layer to check if any more cells are
- * available.
+ * This is used by the scheduler to know if the channel has more to flush
+ * after a scheduling round.
*/
-
MOCK_IMPL(int,
channel_more_to_flush, (channel_t *chan))
{
tor_assert(chan);
- /* Check if we have any queued */
- if (! TOR_SIMPLEQ_EMPTY(&chan->incoming_queue))
- return 1;
-
- /* Check if any circuits would like to queue some */
if (circuitmux_num_cells(chan->cmux) > 0) return 1;
/* Else no */
@@ -2816,207 +1986,31 @@ channel_listener_queue_incoming(channel_listener_t *listener,
}
/**
- * Process queued incoming cells
- *
- * Process as many queued cells as we can from the incoming
- * cell queue.
+ * Process a cell from the given channel.
*/
-
void
-channel_process_cells(channel_t *chan)
+channel_process_cell(channel_t *chan, cell_t *cell)
{
- cell_queue_entry_t *q;
tor_assert(chan);
tor_assert(CHANNEL_IS_CLOSING(chan) || CHANNEL_IS_MAINT(chan) ||
CHANNEL_IS_OPEN(chan));
-
- log_debug(LD_CHANNEL,
- "Processing as many incoming cells as we can for channel %p",
- chan);
-
- /* Nothing we can do if we have no registered cell handlers */
- if (!(chan->cell_handler ||
- chan->var_cell_handler)) return;
- /* Nothing we can do if we have no cells */
- if (TOR_SIMPLEQ_EMPTY(&chan->incoming_queue)) return;
-
- /*
- * Process cells until we're done or find one we have no current handler
- * for.
- *
- * We must free the cells here after calling the handler, since custody
- * of the buffer was given to the channel layer when they were queued;
- * see comments on memory management in channel_queue_cell() and in
- * channel_queue_var_cell() below.
- */
- while (NULL != (q = TOR_SIMPLEQ_FIRST(&chan->incoming_queue))) {
- tor_assert(q);
- tor_assert(q->type == CELL_QUEUE_FIXED ||
- q->type == CELL_QUEUE_VAR);
-
- if (q->type == CELL_QUEUE_FIXED &&
- chan->cell_handler) {
- /* Handle a fixed-length cell */
- TOR_SIMPLEQ_REMOVE_HEAD(&chan->incoming_queue, next);
- tor_assert(q->u.fixed.cell);
- log_debug(LD_CHANNEL,
- "Processing incoming cell_t %p for channel %p (global ID "
- U64_FORMAT ")",
- q->u.fixed.cell, chan,
- U64_PRINTF_ARG(chan->global_identifier));
- chan->cell_handler(chan, q->u.fixed.cell);
- tor_free(q->u.fixed.cell);
- tor_free(q);
- } else if (q->type == CELL_QUEUE_VAR &&
- chan->var_cell_handler) {
- /* Handle a variable-length cell */
- TOR_SIMPLEQ_REMOVE_HEAD(&chan->incoming_queue, next);
- tor_assert(q->u.var.var_cell);
- log_debug(LD_CHANNEL,
- "Processing incoming var_cell_t %p for channel %p (global ID "
- U64_FORMAT ")",
- q->u.var.var_cell, chan,
- U64_PRINTF_ARG(chan->global_identifier));
- chan->var_cell_handler(chan, q->u.var.var_cell);
- tor_free(q->u.var.var_cell);
- tor_free(q);
- } else {
- /* Can't handle this one */
- break;
- }
- }
-}
-
-/**
- * Queue incoming cell
- *
- * This should be called by a channel_t subclass to queue an incoming fixed-
- * length cell for processing, and process it if possible.
- */
-
-void
-channel_queue_cell(channel_t *chan, cell_t *cell)
-{
- int need_to_queue = 0;
- cell_queue_entry_t *q;
- cell_t *cell_copy = NULL;
-
- tor_assert(chan);
tor_assert(cell);
- tor_assert(CHANNEL_IS_OPEN(chan));
- /* Do we need to queue it, or can we just call the handler right away? */
- if (!(chan->cell_handler)) need_to_queue = 1;
- if (! TOR_SIMPLEQ_EMPTY(&chan->incoming_queue))
- need_to_queue = 1;
+ /* Nothing we can do if we have no registered cell handlers */
+ if (!chan->cell_handler)
+ return;
/* Timestamp for receiving */
channel_timestamp_recv(chan);
-
- /* Update the counters */
+ /* Update received counter. */
++(chan->n_cells_recved);
chan->n_bytes_recved += get_cell_network_size(chan->wide_circ_ids);
- /* If we don't need to queue we can just call cell_handler */
- if (!need_to_queue) {
- tor_assert(chan->cell_handler);
- log_debug(LD_CHANNEL,
- "Directly handling incoming cell_t %p for channel %p "
- "(global ID " U64_FORMAT ")",
- cell, chan,
- U64_PRINTF_ARG(chan->global_identifier));
- chan->cell_handler(chan, cell);
- } else {
- /*
- * Otherwise queue it and then process the queue if possible.
- *
- * We queue a copy, not the original pointer - it might have been on the
- * stack in connection_or_process_cells_from_inbuf() (or another caller
- * if we ever have a subclass other than channel_tls_t), or be freed
- * there after we return. This is the uncommon case; the non-copying
- * fast path occurs in the if (!need_to_queue) case above when the
- * upper layer has installed cell handlers.
- */
- cell_copy = tor_malloc_zero(sizeof(cell_t));
- memcpy(cell_copy, cell, sizeof(cell_t));
- q = cell_queue_entry_new_fixed(cell_copy);
- log_debug(LD_CHANNEL,
- "Queueing incoming cell_t %p for channel %p "
- "(global ID " U64_FORMAT ")",
- cell, chan,
- U64_PRINTF_ARG(chan->global_identifier));
- TOR_SIMPLEQ_INSERT_TAIL(&chan->incoming_queue, q, next);
- if (chan->cell_handler ||
- chan->var_cell_handler) {
- channel_process_cells(chan);
- }
- }
-}
-
-/**
- * Queue incoming variable-length cell
- *
- * This should be called by a channel_t subclass to queue an incoming
- * variable-length cell for processing, and process it if possible.
- */
-
-void
-channel_queue_var_cell(channel_t *chan, var_cell_t *var_cell)
-{
- int need_to_queue = 0;
- cell_queue_entry_t *q;
- var_cell_t *cell_copy = NULL;
-
- tor_assert(chan);
- tor_assert(var_cell);
- tor_assert(CHANNEL_IS_OPEN(chan));
-
- /* Do we need to queue it, or can we just call the handler right away? */
- if (!(chan->var_cell_handler)) need_to_queue = 1;
- if (! TOR_SIMPLEQ_EMPTY(&chan->incoming_queue))
- need_to_queue = 1;
-
- /* Timestamp for receiving */
- channel_timestamp_recv(chan);
-
- /* Update the counter */
- ++(chan->n_cells_recved);
- chan->n_bytes_recved += get_var_cell_header_size(chan->wide_circ_ids) +
- var_cell->payload_len;
-
- /* If we don't need to queue we can just call cell_handler */
- if (!need_to_queue) {
- tor_assert(chan->var_cell_handler);
- log_debug(LD_CHANNEL,
- "Directly handling incoming var_cell_t %p for channel %p "
- "(global ID " U64_FORMAT ")",
- var_cell, chan,
- U64_PRINTF_ARG(chan->global_identifier));
- chan->var_cell_handler(chan, var_cell);
- } else {
- /*
- * Otherwise queue it and then process the queue if possible.
- *
- * We queue a copy, not the original pointer - it might have been on the
- * stack in connection_or_process_cells_from_inbuf() (or another caller
- * if we ever have a subclass other than channel_tls_t), or be freed
- * there after we return. This is the uncommon case; the non-copying
- * fast path occurs in the if (!need_to_queue) case above when the
- * upper layer has installed cell handlers.
- */
- cell_copy = var_cell_copy(var_cell);
- q = cell_queue_entry_new_var(cell_copy);
- log_debug(LD_CHANNEL,
- "Queueing incoming var_cell_t %p for channel %p "
- "(global ID " U64_FORMAT ")",
- var_cell, chan,
- U64_PRINTF_ARG(chan->global_identifier));
- TOR_SIMPLEQ_INSERT_TAIL(&chan->incoming_queue, q, next);
- if (chan->cell_handler ||
- chan->var_cell_handler) {
- channel_process_cells(chan);
- }
- }
+ log_debug(LD_CHANNEL,
+ "Processing incoming cell_t %p for channel %p (global ID "
+ U64_FORMAT ")", cell, chan,
+ U64_PRINTF_ARG(chan->global_identifier));
+ chan->cell_handler(chan, cell);
}
/** If <b>packed_cell</b> on <b>chan</b> is a destroy cell, then set
@@ -3043,44 +2037,6 @@ packed_cell_is_destroy(channel_t *chan,
}
/**
- * Assert that the global channel stats counters are internally consistent
- */
-
-static void
-channel_assert_counter_consistency(void)
-{
- tor_assert(n_channel_cells_queued ==
- (n_channel_cells_in_queues + n_channel_cells_passed_to_lower_layer));
- tor_assert(n_channel_bytes_queued ==
- (n_channel_bytes_in_queues + n_channel_bytes_passed_to_lower_layer));
-}
-
-/* DOCDOC */
-static int
-is_destroy_cell(channel_t *chan,
- const cell_queue_entry_t *q, circid_t *circid_out)
-{
- *circid_out = 0;
- switch (q->type) {
- case CELL_QUEUE_FIXED:
- if (q->u.fixed.cell->command == CELL_DESTROY) {
- *circid_out = q->u.fixed.cell->circ_id;
- return 1;
- }
- break;
- case CELL_QUEUE_VAR:
- if (q->u.var.var_cell->command == CELL_DESTROY) {
- *circid_out = q->u.var.var_cell->circ_id;
- return 1;
- }
- break;
- case CELL_QUEUE_PACKED:
- return packed_cell_is_destroy(chan, q->u.packed.packed_cell, circid_out);
- }
- return 0;
-}
-
-/**
* Send destroy cell on a channel
*
* Write a destroy cell with circ ID <b>circ_id</b> and reason <b>reason</b>
@@ -3134,19 +2090,6 @@ channel_dumpstats(int severity)
{
if (all_channels && smartlist_len(all_channels) > 0) {
tor_log(severity, LD_GENERAL,
- "Channels have queued " U64_FORMAT " bytes in " U64_FORMAT " cells, "
- "and handed " U64_FORMAT " bytes in " U64_FORMAT " cells to the lower"
- " layer.",
- U64_PRINTF_ARG(n_channel_bytes_queued),
- U64_PRINTF_ARG(n_channel_cells_queued),
- U64_PRINTF_ARG(n_channel_bytes_passed_to_lower_layer),
- U64_PRINTF_ARG(n_channel_cells_passed_to_lower_layer));
- tor_log(severity, LD_GENERAL,
- "There are currently " U64_FORMAT " bytes in " U64_FORMAT " cells "
- "in channel queues.",
- U64_PRINTF_ARG(n_channel_bytes_in_queues),
- U64_PRINTF_ARG(n_channel_cells_in_queues));
- tor_log(severity, LD_GENERAL,
"Dumping statistics about %d channels:",
smartlist_len(all_channels));
tor_log(severity, LD_GENERAL,
@@ -3296,7 +2239,7 @@ channel_free_list(smartlist_t *channels, int mark_for_close)
if (!CHANNEL_CONDEMNED(curr)) {
channel_mark_for_close(curr);
}
- channel_force_free(curr);
+ channel_force_xfree(curr);
} else channel_free(curr);
} SMARTLIST_FOREACH_END(curr);
}
@@ -3325,7 +2268,7 @@ channel_listener_free_list(smartlist_t *listeners, int mark_for_close)
curr->state == CHANNEL_LISTENER_STATE_ERROR)) {
channel_listener_mark_for_close(curr);
}
- channel_listener_force_free(curr);
+ channel_listener_force_xfree(curr);
} else channel_listener_free(curr);
} SMARTLIST_FOREACH_END(curr);
}
@@ -3629,19 +2572,6 @@ channel_listener_describe_transport(channel_listener_t *chan_l)
}
/**
- * Return the number of entries in <b>queue</b>
- */
-STATIC int
-chan_cell_queue_len(const chan_cell_queue_t *queue)
-{
- int r = 0;
- cell_queue_entry_t *cell;
- TOR_SIMPLEQ_FOREACH(cell, queue, next)
- ++r;
- return r;
-}
-
-/**
* Dump channel statistics
*
* Dump statistics for one channel to the log
@@ -3676,35 +2606,18 @@ channel_dump_statistics, (channel_t *chan, int severity))
U64_PRINTF_ARG(chan->timestamp_active),
U64_PRINTF_ARG(now - chan->timestamp_active));
- /* Handle digest and nickname */
+ /* Handle digest. */
if (!tor_digest_is_zero(chan->identity_digest)) {
- if (chan->nickname) {
- tor_log(severity, LD_GENERAL,
- " * Channel " U64_FORMAT " says it is connected "
- "to an OR with digest %s and nickname %s",
- U64_PRINTF_ARG(chan->global_identifier),
- hex_str(chan->identity_digest, DIGEST_LEN),
- chan->nickname);
- } else {
- tor_log(severity, LD_GENERAL,
- " * Channel " U64_FORMAT " says it is connected "
- "to an OR with digest %s and no known nickname",
- U64_PRINTF_ARG(chan->global_identifier),
- hex_str(chan->identity_digest, DIGEST_LEN));
- }
+ tor_log(severity, LD_GENERAL,
+ " * Channel " U64_FORMAT " says it is connected "
+ "to an OR with digest %s",
+ U64_PRINTF_ARG(chan->global_identifier),
+ hex_str(chan->identity_digest, DIGEST_LEN));
} else {
- if (chan->nickname) {
- tor_log(severity, LD_GENERAL,
- " * Channel " U64_FORMAT " does not know the digest"
- " of the OR it is connected to, but reports its nickname is %s",
- U64_PRINTF_ARG(chan->global_identifier),
- chan->nickname);
- } else {
- tor_log(severity, LD_GENERAL,
- " * Channel " U64_FORMAT " does not know the digest"
- " or the nickname of the OR it is connected to",
- U64_PRINTF_ARG(chan->global_identifier));
- }
+ tor_log(severity, LD_GENERAL,
+ " * Channel " U64_FORMAT " does not know the digest"
+ " of the OR it is connected to",
+ U64_PRINTF_ARG(chan->global_identifier));
}
/* Handle remote address and descriptions */
@@ -3753,14 +2666,6 @@ channel_dump_statistics, (channel_t *chan, int severity))
channel_is_incoming(chan) ?
"incoming" : "outgoing");
- /* Describe queues */
- tor_log(severity, LD_GENERAL,
- " * Channel " U64_FORMAT " has %d queued incoming cells"
- " and %d queued outgoing cells",
- U64_PRINTF_ARG(chan->global_identifier),
- chan_cell_queue_len(&chan->incoming_queue),
- chan_cell_queue_len(&chan->outgoing_queue));
-
/* Describe circuits */
tor_log(severity, LD_GENERAL,
" * Channel " U64_FORMAT " has %d active circuits out of"
@@ -3779,12 +2684,6 @@ channel_dump_statistics, (channel_t *chan, int severity))
U64_PRINTF_ARG(chan->timestamp_client),
U64_PRINTF_ARG(now - chan->timestamp_client));
tor_log(severity, LD_GENERAL,
- " * Channel " U64_FORMAT " was last drained at "
- U64_FORMAT " (" U64_FORMAT " seconds ago)",
- U64_PRINTF_ARG(chan->global_identifier),
- U64_PRINTF_ARG(chan->timestamp_drained),
- U64_PRINTF_ARG(now - chan->timestamp_drained));
- tor_log(severity, LD_GENERAL,
" * Channel " U64_FORMAT " last received a cell "
"at " U64_FORMAT " (" U64_FORMAT " seconds ago)",
U64_PRINTF_ARG(chan->global_identifier),
@@ -4027,29 +2926,18 @@ channel_get_addr_if_possible(channel_t *chan, tor_addr_t *addr_out)
else return 0;
}
-/**
- * Check if there are outgoing queue writes on this channel
- *
- * Indicate if either we have queued cells, or if not, whether the underlying
- * lower-layer transport thinks it has an output queue.
+/*
+ * Return true iff the channel has any cells on the connection outbuf waiting
+ * to be sent onto the network.
*/
-
int
channel_has_queued_writes(channel_t *chan)
{
- int has_writes = 0;
-
tor_assert(chan);
tor_assert(chan->has_queued_writes);
- if (! TOR_SIMPLEQ_EMPTY(&chan->outgoing_queue)) {
- has_writes = 1;
- } else {
- /* Check with the lower layer */
- has_writes = chan->has_queued_writes(chan);
- }
-
- return has_writes;
+ /* Check with the lower layer */
+ return chan->has_queued_writes(chan);
}
/**
@@ -4274,23 +3162,10 @@ channel_mark_outgoing(channel_t *chan)
***********************/
/*
- * Get the latest estimate for the total queue size of all open channels
- */
-
-uint64_t
-channel_get_global_queue_estimate(void)
-{
- return estimated_total_queue_size;
-}
-
-/*
* Estimate the number of writeable cells
*
- * Ask the lower layer for an estimate of how many cells it can accept, and
- * then subtract the length of our outgoing_queue, if any, to produce an
- * estimate of the number of cells this channel can accept for writes.
+ * Ask the lower layer for an estimate of how many cells it can accept.
*/
-
int
channel_num_cells_writeable(channel_t *chan)
{
@@ -4302,8 +3177,6 @@ channel_num_cells_writeable(channel_t *chan)
if (chan->state == CHANNEL_STATE_OPEN) {
/* Query lower layer */
result = chan->num_cells_writeable(chan);
- /* Subtract cell queue length, if any */
- result -= chan_cell_queue_len(&chan->outgoing_queue);
if (result < 0) result = 0;
} else {
/* No cells are writeable in any other state */
@@ -4427,25 +3300,6 @@ channel_timestamp_client(channel_t *chan)
}
/**
- * Update the last drained timestamp
- *
- * This is called whenever we transmit a cell which leaves the outgoing cell
- * queue completely empty. It also updates the xmit time and the active time.
- */
-
-void
-channel_timestamp_drained(channel_t *chan)
-{
- time_t now = time(NULL);
-
- tor_assert(chan);
-
- chan->timestamp_active = now;
- chan->timestamp_drained = now;
- chan->timestamp_xmit = now;
-}
-
-/**
* Update the recv timestamp
*
* This is called whenever we get an incoming cell from the lower layer.
@@ -4504,54 +3358,6 @@ channel_when_created(channel_t *chan)
}
/**
- * Query created timestamp for a channel listener
- */
-
-time_t
-channel_listener_when_created(channel_listener_t *chan_l)
-{
- tor_assert(chan_l);
-
- return chan_l->timestamp_created;
-}
-
-/**
- * Query last active timestamp for a channel
- */
-
-time_t
-channel_when_last_active(channel_t *chan)
-{
- tor_assert(chan);
-
- return chan->timestamp_active;
-}
-
-/**
- * Query last active timestamp for a channel listener
- */
-
-time_t
-channel_listener_when_last_active(channel_listener_t *chan_l)
-{
- tor_assert(chan_l);
-
- return chan_l->timestamp_active;
-}
-
-/**
- * Query last accepted timestamp for a channel listener
- */
-
-time_t
-channel_listener_when_last_accepted(channel_listener_t *chan_l)
-{
- tor_assert(chan_l);
-
- return chan_l->timestamp_accepted;
-}
-
-/**
* Query client timestamp
*/
@@ -4564,30 +3370,6 @@ channel_when_last_client(channel_t *chan)
}
/**
- * Query drained timestamp
- */
-
-time_t
-channel_when_last_drained(channel_t *chan)
-{
- tor_assert(chan);
-
- return chan->timestamp_drained;
-}
-
-/**
- * Query recv timestamp
- */
-
-time_t
-channel_when_last_recv(channel_t *chan)
-{
- tor_assert(chan);
-
- return chan->timestamp_recv;
-}
-
-/**
* Query xmit timestamp
*/
@@ -4600,42 +3382,6 @@ channel_when_last_xmit(channel_t *chan)
}
/**
- * Query accepted counter
- */
-
-uint64_t
-channel_listener_count_accepted(channel_listener_t *chan_l)
-{
- tor_assert(chan_l);
-
- return chan_l->n_accepted;
-}
-
-/**
- * Query received cell counter
- */
-
-uint64_t
-channel_count_recved(channel_t *chan)
-{
- tor_assert(chan);
-
- return chan->n_cells_recved;
-}
-
-/**
- * Query transmitted cell counter
- */
-
-uint64_t
-channel_count_xmitted(channel_t *chan)
-{
- tor_assert(chan);
-
- return chan->n_cells_xmitted;
-}
-
-/**
* Check if a channel matches an extend_info_t
*
* This function calls the lower layer and asks if this channel matches a
@@ -4726,6 +3472,16 @@ channel_set_circid_type,(channel_t *chan,
}
}
+static int
+channel_sort_by_ed25519_identity(const void **a_, const void **b_)
+{
+ const channel_t *a = *a_,
+ *b = *b_;
+ return fast_memcmp(&a->ed25519_identity.pubkey,
+ &b->ed25519_identity.pubkey,
+ sizeof(a->ed25519_identity.pubkey));
+}
+
/** Helper for channel_update_bad_for_new_circs(): Perform the
* channel_update_bad_for_new_circs operation on all channels in <b>lst</b>,
* all of which MUST have the same RSA ID. (They MAY have different
@@ -4734,44 +3490,52 @@ static void
channel_rsa_id_group_set_badness(struct channel_list_s *lst, int force)
{
/*XXXX This function should really be about channels. 15056 */
- channel_t *chan;
+ channel_t *chan = TOR_LIST_FIRST(lst);
+
+ if (!chan)
+ return;
+
+ /* if there is only one channel, don't bother looping */
+ if (PREDICT_LIKELY(!TOR_LIST_NEXT(chan, next_with_same_id))) {
+ connection_or_single_set_badness_(
+ time(NULL), BASE_CHAN_TO_TLS(chan)->conn, force);
+ return;
+ }
+
+ smartlist_t *channels = smartlist_new();
- /* First, get a minimal list of the ed25519 identites */
- smartlist_t *ed_identities = smartlist_new();
TOR_LIST_FOREACH(chan, lst, next_with_same_id) {
- uint8_t *id_copy =
- tor_memdup(&chan->ed25519_identity.pubkey, DIGEST256_LEN);
- smartlist_add(ed_identities, id_copy);
+ if (BASE_CHAN_TO_TLS(chan)->conn) {
+ smartlist_add(channels, chan);
+ }
}
- smartlist_sort_digests256(ed_identities);
- smartlist_uniq_digests256(ed_identities);
- /* Now, for each Ed identity, build a smartlist and find the best entry on
- * it. */
+ smartlist_sort(channels, channel_sort_by_ed25519_identity);
+
+ const ed25519_public_key_t *common_ed25519_identity = NULL;
+ /* it would be more efficient to do a slice, but this case is rare */
smartlist_t *or_conns = smartlist_new();
- SMARTLIST_FOREACH_BEGIN(ed_identities, const uint8_t *, ed_id) {
- TOR_LIST_FOREACH(chan, lst, next_with_same_id) {
- channel_tls_t *chantls = BASE_CHAN_TO_TLS(chan);
- if (tor_memneq(ed_id, &chan->ed25519_identity.pubkey, DIGEST256_LEN))
- continue;
- or_connection_t *orconn = chantls->conn;
- if (orconn) {
- tor_assert(orconn->chan == chantls);
- smartlist_add(or_conns, orconn);
- }
+ SMARTLIST_FOREACH_BEGIN(channels, channel_t *, channel) {
+ if (!common_ed25519_identity)
+ common_ed25519_identity = &channel->ed25519_identity;
+
+ if (! ed25519_pubkey_eq(&channel->ed25519_identity,
+ common_ed25519_identity)) {
+ connection_or_group_set_badness_(or_conns, force);
+ smartlist_clear(or_conns);
+ common_ed25519_identity = &channel->ed25519_identity;
}
- connection_or_group_set_badness_(or_conns, force);
- smartlist_clear(or_conns);
- } SMARTLIST_FOREACH_END(ed_id);
+ smartlist_add(or_conns, BASE_CHAN_TO_TLS(channel)->conn);
+ } SMARTLIST_FOREACH_END(channel);
+
+ connection_or_group_set_badness_(or_conns, force);
/* XXXX 15056 we may want to do something special with connections that have
* no set Ed25519 identity! */
smartlist_free(or_conns);
-
- SMARTLIST_FOREACH(ed_identities, uint8_t *, ed_id, tor_free(ed_id));
- smartlist_free(ed_identities);
+ smartlist_free(channels);
}
/** Go through all the channels (or if <b>digest</b> is non-NULL, just
@@ -4801,83 +3565,3 @@ channel_update_bad_for_new_circs(const char *digest, int force)
}
}
-/**
- * Update the estimated number of bytes queued to transmit for this channel,
- * and notify the scheduler. The estimate includes both the channel queue and
- * the queue size reported by the lower layer, and an overhead estimate
- * optionally provided by the lower layer.
- */
-
-void
-channel_update_xmit_queue_size(channel_t *chan)
-{
- uint64_t queued, adj;
- double overhead;
-
- tor_assert(chan);
- tor_assert(chan->num_bytes_queued);
-
- /*
- * First, get the number of bytes we have queued without factoring in
- * lower-layer overhead.
- */
- queued = chan->num_bytes_queued(chan) + chan->bytes_in_queue;
- /* Next, adjust by the overhead factor, if any is available */
- if (chan->get_overhead_estimate) {
- overhead = chan->get_overhead_estimate(chan);
- if (overhead >= 1.0) {
- queued = (uint64_t)(queued * overhead);
- } else {
- /* Ignore silly overhead factors */
- log_notice(LD_CHANNEL, "Ignoring silly overhead factor %f", overhead);
- }
- }
-
- /* Now, compare to the previous estimate */
- if (queued > chan->bytes_queued_for_xmit) {
- adj = queued - chan->bytes_queued_for_xmit;
- log_debug(LD_CHANNEL,
- "Increasing queue size for channel " U64_FORMAT " by " U64_FORMAT
- " from " U64_FORMAT " to " U64_FORMAT,
- U64_PRINTF_ARG(chan->global_identifier),
- U64_PRINTF_ARG(adj),
- U64_PRINTF_ARG(chan->bytes_queued_for_xmit),
- U64_PRINTF_ARG(queued));
- /* Update the channel's estimate */
- chan->bytes_queued_for_xmit = queued;
-
- /* Update the global queue size estimate if appropriate */
- if (chan->state == CHANNEL_STATE_OPEN ||
- chan->state == CHANNEL_STATE_MAINT) {
- estimated_total_queue_size += adj;
- log_debug(LD_CHANNEL,
- "Increasing global queue size by " U64_FORMAT " for channel "
- U64_FORMAT ", new size is " U64_FORMAT,
- U64_PRINTF_ARG(adj), U64_PRINTF_ARG(chan->global_identifier),
- U64_PRINTF_ARG(estimated_total_queue_size));
- }
- } else if (queued < chan->bytes_queued_for_xmit) {
- adj = chan->bytes_queued_for_xmit - queued;
- log_debug(LD_CHANNEL,
- "Decreasing queue size for channel " U64_FORMAT " by " U64_FORMAT
- " from " U64_FORMAT " to " U64_FORMAT,
- U64_PRINTF_ARG(chan->global_identifier),
- U64_PRINTF_ARG(adj),
- U64_PRINTF_ARG(chan->bytes_queued_for_xmit),
- U64_PRINTF_ARG(queued));
- /* Update the channel's estimate */
- chan->bytes_queued_for_xmit = queued;
-
- /* Update the global queue size estimate if appropriate */
- if (chan->state == CHANNEL_STATE_OPEN ||
- chan->state == CHANNEL_STATE_MAINT) {
- estimated_total_queue_size -= adj;
- log_debug(LD_CHANNEL,
- "Decreasing global queue size by " U64_FORMAT " for channel "
- U64_FORMAT ", new size is " U64_FORMAT,
- U64_PRINTF_ARG(adj), U64_PRINTF_ARG(chan->global_identifier),
- U64_PRINTF_ARG(estimated_total_queue_size));
- }
- }
-}
-
diff --git a/src/or/channel.h b/src/or/channel.h
index 32336fe1d2..0f685011a3 100644
--- a/src/or/channel.h
+++ b/src/or/channel.h
@@ -19,10 +19,6 @@ typedef void (*channel_listener_fn_ptr)(channel_listener_t *, channel_t *);
typedef void (*channel_cell_handler_fn_ptr)(channel_t *, cell_t *);
typedef void (*channel_var_cell_handler_fn_ptr)(channel_t *, var_cell_t *);
-struct cell_queue_entry_s;
-TOR_SIMPLEQ_HEAD(chan_cell_queue, cell_queue_entry_s);
-typedef struct chan_cell_queue chan_cell_queue_t;
-
/**
* This enum is used by channelpadding to decide when to pad channels.
* Don't add values to it without updating the checks in
@@ -259,21 +255,12 @@ struct channel_s {
*/
ed25519_public_key_t ed25519_identity;
- /** Nickname of the OR on the other side, or NULL if none. */
- char *nickname;
-
/**
* Linked list of channels with the same RSA identity digest, for use with
* the digest->channel map
*/
TOR_LIST_ENTRY(channel_s) next_with_same_id;
- /** List of incoming cells to handle */
- chan_cell_queue_t incoming_queue;
-
- /** List of queued outgoing cells */
- chan_cell_queue_t outgoing_queue;
-
/** Circuit mux for circuits sending on this channel */
circuitmux_t *cmux;
@@ -320,7 +307,6 @@ struct channel_s {
/** Channel timestamps for cell channels */
time_t timestamp_client; /* Client used this, according to relay.c */
- time_t timestamp_drained; /* Output queue empty */
time_t timestamp_recv; /* Cell received from lower layer */
time_t timestamp_xmit; /* Cell sent to lower layer */
@@ -337,14 +323,6 @@ struct channel_s {
/** Channel counters for cell channels */
uint64_t n_cells_recved, n_bytes_recved;
uint64_t n_cells_xmitted, n_bytes_xmitted;
-
- /** Our current contribution to the scheduler's total xmit queue */
- uint64_t bytes_queued_for_xmit;
-
- /** Number of bytes in this channel's cell queue; does not include
- * lower-layer queueing.
- */
- uint64_t bytes_in_queue;
};
struct channel_listener_s {
@@ -412,18 +390,13 @@ channel_listener_state_to_string(channel_listener_state_t state);
/* Abstract channel operations */
void channel_mark_for_close(channel_t *chan);
-void channel_write_cell(channel_t *chan, cell_t *cell);
-void channel_write_packed_cell(channel_t *chan, packed_cell_t *cell);
-void channel_write_var_cell(channel_t *chan, var_cell_t *cell);
+int channel_write_packed_cell(channel_t *chan, packed_cell_t *cell);
void channel_listener_mark_for_close(channel_listener_t *chan_l);
/* Channel callback registrations */
/* Listener callback */
-channel_listener_fn_ptr
-channel_listener_get_listener_fn(channel_listener_t *chan);
-
void channel_listener_set_listener_fn(channel_listener_t *chan,
channel_listener_fn_ptr listener);
@@ -457,36 +430,9 @@ void channel_set_cmux_policy_everywhere(circuitmux_policy_t *pol);
#ifdef TOR_CHANNEL_INTERNAL_
#ifdef CHANNEL_PRIVATE_
-/* Cell queue structure (here rather than channel.c for test suite use) */
-
-typedef struct cell_queue_entry_s cell_queue_entry_t;
-struct cell_queue_entry_s {
- TOR_SIMPLEQ_ENTRY(cell_queue_entry_s) next;
- enum {
- CELL_QUEUE_FIXED,
- CELL_QUEUE_VAR,
- CELL_QUEUE_PACKED
- } type;
- union {
- struct {
- cell_t *cell;
- } fixed;
- struct {
- var_cell_t *var_cell;
- } var;
- struct {
- packed_cell_t *packed_cell;
- } packed;
- } u;
-};
-
-/* Cell queue functions for benefit of test suite */
-STATIC int chan_cell_queue_len(const chan_cell_queue_t *queue);
-STATIC void cell_queue_entry_free(cell_queue_entry_t *q, int handed_off);
+STATIC void channel_add_to_digest_map(channel_t *chan);
-void channel_write_cell_generic_(channel_t *chan, const char *cell_type,
- void *cell, cell_queue_entry_t *q);
#endif /* defined(CHANNEL_PRIVATE_) */
/* Channel operations for subclasses and internal use only */
@@ -511,13 +457,12 @@ void channel_close_from_lower_layer(channel_t *chan);
void channel_close_for_error(channel_t *chan);
void channel_closed(channel_t *chan);
-void channel_listener_close_from_lower_layer(channel_listener_t *chan_l);
-void channel_listener_close_for_error(channel_listener_t *chan_l);
-void channel_listener_closed(channel_listener_t *chan_l);
-
/* Free a channel */
-void channel_free(channel_t *chan);
-void channel_listener_free(channel_listener_t *chan_l);
+void channel_free_(channel_t *chan);
+#define channel_free(chan) FREE_AND_NULL(channel_t, channel_free_, (chan))
+void channel_listener_free_(channel_listener_t *chan_l);
+#define channel_listener_free(chan_l) \
+ FREE_AND_NULL(channel_listener_t, channel_listener_free_, (chan_l))
/* State/metadata setters */
@@ -532,9 +477,6 @@ void channel_mark_remote(channel_t *chan);
void channel_set_identity_digest(channel_t *chan,
const char *identity_digest,
const ed25519_public_key_t *ed_identity);
-void channel_set_remote_end(channel_t *chan,
- const char *identity_digest,
- const char *nickname);
void channel_listener_change_state(channel_listener_t *chan_l,
channel_listener_state_t to_state);
@@ -542,7 +484,6 @@ void channel_listener_change_state(channel_listener_t *chan_l,
/* Timestamp updates */
void channel_timestamp_created(channel_t *chan);
void channel_timestamp_active(channel_t *chan);
-void channel_timestamp_drained(channel_t *chan);
void channel_timestamp_recv(channel_t *chan);
void channel_timestamp_xmit(channel_t *chan);
@@ -556,12 +497,7 @@ void channel_listener_queue_incoming(channel_listener_t *listener,
channel_t *incoming);
/* Incoming cell handling */
-void channel_process_cells(channel_t *chan);
-void channel_queue_cell(channel_t *chan, cell_t *cell);
-void channel_queue_var_cell(channel_t *chan, var_cell_t *var_cell);
-
-/* Outgoing cell handling */
-void channel_flush_cells(channel_t *chan);
+void channel_process_cell(channel_t *chan, cell_t *cell);
/* Request from lower layer for more cells if available */
MOCK_DECL(ssize_t, channel_flush_some_cells,
@@ -576,10 +512,6 @@ void channel_notify_flushed(channel_t *chan);
/* Handle stuff we need to do on open like notifying circuits */
void channel_do_open_actions(channel_t *chan);
-#ifdef TOR_UNIT_TESTS
-extern uint64_t estimated_total_queue_size;
-#endif
-
#endif /* defined(TOR_CHANNEL_INTERNAL_) */
/* Helper functions to perform operations on channels */
@@ -680,7 +612,6 @@ MOCK_DECL(void,channel_set_circid_type,(channel_t *chan,
crypto_pk_t *identity_rcvd,
int consider_identity));
void channel_timestamp_client(channel_t *chan);
-void channel_update_xmit_queue_size(channel_t *chan);
const char * channel_listener_describe_transport(channel_listener_t *chan_l);
void channel_listener_dump_statistics(channel_listener_t *chan_l,
@@ -692,33 +623,22 @@ void channel_check_for_duplicates(void);
void channel_update_bad_for_new_circs(const char *digest, int force);
/* Flow control queries */
-uint64_t channel_get_global_queue_estimate(void);
int channel_num_cells_writeable(channel_t *chan);
/* Timestamp queries */
time_t channel_when_created(channel_t *chan);
-time_t channel_when_last_active(channel_t *chan);
time_t channel_when_last_client(channel_t *chan);
-time_t channel_when_last_drained(channel_t *chan);
-time_t channel_when_last_recv(channel_t *chan);
time_t channel_when_last_xmit(channel_t *chan);
-time_t channel_listener_when_created(channel_listener_t *chan_l);
-time_t channel_listener_when_last_active(channel_listener_t *chan_l);
-time_t channel_listener_when_last_accepted(channel_listener_t *chan_l);
-
/* Counter queries */
-uint64_t channel_count_recved(channel_t *chan);
-uint64_t channel_count_xmitted(channel_t *chan);
-
-uint64_t channel_listener_count_accepted(channel_listener_t *chan_l);
-
int packed_cell_is_destroy(channel_t *chan,
const packed_cell_t *packed_cell,
circid_t *circid_out);
/* Declare the handle helpers */
HANDLE_DECL(channel, channel_s,)
+#define channel_handle_free(h) \
+ FREE_AND_NULL(channel_handle_t, channel_handle_free_, (h))
#endif /* !defined(TOR_CHANNEL_H) */
diff --git a/src/or/channeltls.c b/src/or/channeltls.c
index 8277813186..023ccdefd3 100644
--- a/src/or/channeltls.c
+++ b/src/or/channeltls.c
@@ -832,6 +832,9 @@ channel_tls_write_cell_method(channel_t *chan, cell_t *cell)
*
* This implements the write_packed_cell method for channel_tls_t; given a
* channel_tls_t and a packed_cell_t, transmit the packed_cell_t.
+ *
+ * Return 0 on success or negative value on error. The caller must free the
+ * packed cell.
*/
static int
@@ -841,7 +844,6 @@ channel_tls_write_packed_cell_method(channel_t *chan,
tor_assert(chan);
channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan);
size_t cell_network_size = get_cell_network_size(chan->wide_circ_ids);
- int written = 0;
tor_assert(tlschan);
tor_assert(packed_cell);
@@ -849,18 +851,15 @@ channel_tls_write_packed_cell_method(channel_t *chan,
if (tlschan->conn) {
connection_buf_add(packed_cell->body, cell_network_size,
TO_CONN(tlschan->conn));
-
- /* This is where the cell is finished; used to be done from relay.c */
- packed_cell_free(packed_cell);
- ++written;
} else {
log_info(LD_CHANNEL,
"something called write_packed_cell on a tlschan "
"(%p with ID " U64_FORMAT " but no conn",
chan, U64_PRINTF_ARG(chan->global_identifier));
+ return -1;
}
- return written;
+ return 0;
}
/**
@@ -1149,7 +1148,7 @@ channel_tls_handle_cell(cell_t *cell, or_connection_t *conn)
* These are all transport independent and we pass them up through the
* channel_t mechanism. They are ultimately handled in command.c.
*/
- channel_queue_cell(TLS_CHAN_TO_BASE(chan), cell);
+ channel_process_cell(TLS_CHAN_TO_BASE(chan), cell);
break;
default:
log_fn(LOG_INFO, LD_PROTOCOL,
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c
index b56190fee2..a350f6c142 100644
--- a/src/or/circuitbuild.c
+++ b/src/or/circuitbuild.c
@@ -631,8 +631,7 @@ circuit_n_chan_done(channel_t *chan, int status, int close_origin_circuits)
tor_assert(chan);
- log_debug(LD_CIRC,"chan to %s/%s, status=%d",
- chan->nickname ? chan->nickname : "NULL",
+ log_debug(LD_CIRC,"chan to %s, status=%d",
channel_get_canonical_remote_descr(chan), status);
pending_circs = smartlist_new();
@@ -1269,7 +1268,7 @@ circuit_extend(cell_t *cell, circuit_t *circ)
const node_t *node = node_get_by_id((const char*)ec.node_id);
const ed25519_public_key_t *node_ed_id = NULL;
if (node &&
- node_supports_ed25519_link_authentication(node) &&
+ node_supports_ed25519_link_authentication(node, 1) &&
(node_ed_id = node_get_ed25519_id(node))) {
ed25519_pubkey_copy(&ec.ed_pubkey, node_ed_id);
}
@@ -2677,7 +2676,7 @@ extend_info_from_node(const node_t *node, int for_direct_connect)
/* Don't send the ed25519 pubkey unless the target node actually supports
* authenticating with it. */
- if (node_supports_ed25519_link_authentication(node)) {
+ if (node_supports_ed25519_link_authentication(node, 0)) {
log_info(LD_CIRC, "Including Ed25519 ID for %s", node_describe(node));
ed_pubkey = node_get_ed25519_id(node);
} else if (node_get_ed25519_id(node)) {
@@ -2686,12 +2685,16 @@ extend_info_from_node(const node_t *node, int for_direct_connect)
node_describe(node));
}
+ /* Retrieve the curve25519 pubkey. */
+ const curve25519_public_key_t *curve_pubkey =
+ node_get_curve25519_onion_key(node);
+
if (valid_addr && node->ri)
return extend_info_new(node->ri->nickname,
node->identity,
ed_pubkey,
node->ri->onion_pkey,
- node->ri->onion_curve25519_pkey,
+ curve_pubkey,
&ap.addr,
ap.port);
else if (valid_addr && node->rs && node->md)
@@ -2699,7 +2702,7 @@ extend_info_from_node(const node_t *node, int for_direct_connect)
node->identity,
ed_pubkey,
node->md->onion_pkey,
- node->md->onion_curve25519_pkey,
+ curve_pubkey,
&ap.addr,
ap.port);
else
@@ -2708,7 +2711,7 @@ extend_info_from_node(const node_t *node, int for_direct_connect)
/** Release storage held by an extend_info_t struct. */
void
-extend_info_free(extend_info_t *info)
+extend_info_free_(extend_info_t *info)
{
if (!info)
return;
diff --git a/src/or/circuitbuild.h b/src/or/circuitbuild.h
index 3c28781bc4..a85ef672f9 100644
--- a/src/or/circuitbuild.h
+++ b/src/or/circuitbuild.h
@@ -58,7 +58,9 @@ extend_info_t *extend_info_new(const char *nickname,
const tor_addr_t *addr, uint16_t port);
extend_info_t *extend_info_from_node(const node_t *r, int for_direct_connect);
extend_info_t *extend_info_dup(extend_info_t *info);
-void extend_info_free(extend_info_t *info);
+void extend_info_free_(extend_info_t *info);
+#define extend_info_free(info) \
+ FREE_AND_NULL(extend_info_t, extend_info_free_, (info))
int extend_info_addr_is_allowed(const tor_addr_t *addr);
int extend_info_supports_tap(const extend_info_t* ei);
int extend_info_supports_ntor(const extend_info_t* ei);
diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c
index fbf10fc0a4..82b9b84c1e 100644
--- a/src/or/circuitlist.c
+++ b/src/or/circuitlist.c
@@ -513,8 +513,7 @@ circuit_count_pending_on_channel(channel_t *chan)
circuit_get_all_pending_on_channel(sl, chan);
cnt = smartlist_len(sl);
smartlist_free(sl);
- log_debug(LD_CIRC,"or_conn to %s at %s, %d pending circs",
- chan->nickname ? chan->nickname : "NULL",
+ log_debug(LD_CIRC,"or_conn to %s, %d pending circs",
channel_get_canonical_remote_descr(chan),
cnt);
return cnt;
@@ -982,7 +981,7 @@ circuit_clear_testing_cell_stats(circuit_t *circ)
/** Deallocate space associated with circ.
*/
STATIC void
-circuit_free(circuit_t *circ)
+circuit_free_(circuit_t *circ)
{
circid_t n_circ_id = 0;
void *mem;
@@ -1145,7 +1144,7 @@ circuit_free_all(void)
while (or_circ->resolving_streams) {
edge_connection_t *next_conn;
next_conn = or_circ->resolving_streams->next_stream;
- connection_free(TO_CONN(or_circ->resolving_streams));
+ connection_free_(TO_CONN(or_circ->resolving_streams));
or_circ->resolving_streams = next_conn;
}
}
@@ -2253,12 +2252,12 @@ n_cells_in_circ_queues(const circuit_t *c)
}
/**
- * Return the age of the oldest cell queued on <b>c</b>, in milliseconds.
+ * Return the age of the oldest cell queued on <b>c</b>, in timestamp units.
* Return 0 if there are no cells queued on c. Requires that <b>now</b> be
- * the current time in milliseconds since the epoch, truncated.
+ * the current coarse timestamp.
*
* This function will return incorrect results if the oldest cell queued on
- * the circuit is older than 2**32 msec (about 49 days) old.
+ * the circuit is older than about 2**32 msec (about 49 days) old.
*/
STATIC uint32_t
circuit_max_queued_cell_age(const circuit_t *c, uint32_t now)
@@ -2267,12 +2266,12 @@ circuit_max_queued_cell_age(const circuit_t *c, uint32_t now)
packed_cell_t *cell;
if (NULL != (cell = TOR_SIMPLEQ_FIRST(&c->n_chan_cells.head)))
- age = now - cell->inserted_time;
+ age = now - cell->inserted_timestamp;
if (! CIRCUIT_IS_ORIGIN(c)) {
const or_circuit_t *orcirc = CONST_TO_OR_CIRCUIT(c);
if (NULL != (cell = TOR_SIMPLEQ_FIRST(&orcirc->p_chan_cells.head))) {
- uint32_t age2 = now - cell->inserted_time;
+ uint32_t age2 = now - cell->inserted_timestamp;
if (age2 > age)
return age2;
}
@@ -2280,31 +2279,30 @@ circuit_max_queued_cell_age(const circuit_t *c, uint32_t now)
return age;
}
-/** Return the age in milliseconds of the oldest buffer chunk on <b>conn</b>,
- * where age is taken in milliseconds before the time <b>now</b> (in truncated
- * absolute monotonic msec). If the connection has no data, treat
- * it as having age zero.
+/** Return the age of the oldest buffer chunk on <b>conn</b>, where age is
+ * taken in timestamp units before the time <b>now</b>. If the connection has
+ * no data, treat it as having age zero.
**/
static uint32_t
-conn_get_buffer_age(const connection_t *conn, uint32_t now)
+conn_get_buffer_age(const connection_t *conn, uint32_t now_ts)
{
uint32_t age = 0, age2;
if (conn->outbuf) {
- age2 = buf_get_oldest_chunk_timestamp(conn->outbuf, now);
+ age2 = buf_get_oldest_chunk_timestamp(conn->outbuf, now_ts);
if (age2 > age)
age = age2;
}
if (conn->inbuf) {
- age2 = buf_get_oldest_chunk_timestamp(conn->inbuf, now);
+ age2 = buf_get_oldest_chunk_timestamp(conn->inbuf, now_ts);
if (age2 > age)
age = age2;
}
return age;
}
-/** Return the age in milliseconds of the oldest buffer chunk on any stream in
- * the linked list <b>stream</b>, where age is taken in milliseconds before
- * the time <b>now</b> (in truncated milliseconds since the epoch). */
+/** Return the age in timestamp units of the oldest buffer chunk on any stream
+ * in the linked list <b>stream</b>, where age is taken in timestamp units
+ * before the timestamp <b>now</b>. */
static uint32_t
circuit_get_streams_max_data_age(const edge_connection_t *stream, uint32_t now)
{
@@ -2323,9 +2321,9 @@ circuit_get_streams_max_data_age(const edge_connection_t *stream, uint32_t now)
return age;
}
-/** Return the age in milliseconds of the oldest buffer chunk on any stream
- * attached to the circuit <b>c</b>, where age is taken in milliseconds before
- * the time <b>now</b> (in truncated milliseconds since the epoch). */
+/** Return the age in timestamp units of the oldest buffer chunk on any stream
+ * attached to the circuit <b>c</b>, where age is taken before the timestamp
+ * <b>now</b>. */
STATIC uint32_t
circuit_max_queued_data_age(const circuit_t *c, uint32_t now)
{
@@ -2339,8 +2337,8 @@ circuit_max_queued_data_age(const circuit_t *c, uint32_t now)
}
/** Return the age of the oldest cell or stream buffer chunk on the circuit
- * <b>c</b>, where age is taken in milliseconds before the time <b>now</b> (in
- * truncated milliseconds since the epoch). */
+ * <b>c</b>, where age is taken in timestamp units before the timestamp
+ * <b>now</b> */
STATIC uint32_t
circuit_max_queued_item_age(const circuit_t *c, uint32_t now)
{
@@ -2370,7 +2368,7 @@ circuits_compare_by_oldest_queued_item_(const void **a_, const void **b_)
return -1;
}
-static uint32_t now_ms_for_buf_cmp;
+static uint32_t now_ts_for_buf_cmp;
/** Helper to sort a list of circuit_t by age of oldest item, in descending
* order. */
@@ -2379,8 +2377,8 @@ conns_compare_by_buffer_age_(const void **a_, const void **b_)
{
const connection_t *a = *a_;
const connection_t *b = *b_;
- time_t age_a = conn_get_buffer_age(a, now_ms_for_buf_cmp);
- time_t age_b = conn_get_buffer_age(b, now_ms_for_buf_cmp);
+ time_t age_a = conn_get_buffer_age(a, now_ts_for_buf_cmp);
+ time_t age_b = conn_get_buffer_age(b, now_ts_for_buf_cmp);
if (age_a < age_b)
return 1;
@@ -2405,7 +2403,7 @@ circuits_handle_oom(size_t current_allocation)
size_t mem_recovered=0;
int n_circuits_killed=0;
int n_dirconns_killed=0;
- uint32_t now_ms;
+ uint32_t now_ts;
log_notice(LD_GENERAL, "We're low on memory. Killing circuits with "
"over-long queues. (This behavior is controlled by "
"MaxMemInQueues.)");
@@ -2418,11 +2416,11 @@ circuits_handle_oom(size_t current_allocation)
mem_to_recover = current_allocation - mem_target;
}
- now_ms = (uint32_t)monotime_coarse_absolute_msec();
+ now_ts = monotime_coarse_get_stamp();
circlist = circuit_get_global_list();
SMARTLIST_FOREACH_BEGIN(circlist, circuit_t *, circ) {
- circ->age_tmp = circuit_max_queued_item_age(circ, now_ms);
+ circ->age_tmp = circuit_max_queued_item_age(circ, now_ts);
} SMARTLIST_FOREACH_END(circ);
/* This is O(n log n); there are faster algorithms we could use instead.
@@ -2435,9 +2433,9 @@ circuits_handle_oom(size_t current_allocation)
} SMARTLIST_FOREACH_END(circ);
/* Now sort the connection array ... */
- now_ms_for_buf_cmp = now_ms;
+ now_ts_for_buf_cmp = now_ts;
smartlist_sort(connection_array, conns_compare_by_buffer_age_);
- now_ms_for_buf_cmp = 0;
+ now_ts_for_buf_cmp = 0;
/* Fix up the connection array to its new order. */
SMARTLIST_FOREACH_BEGIN(connection_array, connection_t *, conn) {
@@ -2456,7 +2454,7 @@ circuits_handle_oom(size_t current_allocation)
* data older than this circuit. */
while (conn_idx < smartlist_len(connection_array)) {
connection_t *conn = smartlist_get(connection_array, conn_idx);
- uint32_t conn_age = conn_get_buffer_age(conn, now_ms);
+ uint32_t conn_age = conn_get_buffer_age(conn, now_ts);
if (conn_age < circ->age_tmp) {
break;
}
diff --git a/src/or/circuitlist.h b/src/or/circuitlist.h
index 6371e913ae..8868646d59 100644
--- a/src/or/circuitlist.h
+++ b/src/or/circuitlist.h
@@ -86,7 +86,8 @@ MOCK_DECL(void, channel_note_destroy_not_pending,
smartlist_t *circuit_find_circuits_to_upgrade_from_guard_wait(void);
#ifdef CIRCUITLIST_PRIVATE
-STATIC void circuit_free(circuit_t *circ);
+STATIC void circuit_free_(circuit_t *circ);
+#define circuit_free(circ) FREE_AND_NULL(circuit_t, circuit_free_, (circ))
STATIC size_t n_cells_in_circ_queues(const circuit_t *c);
STATIC uint32_t circuit_max_queued_data_age(const circuit_t *c, uint32_t now);
STATIC uint32_t circuit_max_queued_cell_age(const circuit_t *c, uint32_t now);
diff --git a/src/or/circuitmux.c b/src/or/circuitmux.c
index f3b8aecb1b..d8408f45fc 100644
--- a/src/or/circuitmux.c
+++ b/src/or/circuitmux.c
@@ -546,7 +546,7 @@ circuitmux_mark_destroyed_circids_usable(circuitmux_t *cmux, channel_t *chan)
*/
void
-circuitmux_free(circuitmux_t *cmux)
+circuitmux_free_(circuitmux_t *cmux)
{
if (!cmux) return;
diff --git a/src/or/circuitmux.h b/src/or/circuitmux.h
index 3e7496ea1c..255822946d 100644
--- a/src/or/circuitmux.h
+++ b/src/or/circuitmux.h
@@ -104,7 +104,9 @@ void circuitmux_assert_okay(circuitmux_t *cmux);
circuitmux_t * circuitmux_alloc(void);
void circuitmux_detach_all_circuits(circuitmux_t *cmux,
smartlist_t *detached_out);
-void circuitmux_free(circuitmux_t *cmux);
+void circuitmux_free_(circuitmux_t *cmux);
+#define circuitmux_free(cmux) \
+ FREE_AND_NULL(circuitmux_t, circuitmux_free_, (cmux))
/* Policy control */
void circuitmux_clear_policy(circuitmux_t *cmux);
diff --git a/src/or/circuitstats.c b/src/or/circuitstats.c
index afb37771f1..f1df19eb25 100644
--- a/src/or/circuitstats.c
+++ b/src/or/circuitstats.c
@@ -434,9 +434,14 @@ circuit_build_times_new_consensus_params(circuit_build_times_t *cbt,
if (num > 0) {
if (num != cbt->liveness.num_recent_circs) {
int8_t *recent_circs;
- log_notice(LD_CIRC, "The Tor Directory Consensus has changed how many "
- "circuits we must track to detect network failures from %d "
- "to %d.", cbt->liveness.num_recent_circs, num);
+ if (cbt->liveness.num_recent_circs > 0) {
+ log_notice(LD_CIRC, "The Tor Directory Consensus has changed how "
+ "many circuits we must track to detect network failures "
+ "from %d to %d.", cbt->liveness.num_recent_circs, num);
+ } else {
+ log_notice(LD_CIRC, "Upon receiving a consensus directory, "
+ "re-enabling circuit-based network failure detection.");
+ }
tor_assert(cbt->liveness.timeouts_after_firsthop ||
cbt->liveness.num_recent_circs == 0);
diff --git a/src/or/circuituse.c b/src/or/circuituse.c
index d4657921ea..825535739f 100644
--- a/src/or/circuituse.c
+++ b/src/or/circuituse.c
@@ -542,8 +542,7 @@ circuit_expire_building(void)
cutoff = begindir_cutoff;
else if (victim->purpose == CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT)
cutoff = close_cutoff;
- else if (victim->purpose == CIRCUIT_PURPOSE_C_INTRODUCING ||
- victim->purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT)
+ else if (victim->purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT)
cutoff = c_intro_cutoff;
else if (victim->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO)
cutoff = s_intro_cutoff;
@@ -662,12 +661,13 @@ circuit_expire_building(void)
TO_ORIGIN_CIRCUIT(victim)->path_state = PATH_STATE_USE_FAILED;
break;
case CIRCUIT_PURPOSE_C_INTRODUCING:
- /* We keep old introducing circuits around for
- * a while in parallel, and they can end up "opened".
- * We decide below if we're going to mark them timed
- * out and eventually close them.
- */
- break;
+ /* That purpose means that the intro point circuit has been opened
+ * succesfully but the INTRODUCE1 cell hasn't been sent yet because
+ * the client is waiting for the rendezvous point circuit to open.
+ * Keep this circuit open while waiting for the rendezvous circuit.
+ * We let the circuit idle timeout take care of cleaning this
+ * circuit if it never used. */
+ continue;
case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
case CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED:
case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT:
@@ -752,8 +752,6 @@ circuit_expire_building(void)
NULL)
break;
/* fallthrough! */
- case CIRCUIT_PURPOSE_C_INTRODUCING:
- /* connection_ap_handshake_attach_circuit() will relaunch for us */
case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT:
case CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED:
/* If we have reached this line, we want to spare the circ for now. */
@@ -998,7 +996,7 @@ circuit_remove_handled_ports(smartlist_t *needed_ports)
tor_assert(*port);
if (circuit_stream_is_being_handled(NULL, *port,
MIN_CIRCUITS_HANDLING_STREAM)) {
-// log_debug(LD_CIRC,"Port %d is already being handled; removing.", port);
+ log_debug(LD_CIRC,"Port %d is already being handled; removing.", *port);
smartlist_del(needed_ports, i--);
tor_free(port);
} else {
@@ -1035,6 +1033,10 @@ circuit_stream_is_being_handled(entry_connection_t *conn,
continue;
if (origin_circ->unusable_for_new_conns)
continue;
+ if (origin_circ->isolation_values_set &&
+ (conn == NULL ||
+ !connection_edge_compatible_with_circuit(conn, origin_circ)))
+ continue;
exitnode = build_state_get_exit_node(build_state);
if (exitnode && (!need_uptime || build_state->need_uptime)) {
diff --git a/src/or/config.c b/src/or/config.c
index 252d50944b..bcfac1dae2 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -253,6 +253,8 @@ static config_var_t option_vars_[] = {
V(BridgeRecordUsageByCountry, BOOL, "1"),
V(BridgeRelay, BOOL, "0"),
V(BridgeDistribution, STRING, NULL),
+ VAR("CacheDirectory", FILENAME, CacheDirectory_option, NULL),
+ V(CacheDirectoryGroupReadable, BOOL, "0"),
V(CellStatistics, BOOL, "0"),
V(PaddingStatistics, BOOL, "1"),
V(LearnCircuitBuildTimeout, BOOL, "1"),
@@ -286,7 +288,7 @@ static config_var_t option_vars_[] = {
V(CookieAuthFileGroupReadable, BOOL, "0"),
V(CookieAuthFile, STRING, NULL),
V(CountPrivateBandwidth, BOOL, "0"),
- V(DataDirectory, FILENAME, NULL),
+ VAR("DataDirectory", FILENAME, DataDirectory_option, NULL),
V(DataDirectoryGroupReadable, BOOL, "0"),
V(DisableOOSCheck, BOOL, "1"),
V(DisableNetwork, BOOL, "0"),
@@ -392,6 +394,8 @@ static config_var_t option_vars_[] = {
V(Socks5Proxy, STRING, NULL),
V(Socks5ProxyUsername, STRING, NULL),
V(Socks5ProxyPassword, STRING, NULL),
+ VAR("KeyDirectory", FILENAME, KeyDirectory_option, NULL),
+ V(KeyDirectoryGroupReadable, BOOL, "0"),
V(KeepalivePeriod, INTERVAL, "5 minutes"),
V(KeepBindCapabilities, AUTOBOOL, "auto"),
VAR("Log", LINELIST, Logs, NULL),
@@ -694,11 +698,6 @@ static const config_var_t testing_tor_network_defaults[] = {
#undef OBSOLETE
static const config_deprecation_t option_deprecation_notes_[] = {
- /* Deprecated since 0.2.9.2-alpha... */
- { "AllowDotExit", "Unrestricted use of the .exit notation can be used for "
- "a wide variety of application-level attacks." },
- /* End of options deprecated since 0.2.9.2-alpha. */
-
/* Deprecated since 0.3.2.0-alpha. */
{ "HTTPProxy", "It only applies to direct unencrypted HTTP connections "
"to your directory server, which your Tor probably wasn't using." },
@@ -738,7 +737,7 @@ static int parse_ports(or_options_t *options, int validate_only,
static int check_server_ports(const smartlist_t *ports,
const or_options_t *options,
int *num_low_ports_out);
-static int validate_data_directory(or_options_t *options);
+static int validate_data_directories(or_options_t *options);
static int write_configuration_file(const char *fname,
const or_options_t *options);
static int options_init_logs(const or_options_t *old_options,
@@ -783,7 +782,7 @@ static or_options_t *global_default_options = NULL;
/** Name of most recently read torrc file. */
static char *torrc_fname = NULL;
/** Name of the most recently read torrc-defaults file.*/
-static char *torrc_defaults_fname;
+static char *torrc_defaults_fname = NULL;
/** Configuration options set by command line. */
static config_line_t *global_cmdline_options = NULL;
/** Non-configuration options set by the command line */
@@ -927,7 +926,7 @@ get_short_version(void)
/** Release additional memory allocated in options
*/
STATIC void
-or_options_free(or_options_t *options)
+or_options_free_(or_options_t *options)
{
if (!options)
return;
@@ -946,6 +945,9 @@ or_options_free(or_options_t *options)
SMARTLIST_FOREACH(options->FilesOpenedByIncludes, char *, f, tor_free(f));
smartlist_free(options->FilesOpenedByIncludes);
}
+ tor_free(options->DataDirectory);
+ tor_free(options->CacheDirectory);
+ tor_free(options->KeyDirectory);
tor_free(options->BridgePassword_AuthDigest_);
tor_free(options->command_arg);
tor_free(options->master_key_fname);
@@ -982,6 +984,8 @@ config_free_all(void)
tor_free(the_short_tor_version);
tor_free(the_tor_version);
+
+ have_parsed_cmdline = 0;
}
/** Make <b>address</b> -- a piece of information related to our operation as
@@ -1092,6 +1096,7 @@ static const char *default_authorities[] = {
"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",
NULL
};
@@ -1254,6 +1259,69 @@ consider_adding_dir_servers(const or_options_t *options,
return 0;
}
+/**
+ * Make sure that <b>directory</b> exists, with appropriate ownership and
+ * permissions (as modified by <b>group_readable</b>). If <b>create</b>,
+ * create the directory if it is missing. Return 0 on success.
+ * On failure, return -1 and set *<b>msg_out</b>.
+ */
+static int
+check_and_create_data_directory(int create,
+ const char *directory,
+ int group_readable,
+ const char *owner,
+ char **msg_out)
+{
+ cpd_check_t cpd_opts = create ? CPD_CREATE : CPD_CHECK;
+ if (group_readable)
+ cpd_opts |= CPD_GROUP_READ;
+ if (check_private_dir(directory,
+ cpd_opts,
+ owner) < 0) {
+ tor_asprintf(msg_out,
+ "Couldn't %s private data directory \"%s\"",
+ create ? "create" : "access",
+ directory);
+ return -1;
+ }
+
+#ifndef _WIN32
+ if (group_readable) {
+ /* Only new dirs created get new opts, also enforce group read. */
+ if (chmod(directory, 0750)) {
+ log_warn(LD_FS,"Unable to make %s group-readable: %s",
+ directory, strerror(errno));
+ }
+ }
+#endif /* !defined(_WIN32) */
+
+ return 0;
+}
+
+/**
+ * Ensure that our keys directory exists, with appropriate permissions.
+ * Return 0 on success, -1 on failure.
+ */
+int
+create_keys_directory(const or_options_t *options)
+{
+ /* Make sure DataDirectory exists, and is private. */
+ cpd_check_t cpd_opts = CPD_CREATE;
+ if (options->DataDirectoryGroupReadable)
+ cpd_opts |= CPD_GROUP_READ;
+ if (check_private_dir(options->DataDirectory, cpd_opts, options->User)) {
+ log_err(LD_OR, "Can't create/check datadirectory %s",
+ options->DataDirectory);
+ return -1;
+ }
+
+ /* Check the key directory. */
+ if (check_private_dir(options->KeyDirectory, CPD_CREATE, options->User)) {
+ return -1;
+ }
+ return 0;
+}
+
/* Helps determine flags to pass to switch_id. */
static int have_low_ports = -1;
@@ -1408,29 +1476,30 @@ options_act_reversible(const or_options_t *old_options, char **msg)
}
/* Ensure data directory is private; create if possible. */
- cpd_check_t cpd_opts = running_tor ? CPD_CREATE : CPD_CHECK;
- if (options->DataDirectoryGroupReadable)
- cpd_opts |= CPD_GROUP_READ;
- if (check_private_dir(options->DataDirectory,
- cpd_opts,
- options->User)<0) {
- tor_asprintf(msg,
- "Couldn't access/create private data directory \"%s\"",
- options->DataDirectory);
-
+ /* It's okay to do this in "options_act_reversible()" even though it isn't
+ * actually reversible, since you can't change the DataDirectory while
+ * Tor is running. */
+ if (check_and_create_data_directory(running_tor /* create */,
+ options->DataDirectory,
+ options->DataDirectoryGroupReadable,
+ options->User,
+ msg) < 0) {
goto done;
- /* No need to roll back, since you can't change the value. */
}
-
-#ifndef _WIN32
- if (options->DataDirectoryGroupReadable) {
- /* Only new dirs created get new opts, also enforce group read. */
- if (chmod(options->DataDirectory, 0750)) {
- log_warn(LD_FS,"Unable to make %s group-readable: %s",
- options->DataDirectory, strerror(errno));
- }
+ if (check_and_create_data_directory(running_tor /* create */,
+ options->KeyDirectory,
+ options->KeyDirectoryGroupReadable,
+ options->User,
+ msg) < 0) {
+ goto done;
+ }
+ if (check_and_create_data_directory(running_tor /* create */,
+ options->CacheDirectory,
+ options->CacheDirectoryGroupReadable,
+ options->User,
+ msg) < 0) {
+ goto done;
}
-#endif /* !defined(_WIN32) */
/* Bail out at this point if we're not going to be a client or server:
* we don't run Tor itself. */
@@ -1792,7 +1861,7 @@ options_act(const or_options_t *old_options)
"given FD.");
return -1;
}
-#endif
+#endif /* defined(_WIN32) */
}
/* Load state */
@@ -3192,7 +3261,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
if (parse_outbound_addresses(options, 1, msg) < 0)
return -1;
- if (validate_data_directory(options)<0)
+ if (validate_data_directories(options)<0)
REJECT("Invalid DataDirectory");
if (options->Nickname == NULL) {
@@ -4590,6 +4659,22 @@ options_transition_allowed(const or_options_t *old,
return -1;
}
+ if (!opt_streq(old->KeyDirectory, new_val->KeyDirectory)) {
+ tor_asprintf(msg,
+ "While Tor is running, changing KeyDirectory "
+ "(\"%s\"->\"%s\") is not allowed.",
+ old->KeyDirectory, new_val->KeyDirectory);
+ return -1;
+ }
+
+ if (!opt_streq(old->CacheDirectory, new_val->CacheDirectory)) {
+ tor_asprintf(msg,
+ "While Tor is running, changing CacheDirectory "
+ "(\"%s\"->\"%s\") is not allowed.",
+ old->CacheDirectory, new_val->CacheDirectory);
+ return -1;
+ }
+
if (!opt_streq(old->User, new_val->User)) {
*msg = tor_strdup("While Tor is running, changing User is not allowed.");
return -1;
@@ -5742,7 +5827,7 @@ validate_transport_socks_arguments(const smartlist_t *args)
/** Deallocate a bridge_line_t structure. */
/* private */ void
-bridge_line_free(bridge_line_t *bridge_line)
+bridge_line_free_(bridge_line_t *bridge_line)
{
if (!bridge_line)
return;
@@ -6502,14 +6587,13 @@ port_cfg_new(size_t namelen)
cfg->entry_cfg.ipv6_traffic = 1;
cfg->entry_cfg.dns_request = 1;
cfg->entry_cfg.onion_traffic = 1;
- cfg->entry_cfg.cache_ipv4_answers = 1;
cfg->entry_cfg.prefer_ipv6_virtaddr = 1;
return cfg;
}
/** Free all storage held in <b>port</b> */
STATIC void
-port_cfg_free(port_cfg_t *port)
+port_cfg_free_(port_cfg_t *port)
{
tor_free(port);
}
@@ -6818,7 +6902,7 @@ parse_port_config(smartlist_t *out,
bind_ipv4_only = 0, bind_ipv6_only = 0,
ipv4_traffic = 1, ipv6_traffic = 1, prefer_ipv6 = 0, dns_request = 1,
onion_traffic = 1,
- cache_ipv4 = 1, use_cached_ipv4 = 0,
+ cache_ipv4 = 0, use_cached_ipv4 = 0,
cache_ipv6 = 0, use_cached_ipv6 = 0,
prefer_ipv6_automap = 1, world_writable = 0, group_writable = 0,
relax_dirmode_check = 0,
@@ -7687,60 +7771,81 @@ port_exists_by_type_addr32h_port(int listener_type, uint32_t addr_ipv4h,
check_wildcard);
}
-/** Adjust the value of options->DataDirectory, or fill it in if it's
- * absent. Return 0 on success, -1 on failure. */
-static int
-normalize_data_directory(or_options_t *options)
+/** Allocate and return a good value for the DataDirectory based on
+ * <b>val</b>, which may be NULL. Return NULL on failure. */
+static char *
+get_data_directory(const char *val)
{
#ifdef _WIN32
- char *p;
- if (options->DataDirectory)
- return 0; /* all set */
- p = tor_malloc(MAX_PATH);
- strlcpy(p,get_windows_conf_root(),MAX_PATH);
- options->DataDirectory = p;
- return 0;
+ if (val) {
+ return tor_strdup(val);
+ } else {
+ return tor_strdup(get_windows_conf_root());
+ }
#else /* !(defined(_WIN32)) */
- const char *d = options->DataDirectory;
+ const char *d = val;
if (!d)
d = "~/.tor";
- if (strncmp(d,"~/",2) == 0) {
- char *fn = expand_filename(d);
- if (!fn) {
- log_warn(LD_CONFIG,"Failed to expand filename \"%s\".", d);
- return -1;
- }
- if (!options->DataDirectory && !strcmp(fn,"/.tor")) {
- /* If our homedir is /, we probably don't want to use it. */
- /* Default to LOCALSTATEDIR/tor which is probably closer to what we
- * want. */
- log_warn(LD_CONFIG,
- "Default DataDirectory is \"~/.tor\". This expands to "
- "\"%s\", which is probably not what you want. Using "
- "\"%s"PATH_SEPARATOR"tor\" instead", fn, LOCALSTATEDIR);
- tor_free(fn);
- fn = tor_strdup(LOCALSTATEDIR PATH_SEPARATOR "tor");
- }
- tor_free(options->DataDirectory);
- options->DataDirectory = fn;
- }
- return 0;
+ if (!strcmpstart(d, "~/")) {
+ char *fn = expand_filename(d);
+ if (!fn) {
+ log_warn(LD_CONFIG,"Failed to expand filename \"%s\".", d);
+ return NULL;
+ }
+ if (!val && !strcmp(fn,"/.tor")) {
+ /* If our homedir is /, we probably don't want to use it. */
+ /* Default to LOCALSTATEDIR/tor which is probably closer to what we
+ * want. */
+ log_warn(LD_CONFIG,
+ "Default DataDirectory is \"~/.tor\". This expands to "
+ "\"%s\", which is probably not what you want. Using "
+ "\"%s"PATH_SEPARATOR"tor\" instead", fn, LOCALSTATEDIR);
+ tor_free(fn);
+ fn = tor_strdup(LOCALSTATEDIR PATH_SEPARATOR "tor");
+ }
+ return fn;
+ }
+ return tor_strdup(d);
#endif /* defined(_WIN32) */
}
-/** Check and normalize the value of options->DataDirectory; return 0 if it
- * is sane, -1 otherwise. */
+/** Check and normalize the values of options->{Key,Data,Cache}Directory;
+ * return 0 if it is sane, -1 otherwise. */
static int
-validate_data_directory(or_options_t *options)
+validate_data_directories(or_options_t *options)
{
- if (normalize_data_directory(options) < 0)
+ tor_free(options->DataDirectory);
+ options->DataDirectory = get_data_directory(options->DataDirectory_option);
+ if (!options->DataDirectory)
return -1;
- tor_assert(options->DataDirectory);
if (strlen(options->DataDirectory) > (512-128)) {
log_warn(LD_CONFIG, "DataDirectory is too long.");
return -1;
}
+
+ tor_free(options->KeyDirectory);
+ if (options->KeyDirectory_option) {
+ options->KeyDirectory = get_data_directory(options->KeyDirectory_option);
+ if (!options->KeyDirectory)
+ return -1;
+ } else {
+ /* Default to the data directory's keys subdir */
+ tor_asprintf(&options->KeyDirectory, "%s"PATH_SEPARATOR"keys",
+ options->DataDirectory);
+ }
+
+ tor_free(options->CacheDirectory);
+ if (options->CacheDirectory_option) {
+ options->CacheDirectory = get_data_directory(
+ options->CacheDirectory_option);
+ if (!options->CacheDirectory)
+ return -1;
+ } else {
+ /* Default to the data directory. */
+ options->CacheDirectory = tor_strdup(options->DataDirectory);
+ }
+
return 0;
}
@@ -7881,53 +7986,56 @@ init_libevent(const or_options_t *options)
suppress_libevent_log_msg(NULL);
}
-/** Return a newly allocated string holding a filename relative to the data
- * directory. If <b>sub1</b> is present, it is the first path component after
+/** Return a newly allocated string holding a filename relative to the
+ * directory in <b>options</b> specified by <b>roottype</b>.
+ * If <b>sub1</b> is present, it is the first path component after
* the data directory. If <b>sub2</b> is also present, it is the second path
* component after the data directory. If <b>suffix</b> is present, it
* is appended to the filename.
*
- * Examples:
- * get_datadir_fname2_suffix("a", NULL, NULL) -> $DATADIR/a
- * get_datadir_fname2_suffix("a", NULL, ".tmp") -> $DATADIR/a.tmp
- * get_datadir_fname2_suffix("a", "b", ".tmp") -> $DATADIR/a/b/.tmp
- * get_datadir_fname2_suffix("a", "b", NULL) -> $DATADIR/a/b
- *
- * Note: Consider using the get_datadir_fname* macros in or.h.
+ * Note: Consider using macros in config.h that wrap this function;
+ * you should probably never need to call it as-is.
*/
MOCK_IMPL(char *,
-options_get_datadir_fname2_suffix,(const or_options_t *options,
- const char *sub1, const char *sub2,
- const char *suffix))
+options_get_dir_fname2_suffix,(const or_options_t *options,
+ directory_root_t roottype,
+ const char *sub1, const char *sub2,
+ const char *suffix))
{
- char *fname = NULL;
- size_t len;
tor_assert(options);
- tor_assert(options->DataDirectory);
- tor_assert(sub1 || !sub2); /* If sub2 is present, sub1 must be present. */
- len = strlen(options->DataDirectory);
- if (sub1) {
- len += strlen(sub1)+1;
- if (sub2)
- len += strlen(sub2)+1;
- }
- if (suffix)
- len += strlen(suffix);
- len++;
- fname = tor_malloc(len);
- if (sub1) {
- if (sub2) {
- tor_snprintf(fname, len, "%s"PATH_SEPARATOR"%s"PATH_SEPARATOR"%s",
- options->DataDirectory, sub1, sub2);
- } else {
- tor_snprintf(fname, len, "%s"PATH_SEPARATOR"%s",
- options->DataDirectory, sub1);
- }
+
+ const char *rootdir = NULL;
+ switch (roottype) {
+ case DIRROOT_DATADIR:
+ rootdir = options->DataDirectory;
+ break;
+ case DIRROOT_CACHEDIR:
+ rootdir = options->CacheDirectory;
+ break;
+ case DIRROOT_KEYDIR:
+ rootdir = options->KeyDirectory;
+ break;
+ default:
+ tor_assert_unreached();
+ break;
+ }
+ tor_assert(rootdir);
+
+ if (!suffix)
+ suffix = "";
+
+ char *fname = NULL;
+
+ if (sub1 == NULL) {
+ tor_asprintf(&fname, "%s%s", rootdir, suffix);
+ tor_assert(!sub2); /* If sub2 is present, sub1 must be present. */
+ } else if (sub2 == NULL) {
+ tor_asprintf(&fname, "%s"PATH_SEPARATOR"%s%s", rootdir, sub1, suffix);
} else {
- strlcpy(fname, options->DataDirectory, len);
+ tor_asprintf(&fname, "%s"PATH_SEPARATOR"%s"PATH_SEPARATOR"%s%s",
+ rootdir, sub1, sub2, suffix);
}
- if (suffix)
- strlcat(fname, suffix, len);
+
return fname;
}
@@ -7968,28 +8076,6 @@ write_to_data_subdir(const char* subdir, const char* fname,
return return_val;
}
-/** Given a file name check to see whether the file exists but has not been
- * modified for a very long time. If so, remove it. */
-void
-remove_file_if_very_old(const char *fname, time_t now)
-{
-#define VERY_OLD_FILE_AGE (28*24*60*60)
- struct stat st;
-
- log_debug(LD_FS, "stat()ing %s", fname);
- if (stat(sandbox_intern_string(fname), &st)==0 &&
- st.st_mtime < now-VERY_OLD_FILE_AGE) {
- char buf[ISO_TIME_LEN+1];
- format_local_iso_time(buf, st.st_mtime);
- log_notice(LD_GENERAL, "Obsolete file %s hasn't been modified since %s. "
- "Removing it.", fname, buf);
- if (unlink(fname) != 0) {
- log_warn(LD_FS, "Failed to unlink %s: %s",
- fname, strerror(errno));
- }
- }
-}
-
/** Return a smartlist of ports that must be forwarded by
* tor-fw-helper. The smartlist contains the ports in a string format
* that is understandable by tor-fw-helper. */
diff --git a/src/or/config.h b/src/or/config.h
index efdd8c59b0..7c7ef1825a 100644
--- a/src/or/config.h
+++ b/src/or/config.h
@@ -58,31 +58,77 @@ config_line_t *option_get_assignment(const or_options_t *options,
const char *key);
int options_save_current(void);
const char *get_torrc_fname(int defaults_fname);
+typedef enum {
+ DIRROOT_DATADIR,
+ DIRROOT_CACHEDIR,
+ DIRROOT_KEYDIR
+} directory_root_t;
+
MOCK_DECL(char *,
- options_get_datadir_fname2_suffix,
+ options_get_dir_fname2_suffix,
(const or_options_t *options,
+ directory_root_t roottype,
const char *sub1, const char *sub2,
const char *suffix));
+
+/* These macros wrap options_get_dir_fname2_suffix to provide a more
+ * convenient API for finding filenames that Tor uses inside its storage
+ * They are named according to a pattern:
+ * (options_)?get_(cache|key|data)dir_fname(2)?(_suffix)?
+ *
+ * Macros that begin with options_ take an options argument; the others
+ * work with respect to the global options.
+ *
+ * Each macro works relative to the data directory, the key directory,
+ * or the cache directory, as determined by which one is mentioned.
+ *
+ * Macro variants with "2" in their name take two path components; others
+ * take one.
+ *
+ * Macro variants with "_suffix" at the end take an additional suffix
+ * that gets appended to the end of the file
+ */
+#define options_get_datadir_fname2_suffix(options, sub1, sub2, suffix) \
+ options_get_dir_fname2_suffix((options), DIRROOT_DATADIR, \
+ (sub1), (sub2), (suffix))
+#define options_get_cachedir_fname2_suffix(options, sub1, sub2, suffix) \
+ options_get_dir_fname2_suffix((options), DIRROOT_CACHEDIR, \
+ (sub1), (sub2), (suffix))
+#define options_get_keydir_fname2_suffix(options, sub1, sub2, suffix) \
+ options_get_dir_fname2_suffix((options), DIRROOT_KEYDIR, \
+ (sub1), (sub2), (suffix))
+
+#define options_get_datadir_fname(opts,sub1) \
+ options_get_datadir_fname2_suffix((opts),(sub1), NULL, NULL)
+#define options_get_datadir_fname2(opts,sub1,sub2) \
+ options_get_datadir_fname2_suffix((opts),(sub1), (sub2), NULL)
+
#define get_datadir_fname2_suffix(sub1, sub2, suffix) \
options_get_datadir_fname2_suffix(get_options(), (sub1), (sub2), (suffix))
-/** Return a newly allocated string containing datadir/sub1. See
- * get_datadir_fname2_suffix. */
-#define get_datadir_fname(sub1) get_datadir_fname2_suffix((sub1), NULL, NULL)
-/** Return a newly allocated string containing datadir/sub1/sub2. See
- * get_datadir_fname2_suffix. */
+#define get_datadir_fname(sub1) \
+ get_datadir_fname2_suffix((sub1), NULL, NULL)
#define get_datadir_fname2(sub1,sub2) \
get_datadir_fname2_suffix((sub1), (sub2), NULL)
-/** Return a newly allocated string containing datadir/sub1/sub2 relative to
- * opts. See get_datadir_fname2_suffix. */
-#define options_get_datadir_fname2(opts,sub1,sub2) \
- options_get_datadir_fname2_suffix((opts),(sub1), (sub2), NULL)
-/** Return a newly allocated string containing datadir/sub1suffix. See
- * get_datadir_fname2_suffix. */
#define get_datadir_fname_suffix(sub1, suffix) \
get_datadir_fname2_suffix((sub1), NULL, (suffix))
+/** DOCDOC */
+#define options_get_keydir_fname(options, sub1) \
+ options_get_keydir_fname2_suffix((options), (sub1), NULL, NULL)
+#define get_keydir_fname_suffix(sub1, suffix) \
+ options_get_keydir_fname2_suffix(get_options(), (sub1), NULL, suffix)
+#define get_keydir_fname(sub1) \
+ options_get_keydir_fname2_suffix(get_options(), (sub1), NULL, NULL)
+
+#define get_cachedir_fname(sub1) \
+ options_get_cachedir_fname2_suffix(get_options(), (sub1), NULL, NULL)
+#define get_cachedir_fname_suffix(sub1, suffix) \
+ options_get_cachedir_fname2_suffix(get_options(), (sub1), NULL, (suffix))
+
int using_default_dir_authorities(const or_options_t *options);
+int create_keys_directory(const or_options_t *options);
+
int check_or_create_data_subdir(const char *subdir);
int write_to_data_subdir(const char* subdir, const char* fname,
const char* str, const char* descr);
@@ -152,7 +198,9 @@ typedef struct bridge_line_t {
transport proxy. */
} bridge_line_t;
-void bridge_line_free(bridge_line_t *bridge_line);
+void bridge_line_free_(bridge_line_t *bridge_line);
+#define bridge_line_free(line) \
+ FREE_AND_NULL(bridge_line_t, bridge_line_free_, (line))
bridge_line_t *parse_bridge_line(const char *line);
smartlist_t *get_options_from_transport_options_line(const char *line,
const char *transport);
@@ -175,8 +223,12 @@ extern struct config_format_t options_format;
#endif
STATIC port_cfg_t *port_cfg_new(size_t namelen);
-STATIC void port_cfg_free(port_cfg_t *port);
-STATIC void or_options_free(or_options_t *options);
+#define port_cfg_free(port) \
+ FREE_AND_NULL(port_cfg_t, port_cfg_free_, (port))
+STATIC void port_cfg_free_(port_cfg_t *port);
+#define or_options_free(opt) \
+ FREE_AND_NULL(or_options_t, or_options_free_, (opt))
+STATIC void or_options_free_(or_options_t *options);
STATIC int options_validate_single_onion(or_options_t *options,
char **msg);
STATIC int options_validate(or_options_t *old_options,
diff --git a/src/or/confparse.c b/src/or/confparse.c
index abae7e33dc..64ed9ee6bb 100644
--- a/src/or/confparse.c
+++ b/src/or/confparse.c
@@ -863,7 +863,7 @@ config_reset(const config_format_t *fmt, void *options,
/** Release storage held by <b>options</b>. */
void
-config_free(const config_format_t *fmt, void *options)
+config_free_(const config_format_t *fmt, void *options)
{
int i;
diff --git a/src/or/confparse.h b/src/or/confparse.h
index 6f0b3b325c..fc4a7b2d06 100644
--- a/src/or/confparse.h
+++ b/src/or/confparse.h
@@ -68,7 +68,7 @@ typedef union {
config_line_t **LINELIST_V;
routerset_t **ROUTERSET;
} confparse_dummy_values_t;
-#endif
+#endif /* defined(TOR_UNIT_TESTS) */
/** An abbreviation for a configuration option allowed on the command line. */
typedef struct config_abbrev_t {
@@ -132,13 +132,13 @@ typedef struct config_var_t {
{ NULL, CONFIG_TYPE_OBSOLETE, 0, NULL, { .INT=NULL } }
#define DUMMY_TYPECHECK_INSTANCE(tp) \
static tp tp ## _dummy
-#else
+#else /* !(defined(TOR_UNIT_TESTS)) */
#define CONF_TEST_MEMBERS(tp, conftype, member)
#define END_OF_CONFIG_VARS { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
/* Repeatedly declarable incomplete struct to absorb redundant semicolons */
#define DUMMY_TYPECHECK_INSTANCE(tp) \
struct tor_semicolon_eater
-#endif
+#endif /* defined(TOR_UNIT_TESTS) */
/** Type of a callback to validate whether a given configuration is
* well-formed and consistent. See options_trial_assign() for documentation
@@ -177,7 +177,12 @@ typedef struct config_format_t {
#define CAL_WARN_DEPRECATIONS (1u<<2)
void *config_new(const config_format_t *fmt);
-void config_free(const config_format_t *fmt, void *options);
+void config_free_(const config_format_t *fmt, void *options);
+#define config_free(fmt, options) do { \
+ config_free_((fmt), (options)); \
+ (options) = NULL; \
+ } while (0)
+
config_line_t *config_get_assigned_option(const config_format_t *fmt,
const void *options, const char *key,
int escape_val);
diff --git a/src/or/connection.c b/src/or/connection.c
index e6aae71627..3c37c59b40 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2001 Matej Pfajfar.
+ /* 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. */
@@ -499,7 +499,7 @@ conn_listener_type_supports_af_unix(int type)
* if <b>conn</b> is an OR or OP connection.
*/
STATIC void
-connection_free_(connection_t *conn)
+connection_free_minimal(connection_t *conn)
{
void *mem;
size_t memlen;
@@ -675,7 +675,7 @@ connection_free_(connection_t *conn)
/** Make sure <b>conn</b> isn't in any of the global conn lists; then free it.
*/
MOCK_IMPL(void,
-connection_free,(connection_t *conn))
+connection_free_,(connection_t *conn))
{
if (!conn)
return;
@@ -704,7 +704,7 @@ connection_free,(connection_t *conn))
}
#endif /* 1 */
connection_unregister_events(conn);
- connection_free_(conn);
+ connection_free_minimal(conn);
}
/**
@@ -768,6 +768,10 @@ connection_close_immediate(connection_t *conn)
connection_unregister_events(conn);
+ /* Prevent the event from getting unblocked. */
+ conn->read_blocked_on_bw =
+ conn->write_blocked_on_bw = 0;
+
if (SOCKET_OK(conn->s))
tor_close_socket(conn->s);
conn->s = TOR_INVALID_SOCKET;
@@ -1748,7 +1752,11 @@ connection_connect_sockaddr,(connection_t *conn,
if (get_options()->DisableNetwork) {
/* We should never even try to connect anyplace if DisableNetwork is set.
- * Warn if we do, and refuse to make the connection. */
+ * Warn if we do, and refuse to make the connection.
+ *
+ * We only check DisableNetwork here, not we_are_hibernating(), since
+ * we'll still try to fulfill client requests sometimes in the latter case
+ * (if it is soft hibernation) */
static ratelim_t disablenet_violated = RATELIM_INIT(30*60);
*socket_error = SOCK_ERRNO(ENETUNREACH);
log_fn_ratelim(&disablenet_violated, LOG_WARN, LD_BUG,
@@ -5231,8 +5239,8 @@ proxy_type_to_string(int proxy_type)
return NULL; /*Unreached*/
}
-/** Call connection_free_() on every connection in our array, and release all
- * storage held by connection.c.
+/** Call connection_free_minimal() on every connection in our array, and
+ * release all storage held by connection.c.
*
* Don't do the checks in connection_free(), because they will
* fail.
@@ -5256,7 +5264,8 @@ connection_free_all(void)
/* Clear out our list of broken connections */
clear_broken_connection_map(0);
- SMARTLIST_FOREACH(conns, connection_t *, conn, connection_free_(conn));
+ SMARTLIST_FOREACH(conns, connection_t *, conn,
+ connection_free_minimal(conn));
if (outgoing_addrs) {
SMARTLIST_FOREACH(outgoing_addrs, tor_addr_t *, addr, tor_free(addr));
diff --git a/src/or/connection.h b/src/or/connection.h
index 450229ce8f..6bc5a7cfd0 100644
--- a/src/or/connection.h
+++ b/src/or/connection.h
@@ -29,7 +29,9 @@ connection_t *connection_new(int type, int socket_family);
int connection_init_accepted_conn(connection_t *conn,
const listener_connection_t *listener);
void connection_link_connections(connection_t *conn_a, connection_t *conn_b);
-MOCK_DECL(void,connection_free,(connection_t *conn));
+MOCK_DECL(void,connection_free_,(connection_t *conn));
+#define connection_free(conn) \
+ FREE_AND_NULL(connection_t, connection_free_, (conn))
void connection_free_all(void);
void connection_about_to_close_connection(connection_t *conn);
void connection_close_immediate(connection_t *conn);
@@ -245,7 +247,6 @@ char *alloc_http_authenticator(const char *authenticator);
void assert_connection_ok(connection_t *conn, time_t now);
int connection_or_nonopen_was_started_here(or_connection_t *conn);
void connection_dump_buffer_mem_stats(int severity);
-void remove_file_if_very_old(const char *fname, time_t now);
void clock_skew_warning(const connection_t *conn, long apparent_skew,
int trusted, log_domain_mask_t domain,
@@ -268,7 +269,7 @@ connection_is_moribund(connection_t *conn)
void connection_check_oos(int n_socks, int failed);
#ifdef CONNECTION_PRIVATE
-STATIC void connection_free_(connection_t *conn);
+STATIC void connection_free_minimal(connection_t *conn);
/* Used only by connection.c and test*.c */
uint32_t bucket_millis_empty(int tokens_before, uint32_t last_empty_time,
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c
index 41f0fe6a1d..0c4352ea13 100644
--- a/src/or/connection_edge.c
+++ b/src/or/connection_edge.c
@@ -339,6 +339,10 @@ relay_send_end_cell_from_edge(streamid_t stream_id, circuit_t *circ,
payload[0] = (char) reason;
+ /* Note: we have to use relay_send_command_from_edge here, not
+ * connection_edge_end or connection_edge_send_command, since those require
+ * that we have a stream connected to a circuit, and we don't connect to a
+ * circuit until we have a pending/successful resolve. */
return relay_send_command_from_edge(stream_id, circ, RELAY_COMMAND_END,
payload, 1, cpath_layer);
}
@@ -3327,7 +3331,7 @@ handle_hs_exit_conn(circuit_t *circ, edge_connection_t *conn)
relay_send_end_cell_from_edge(conn->stream_id, circ,
END_STREAM_REASON_DONE,
origin_circ->cpath->prev);
- connection_free(TO_CONN(conn));
+ connection_free_(TO_CONN(conn));
/* Drop the circuit here since it might be someone deliberately
* scanning the hidden service ports. Note that this mitigates port
@@ -3405,11 +3409,6 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
if (rh.length > RELAY_PAYLOAD_SIZE)
return -END_CIRC_REASON_TORPROTOCOL;
- /* Note: we have to use relay_send_command_from_edge here, not
- * connection_edge_end or connection_edge_send_command, since those require
- * that we have a stream connected to a circuit, and we don't connect to a
- * circuit until we have a pending/successful resolve. */
-
if (!server_mode(options) &&
circ->purpose != CIRCUIT_PURPOSE_S_REND_JOINED) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
@@ -3524,7 +3523,7 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
if (we_are_hibernating()) {
relay_send_end_cell_from_edge(rh.stream_id, circ,
END_STREAM_REASON_HIBERNATING, NULL);
- connection_free(TO_CONN(n_stream));
+ connection_free_(TO_CONN(n_stream));
return 0;
}
@@ -3602,7 +3601,7 @@ connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ)
return 0;
case 1: /* The result was cached; a resolved cell was sent. */
if (!dummy_conn->base_.marked_for_close)
- connection_free(TO_CONN(dummy_conn));
+ connection_free_(TO_CONN(dummy_conn));
return 0;
case 0: /* resolve added to pending list */
assert_circuit_ok(TO_CIRCUIT(circ));
@@ -3775,8 +3774,8 @@ connection_exit_connect_dir(edge_connection_t *exitconn)
if (connection_add(TO_CONN(exitconn))<0) {
connection_edge_end(exitconn, END_STREAM_REASON_RESOURCELIMIT);
- connection_free(TO_CONN(exitconn));
- connection_free(TO_CONN(dirconn));
+ connection_free_(TO_CONN(exitconn));
+ connection_free_(TO_CONN(dirconn));
return 0;
}
@@ -3788,7 +3787,7 @@ connection_exit_connect_dir(edge_connection_t *exitconn)
connection_edge_end(exitconn, END_STREAM_REASON_RESOURCELIMIT);
connection_close_immediate(TO_CONN(exitconn));
connection_mark_for_close(TO_CONN(exitconn));
- connection_free(TO_CONN(dirconn));
+ connection_free_(TO_CONN(dirconn));
return 0;
}
diff --git a/src/or/connection_or.c b/src/or/connection_or.c
index 9e34063609..a877761491 100644
--- a/src/or/connection_or.c
+++ b/src/or/connection_or.c
@@ -505,7 +505,7 @@ var_cell_copy(const var_cell_t *src)
/** Release all space held by <b>cell</b>. */
void
-var_cell_free(var_cell_t *cell)
+var_cell_free_(var_cell_t *cell)
{
tor_free(cell);
}
@@ -592,9 +592,6 @@ connection_or_flushed_some(or_connection_t *conn)
{
size_t datalen;
- /* The channel will want to update its estimated queue size */
- channel_update_xmit_queue_size(TLS_CHAN_TO_BASE(conn->chan));
-
/* If we're under the low water mark, add cells until we're just over the
* high water mark. */
datalen = connection_get_outbuf_len(TO_CONN(conn));
@@ -886,7 +883,7 @@ connection_or_check_canonicity(or_connection_t *conn, int started_here)
const node_t *r = node_get_by_id(id_digest);
if (r &&
- node_supports_ed25519_link_authentication(r) &&
+ node_supports_ed25519_link_authentication(r, 1) &&
! node_ed25519_id_matches(r, ed_id)) {
/* If this node is capable of proving an ed25519 ID,
* we can't call this a canonical connection unless both IDs match. */
@@ -965,6 +962,36 @@ connection_or_mark_bad_for_new_circs(or_connection_t *or_conn)
* too old for new circuits? */
#define TIME_BEFORE_OR_CONN_IS_TOO_OLD (60*60*24*7)
+/** Expire an or_connection if it is too old. Helper for
+ * connection_or_group_set_badness_ and fast path for
+ * channel_rsa_id_group_set_badness.
+ *
+ * Returns 1 if the connection was already expired, else 0.
+ */
+int
+connection_or_single_set_badness_(time_t now,
+ or_connection_t *or_conn,
+ int force)
+{
+ /* XXXX this function should also be about channels? */
+ if (or_conn->base_.marked_for_close ||
+ connection_or_is_bad_for_new_circs(or_conn))
+ return 1;
+
+ if (force ||
+ or_conn->base_.timestamp_created + TIME_BEFORE_OR_CONN_IS_TOO_OLD
+ < now) {
+ log_info(LD_OR,
+ "Marking OR conn to %s:%d as too old for new circuits "
+ "(fd "TOR_SOCKET_T_FORMAT", %d secs old).",
+ or_conn->base_.address, or_conn->base_.port, or_conn->base_.s,
+ (int)(now - or_conn->base_.timestamp_created));
+ connection_or_mark_bad_for_new_circs(or_conn);
+ }
+
+ return 0;
+}
+
/** Given a list of all the or_connections with a given
* identity, set elements of that list as is_bad_for_new_circs as
* appropriate. Helper for connection_or_set_bad_connections().
@@ -995,19 +1022,8 @@ connection_or_group_set_badness_(smartlist_t *group, int force)
/* Pass 1: expire everything that's old, and see what the status of
* everything else is. */
SMARTLIST_FOREACH_BEGIN(group, or_connection_t *, or_conn) {
- if (or_conn->base_.marked_for_close ||
- connection_or_is_bad_for_new_circs(or_conn))
+ if (connection_or_single_set_badness_(now, or_conn, force))
continue;
- if (force ||
- or_conn->base_.timestamp_created + TIME_BEFORE_OR_CONN_IS_TOO_OLD
- < now) {
- log_info(LD_OR,
- "Marking OR conn to %s:%d as too old for new circuits "
- "(fd "TOR_SOCKET_T_FORMAT", %d secs old).",
- or_conn->base_.address, or_conn->base_.port, or_conn->base_.s,
- (int)(now - or_conn->base_.timestamp_created));
- connection_or_mark_bad_for_new_circs(or_conn);
- }
if (connection_or_is_bad_for_new_circs(or_conn)) {
++n_old;
@@ -1247,7 +1263,7 @@ connection_or_connect, (const tor_addr_t *_addr, uint16_t port,
fmt_addrport(&TO_CONN(conn)->addr, TO_CONN(conn)->port));
}
- connection_free(TO_CONN(conn));
+ connection_free_(TO_CONN(conn));
return NULL;
}
@@ -1260,7 +1276,7 @@ connection_or_connect, (const tor_addr_t *_addr, uint16_t port,
connection_or_connect_failed(conn,
errno_to_orconn_end_reason(socket_error),
tor_socket_strerror(socket_error));
- connection_free(TO_CONN(conn));
+ connection_free_(TO_CONN(conn));
return NULL;
case 0:
connection_watch_events(TO_CONN(conn), READ_EVENT | WRITE_EVENT);
@@ -1854,7 +1870,7 @@ connection_init_or_handshake_state(or_connection_t *conn, int started_here)
/** Free all storage held by <b>state</b>. */
void
-or_handshake_state_free(or_handshake_state_t *state)
+or_handshake_state_free_(or_handshake_state_t *state)
{
if (!state)
return;
diff --git a/src/or/connection_or.h b/src/or/connection_or.h
index ee66b7c528..7c1dced631 100644
--- a/src/or/connection_or.h
+++ b/src/or/connection_or.h
@@ -68,7 +68,9 @@ int connection_or_client_learned_peer_id(or_connection_t *conn,
const ed25519_public_key_t *ed_peer_id);
time_t connection_or_client_used(or_connection_t *conn);
MOCK_DECL(int, connection_or_get_num_circuits, (or_connection_t *conn));
-void or_handshake_state_free(or_handshake_state_t *state);
+void or_handshake_state_free_(or_handshake_state_t *state);
+#define or_handshake_state_free(state) \
+ FREE_AND_NULL(or_handshake_state_t, or_handshake_state_free_, (state))
void or_handshake_state_record_cell(or_connection_t *conn,
or_handshake_state_t *state,
const cell_t *cell,
@@ -105,13 +107,17 @@ int var_cell_pack_header(const var_cell_t *cell, char *hdr_out,
int wide_circ_ids);
var_cell_t *var_cell_new(uint16_t payload_len);
var_cell_t *var_cell_copy(const var_cell_t *src);
-void var_cell_free(var_cell_t *cell);
+void var_cell_free_(var_cell_t *cell);
+#define var_cell_free(cell) FREE_AND_NULL(var_cell_t, var_cell_free_, (cell))
/* DOCDOC */
#define MIN_LINK_PROTO_FOR_WIDE_CIRC_IDS 4
#define MIN_LINK_PROTO_FOR_CHANNEL_PADDING 5
#define MAX_LINK_PROTO MIN_LINK_PROTO_FOR_CHANNEL_PADDING
+int connection_or_single_set_badness_(time_t now,
+ or_connection_t *or_conn,
+ int force);
void connection_or_group_set_badness_(smartlist_t *group, int force);
#ifdef TOR_UNIT_TESTS
diff --git a/src/or/conscache.c b/src/or/conscache.c
index 0f3e453eaf..e25ac5f40b 100644
--- a/src/or/conscache.c
+++ b/src/or/conscache.c
@@ -79,7 +79,7 @@ consensus_cache_open(const char *subdir, int max_entries)
{
int storagedir_max_entries;
consensus_cache_t *cache = tor_malloc_zero(sizeof(consensus_cache_t));
- char *directory = get_datadir_fname(subdir);
+ char *directory = get_cachedir_fname(subdir);
cache->max_entries = max_entries;
#ifdef MUST_UNMAP_TO_UNLINK
@@ -170,7 +170,7 @@ consensus_cache_clear(consensus_cache_t *cache)
* Drop all storage held by <b>cache</b>.
*/
void
-consensus_cache_free(consensus_cache_t *cache)
+consensus_cache_free_(consensus_cache_t *cache)
{
if (! cache)
return;
@@ -539,9 +539,20 @@ consensus_cache_rescan(consensus_cache_t *cache)
map = storage_dir_map_labeled(cache->dir, fname,
&labels, &body, &bodylen);
if (! map) {
- /* Can't load this; continue */
- log_warn(LD_FS, "Unable to map file %s from consensus cache: %s",
- escaped(fname), strerror(errno));
+ /* The ERANGE error might come from tor_mmap_file() -- it means the file
+ * was empty. EINVAL might come from ..map_labeled() -- it means the
+ * file was misformatted. In both cases, we should just delete it.
+ */
+ if (errno == ERANGE || errno == EINVAL) {
+ log_warn(LD_FS, "Found %s file %s in consensus cache; removing it.",
+ errno == ERANGE ? "empty" : "misformatted",
+ escaped(fname));
+ storage_dir_remove_file(cache->dir, fname);
+ } else {
+ /* Can't load this; continue */
+ log_warn(LD_FS, "Unable to map file %s from consensus cache: %s",
+ escaped(fname), strerror(errno));
+ }
continue;
}
consensus_cache_entry_t *ent =
diff --git a/src/or/conscache.h b/src/or/conscache.h
index 3c89dedf43..08a5c5a37b 100644
--- a/src/or/conscache.h
+++ b/src/or/conscache.h
@@ -10,9 +10,14 @@ typedef struct consensus_cache_entry_t consensus_cache_entry_t;
typedef struct consensus_cache_t consensus_cache_t;
HANDLE_DECL(consensus_cache_entry, consensus_cache_entry_t, )
+#define consensus_cache_entry_handle_free(h) \
+ FREE_AND_NULL(consensus_cache_entry_handle_t, \
+ consensus_cache_entry_handle_free_, (h))
consensus_cache_t *consensus_cache_open(const char *subdir, int max_entries);
-void consensus_cache_free(consensus_cache_t *cache);
+void consensus_cache_free_(consensus_cache_t *cache);
+#define consensus_cache_free(cache) \
+ FREE_AND_NULL(consensus_cache_t, consensus_cache_free_, (cache))
struct sandbox_cfg_elem;
int consensus_cache_may_overallocate(consensus_cache_t *cache);
int consensus_cache_register_with_sandbox(consensus_cache_t *cache,
diff --git a/src/or/consdiffmgr.c b/src/or/consdiffmgr.c
index 1d63d59577..38d901a3ae 100644
--- a/src/or/consdiffmgr.c
+++ b/src/or/consdiffmgr.c
@@ -207,9 +207,12 @@ HT_PROTOTYPE(cdm_diff_ht, cdm_diff_t, node, cdm_diff_hash, cdm_diff_eq)
HT_GENERATE2(cdm_diff_ht, cdm_diff_t, node, cdm_diff_hash, cdm_diff_eq,
0.6, tor_reallocarray, tor_free_)
+#define cdm_diff_free(diff) \
+ FREE_AND_NULL(cdm_diff_t, cdm_diff_free_, (diff))
+
/** Release all storage held in <b>diff</b>. */
static void
-cdm_diff_free(cdm_diff_t *diff)
+cdm_diff_free_(cdm_diff_t *diff)
{
if (!diff)
return;
@@ -283,6 +286,10 @@ cdm_diff_ht_set_status(consensus_flavor_t flav,
int status,
consensus_cache_entry_handle_t *handle)
{
+ if (handle == NULL) {
+ tor_assert_nonfatal(status != CDM_DIFF_PRESENT);
+ }
+
struct cdm_diff_t search, *ent;
memset(&search, 0, sizeof(cdm_diff_t));
search.flavor = flav;
@@ -1502,11 +1509,15 @@ consensus_diff_worker_threadfn(void *state_, void *work_)
return WQ_RPL_REPLY;
}
+#define consensus_diff_worker_job_free(job) \
+ FREE_AND_NULL(consensus_diff_worker_job_t, \
+ consensus_diff_worker_job_free_, (job))
+
/**
* Helper: release all storage held in <b>job</b>.
*/
static void
-consensus_diff_worker_job_free(consensus_diff_worker_job_t *job)
+consensus_diff_worker_job_free_(consensus_diff_worker_job_t *job)
{
if (!job)
return;
@@ -1589,8 +1600,13 @@ consensus_diff_worker_replyfn(void *work_)
for (u = 0; u < ARRAY_LENGTH(handles); ++u) {
compress_method_t method = compress_diffs_with[u];
if (cache) {
- cdm_diff_ht_set_status(flav, from_sha3, to_sha3, method, status,
- handles[u]);
+ consensus_cache_entry_handle_t *h = handles[u];
+ int this_status = status;
+ if (h == NULL) {
+ this_status = CDM_DIFF_ERROR;
+ }
+ tor_assert_nonfatal(h != NULL || this_status == CDM_DIFF_ERROR);
+ cdm_diff_ht_set_status(flav, from_sha3, to_sha3, method, this_status, h);
} else {
consensus_cache_entry_handle_free(handles[u]);
}
@@ -1649,11 +1665,15 @@ typedef struct consensus_compress_worker_job_t {
compressed_result_t out[ARRAY_LENGTH(compress_consensus_with)];
} consensus_compress_worker_job_t;
+#define consensus_compress_worker_job_free(job) \
+ FREE_AND_NULL(consensus_compress_worker_job_t, \
+ consensus_compress_worker_job_free_, (job))
+
/**
* Free all resources held in <b>job</b>
*/
static void
-consensus_compress_worker_job_free(consensus_compress_worker_job_t *job)
+consensus_compress_worker_job_free_(consensus_compress_worker_job_t *job)
{
if (!job)
return;
diff --git a/src/or/control.c b/src/or/control.c
index d417d42f73..cce5c7953b 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -58,7 +58,9 @@
#include "entrynodes.h"
#include "geoip.h"
#include "hibernate.h"
+#include "hs_cache.h"
#include "hs_common.h"
+#include "hs_control.h"
#include "main.h"
#include "microdesc.h"
#include "networkstatus.h"
@@ -783,9 +785,12 @@ queue_control_event_string,(uint16_t event, char *msg))
}
}
+#define queued_event_free(ev) \
+ FREE_AND_NULL(queued_event_t, queued_event_free_, (ev))
+
/** Release all storage held by <b>ev</b>. */
static void
-queued_event_free(queued_event_t *ev)
+queued_event_free_(queued_event_t *ev)
{
if (ev == NULL)
return;
@@ -2014,36 +2019,89 @@ getinfo_helper_dir(control_connection_t *control_conn,
SMARTLIST_FOREACH(sl, char *, c, tor_free(c));
smartlist_free(sl);
} else if (!strcmpstart(question, "hs/client/desc/id/")) {
- rend_cache_entry_t *e = NULL;
+ hostname_type_t addr_type;
question += strlen("hs/client/desc/id/");
- if (strlen(question) != REND_SERVICE_ID_LEN_BASE32) {
+ if (rend_valid_v2_service_id(question)) {
+ addr_type = ONION_V2_HOSTNAME;
+ } else if (hs_address_is_valid(question)) {
+ addr_type = ONION_V3_HOSTNAME;
+ } else {
*errmsg = "Invalid address";
return -1;
}
- if (!rend_cache_lookup_entry(question, -1, &e)) {
- /* Descriptor found in cache */
- *answer = tor_strdup(e->desc);
+ if (addr_type == ONION_V2_HOSTNAME) {
+ rend_cache_entry_t *e = NULL;
+ if (!rend_cache_lookup_entry(question, -1, &e)) {
+ /* Descriptor found in cache */
+ *answer = tor_strdup(e->desc);
+ } else {
+ *errmsg = "Not found in cache";
+ return -1;
+ }
} else {
- *errmsg = "Not found in cache";
- return -1;
+ ed25519_public_key_t service_pk;
+ const char *desc;
+
+ /* The check before this if/else makes sure of this. */
+ tor_assert(addr_type == ONION_V3_HOSTNAME);
+
+ if (hs_parse_address(question, &service_pk, NULL, NULL) < 0) {
+ *errmsg = "Invalid v3 address";
+ return -1;
+ }
+
+ desc = hs_cache_lookup_encoded_as_client(&service_pk);
+ if (desc) {
+ *answer = tor_strdup(desc);
+ } else {
+ *errmsg = "Not found in cache";
+ return -1;
+ }
}
} else if (!strcmpstart(question, "hs/service/desc/id/")) {
- rend_cache_entry_t *e = NULL;
+ hostname_type_t addr_type;
question += strlen("hs/service/desc/id/");
- if (strlen(question) != REND_SERVICE_ID_LEN_BASE32) {
+ if (rend_valid_v2_service_id(question)) {
+ addr_type = ONION_V2_HOSTNAME;
+ } else if (hs_address_is_valid(question)) {
+ addr_type = ONION_V3_HOSTNAME;
+ } else {
*errmsg = "Invalid address";
return -1;
}
+ rend_cache_entry_t *e = NULL;
- if (!rend_cache_lookup_v2_desc_as_service(question, &e)) {
- /* Descriptor found in cache */
- *answer = tor_strdup(e->desc);
+ if (addr_type == ONION_V2_HOSTNAME) {
+ if (!rend_cache_lookup_v2_desc_as_service(question, &e)) {
+ /* Descriptor found in cache */
+ *answer = tor_strdup(e->desc);
+ } else {
+ *errmsg = "Not found in cache";
+ return -1;
+ }
} else {
- *errmsg = "Not found in cache";
- return -1;
+ ed25519_public_key_t service_pk;
+ char *desc;
+
+ /* The check before this if/else makes sure of this. */
+ tor_assert(addr_type == ONION_V3_HOSTNAME);
+
+ if (hs_parse_address(question, &service_pk, NULL, NULL) < 0) {
+ *errmsg = "Invalid v3 address";
+ return -1;
+ }
+
+ desc = hs_service_lookup_current_desc(&service_pk);
+ if (desc) {
+ /* Newly allocated string, we have ownership. */
+ *answer = desc;
+ } else {
+ *errmsg = "Not found in cache";
+ return -1;
+ }
}
} else if (!strcmpstart(question, "md/id/")) {
const node_t *node = node_get_by_hex_id(question+strlen("md/id/"), 0);
@@ -2115,7 +2173,7 @@ getinfo_helper_dir(control_connection_t *control_conn,
*answer = tor_strdup(consensus->dir);
}
if (!*answer) { /* try loading it from disk */
- char *filename = get_datadir_fname("cached-consensus");
+ char *filename = get_cachedir_fname("cached-consensus");
*answer = read_file_to_str(filename, RFTS_IGNORE_MISSING, NULL);
tor_free(filename);
if (!*answer) { /* generate an error */
@@ -2624,9 +2682,16 @@ circuit_describe_status_for_controller(origin_circuit_t *circ)
}
}
- if (circ->rend_data != NULL) {
- smartlist_add_asprintf(descparts, "REND_QUERY=%s",
- rend_data_get_address(circ->rend_data));
+ if (circ->rend_data != NULL || circ->hs_ident != NULL) {
+ char addr[HS_SERVICE_ADDR_LEN_BASE32 + 1];
+ const char *onion_address;
+ if (circ->rend_data) {
+ onion_address = rend_data_get_address(circ->rend_data);
+ } else {
+ hs_build_address(&circ->hs_ident->identity_pk, HS_VERSION_THREE, addr);
+ onion_address = addr;
+ }
+ smartlist_add_asprintf(descparts, "REND_QUERY=%s", onion_address);
}
{
@@ -4277,9 +4342,11 @@ handle_control_hspost(control_connection_t *conn,
const char *body)
{
static const char *opt_server = "SERVER=";
+ static const char *opt_hsaddress = "HSADDRESS=";
smartlist_t *hs_dirs = NULL;
const char *encoded_desc = body;
size_t encoded_desc_len = len;
+ const char *onion_address = NULL;
char *cp = memchr(body, '\n', len);
if (cp == NULL) {
@@ -4309,15 +4376,16 @@ handle_control_hspost(control_connection_t *conn,
server);
goto done;
}
- if (!node->rs->is_hs_dir) {
- connection_printf_to_buf(conn, "552 Server \"%s\" is not a HSDir"
- "\r\n", server);
- goto done;
- }
/* Valid server, add it to our local list. */
if (!hs_dirs)
hs_dirs = smartlist_new();
smartlist_add(hs_dirs, node->rs);
+ } else if (!strcasecmpstart(arg, opt_hsaddress)) {
+ if (!hs_address_is_valid(arg)) {
+ connection_printf_to_buf(conn, "512 Malformed onion address\r\n");
+ goto done;
+ }
+ onion_address = arg;
} else {
connection_printf_to_buf(conn, "512 Unexpected argument \"%s\"\r\n",
arg);
@@ -4326,6 +4394,19 @@ handle_control_hspost(control_connection_t *conn,
} SMARTLIST_FOREACH_END(arg);
}
+ /* Handle the v3 case. */
+ if (onion_address) {
+ char *desc_str = NULL;
+ read_escaped_data(encoded_desc, encoded_desc_len, &desc_str);
+ if (hs_control_hspost_command(desc_str, onion_address, hs_dirs) < 0) {
+ connection_printf_to_buf(conn, "554 Invalid descriptor\r\n");
+ }
+ tor_free(desc_str);
+ goto done;
+ }
+
+ /* From this point on, it is only v2. */
+
/* Read the dot encoded descriptor, and parse it. */
rend_encoded_v2_service_descriptor_t *desc =
tor_malloc_zero(sizeof(rend_encoded_v2_service_descriptor_t));
@@ -4370,6 +4451,52 @@ handle_control_hspost(control_connection_t *conn,
return 0;
}
+/* Helper function for ADD_ONION that adds an ephemeral service depending on
+ * the given hs_version.
+ *
+ * The secret key in pk depends on the hs_version. The ownership of the key
+ * used in pk is given to the HS subsystem so the caller must stop accessing
+ * it after.
+ *
+ * The port_cfgs is a list of service port. Ownership transfered to service.
+ * The max_streams refers to the MaxStreams= key.
+ * The max_streams_close_circuit refers to the MaxStreamsCloseCircuit key.
+ * The auth_type is the authentication type of the clients in auth_clients.
+ * The ownership of that list is transfered to the service.
+ *
+ * On success (RSAE_OKAY), the address_out points to a newly allocated string
+ * containing the onion address without the .onion part. On error, address_out
+ * is untouched. */
+static hs_service_add_ephemeral_status_t
+add_onion_helper_add_service(int hs_version,
+ add_onion_secret_key_t *pk,
+ smartlist_t *port_cfgs, int max_streams,
+ int max_streams_close_circuit, int auth_type,
+ smartlist_t *auth_clients, char **address_out)
+{
+ hs_service_add_ephemeral_status_t ret;
+
+ tor_assert(pk);
+ tor_assert(port_cfgs);
+ tor_assert(address_out);
+
+ switch (hs_version) {
+ case HS_VERSION_TWO:
+ ret = rend_service_add_ephemeral(pk->v2, port_cfgs, max_streams,
+ max_streams_close_circuit, auth_type,
+ auth_clients, address_out);
+ break;
+ case HS_VERSION_THREE:
+ ret = hs_service_add_ephemeral(pk->v3, port_cfgs, max_streams,
+ max_streams_close_circuit, address_out);
+ break;
+ default:
+ tor_assert_unreached();
+ }
+
+ return ret;
+}
+
/** Called when we get a ADD_ONION command; parse the body, and set up
* the new ephemeral Onion Service. */
static int
@@ -4551,15 +4678,15 @@ handle_control_add_onion(control_connection_t *conn,
}
/* Parse the "keytype:keyblob" argument. */
- crypto_pk_t *pk = NULL;
+ int hs_version = 0;
+ add_onion_secret_key_t pk = { NULL };
const char *key_new_alg = NULL;
char *key_new_blob = NULL;
char *err_msg = NULL;
- pk = add_onion_helper_keyarg(smartlist_get(args, 0), discard_pk,
- &key_new_alg, &key_new_blob,
- &err_msg);
- if (!pk) {
+ if (add_onion_helper_keyarg(smartlist_get(args, 0), discard_pk,
+ &key_new_alg, &key_new_blob, &pk, &hs_version,
+ &err_msg) < 0) {
if (err_msg) {
connection_write_str_to_buf(err_msg, conn);
tor_free(err_msg);
@@ -4568,16 +4695,23 @@ handle_control_add_onion(control_connection_t *conn,
}
tor_assert(!err_msg);
+ /* Hidden service version 3 don't have client authentication support so if
+ * ClientAuth was given, send back an error. */
+ if (hs_version == HS_VERSION_THREE && auth_clients) {
+ connection_printf_to_buf(conn, "513 ClientAuth not supported\r\n");
+ goto out;
+ }
+
/* Create the HS, using private key pk, client authentication auth_type,
* the list of auth_clients, and port config port_cfg.
* rend_service_add_ephemeral() will take ownership of pk and port_cfg,
* regardless of success/failure.
*/
char *service_id = NULL;
- int ret = rend_service_add_ephemeral(pk, port_cfgs, max_streams,
- max_streams_close_circuit,
- auth_type, auth_clients,
- &service_id);
+ int ret = add_onion_helper_add_service(hs_version, &pk, port_cfgs,
+ max_streams,
+ max_streams_close_circuit, auth_type,
+ auth_clients, &service_id);
port_cfgs = NULL; /* port_cfgs is now owned by the rendservice code. */
auth_clients = NULL; /* so is auth_clients */
switch (ret) {
@@ -4670,9 +4804,10 @@ handle_control_add_onion(control_connection_t *conn,
* Note: The error messages returned are deliberately vague to avoid echoing
* key material.
*/
-STATIC crypto_pk_t *
+STATIC int
add_onion_helper_keyarg(const char *arg, int discard_pk,
const char **key_new_alg_out, char **key_new_blob_out,
+ add_onion_secret_key_t *decoded_key, int *hs_version,
char **err_msg_out)
{
smartlist_t *key_args = smartlist_new();
@@ -4680,7 +4815,7 @@ add_onion_helper_keyarg(const char *arg, int discard_pk,
const char *key_new_alg = NULL;
char *key_new_blob = NULL;
char *err_msg = NULL;
- int ok = 0;
+ int ret = -1;
smartlist_split_string(key_args, arg, ":", SPLIT_IGNORE_BLANK, 0);
if (smartlist_len(key_args) != 2) {
@@ -4692,6 +4827,7 @@ add_onion_helper_keyarg(const char *arg, int discard_pk,
static const char *key_type_new = "NEW";
static const char *key_type_best = "BEST";
static const char *key_type_rsa1024 = "RSA1024";
+ static const char *key_type_ed25519_v3 = "ED25519-V3";
const char *key_type = smartlist_get(key_args, 0);
const char *key_blob = smartlist_get(key_args, 1);
@@ -4704,9 +4840,23 @@ add_onion_helper_keyarg(const char *arg, int discard_pk,
goto err;
}
if (crypto_pk_num_bits(pk) != PK_BYTES*8) {
+ crypto_pk_free(pk);
err_msg = tor_strdup("512 Invalid RSA key size\r\n");
goto err;
}
+ decoded_key->v2 = pk;
+ *hs_version = HS_VERSION_TWO;
+ } else if (!strcasecmp(key_type_ed25519_v3, key_type)) {
+ /* "ED25519-V3:<Base64 Blob>" - Loading a pre-existing ed25519 key. */
+ ed25519_secret_key_t *sk = tor_malloc_zero(sizeof(*sk));
+ if (base64_decode((char *) sk->seckey, sizeof(sk->seckey), key_blob,
+ strlen(key_blob)) != sizeof(sk->seckey)) {
+ tor_free(sk);
+ err_msg = tor_strdup("512 Failed to decode ED25519-V3 key\r\n");
+ goto err;
+ }
+ decoded_key->v3 = sk;
+ *hs_version = HS_VERSION_THREE;
} else if (!strcasecmp(key_type_new, key_type)) {
/* "NEW:<Algorithm>" - Generating a new key, blob as algorithm. */
if (!strcasecmp(key_type_rsa1024, key_blob) ||
@@ -4720,12 +4870,38 @@ add_onion_helper_keyarg(const char *arg, int discard_pk,
}
if (!discard_pk) {
if (crypto_pk_base64_encode(pk, &key_new_blob)) {
+ crypto_pk_free(pk);
tor_asprintf(&err_msg, "551 Failed to encode %s key\r\n",
key_type_rsa1024);
goto err;
}
key_new_alg = key_type_rsa1024;
}
+ decoded_key->v2 = pk;
+ *hs_version = HS_VERSION_TWO;
+ } else if (!strcasecmp(key_type_ed25519_v3, key_blob)) {
+ ed25519_secret_key_t *sk = tor_malloc_zero(sizeof(*sk));
+ if (ed25519_secret_key_generate(sk, 1) < 0) {
+ tor_free(sk);
+ tor_asprintf(&err_msg, "551 Failed to generate %s key\r\n",
+ key_type_ed25519_v3);
+ goto err;
+ }
+ if (!discard_pk) {
+ ssize_t len = base64_encode_size(sizeof(sk->seckey), 0) + 1;
+ key_new_blob = tor_malloc_zero(len);
+ if (base64_encode(key_new_blob, len, (const char *) sk->seckey,
+ sizeof(sk->seckey), 0) != (len - 1)) {
+ tor_free(sk);
+ tor_free(key_new_blob);
+ tor_asprintf(&err_msg, "551 Failed to encode %s key\r\n",
+ key_type_ed25519_v3);
+ goto err;
+ }
+ key_new_alg = key_type_ed25519_v3;
+ }
+ decoded_key->v3 = sk;
+ *hs_version = HS_VERSION_THREE;
} else {
err_msg = tor_strdup("513 Invalid key type\r\n");
goto err;
@@ -4736,8 +4912,7 @@ add_onion_helper_keyarg(const char *arg, int discard_pk,
}
/* Succeded in loading or generating a private key. */
- tor_assert(pk);
- ok = 1;
+ ret = 0;
err:
SMARTLIST_FOREACH(key_args, char *, cp, {
@@ -4746,10 +4921,6 @@ add_onion_helper_keyarg(const char *arg, int discard_pk,
});
smartlist_free(key_args);
- if (!ok) {
- crypto_pk_free(pk);
- pk = NULL;
- }
if (err_msg_out) {
*err_msg_out = err_msg;
} else {
@@ -4758,7 +4929,7 @@ add_onion_helper_keyarg(const char *arg, int discard_pk,
*key_new_alg_out = key_new_alg;
*key_new_blob_out = key_new_blob;
- return pk;
+ return ret;
}
/** Helper function to handle parsing a ClientAuth argument to the
@@ -4827,6 +4998,7 @@ handle_control_del_onion(control_connection_t *conn,
uint32_t len,
const char *body)
{
+ int hs_version = 0;
smartlist_t *args;
(void) len; /* body is nul-terminated; it's safe to ignore the length */
args = getargs_helper("DEL_ONION", conn, body, 1, 1);
@@ -4834,7 +5006,11 @@ handle_control_del_onion(control_connection_t *conn,
return 0;
const char *service_id = smartlist_get(args, 0);
- if (!rend_valid_v2_service_id(service_id)) {
+ if (rend_valid_v2_service_id(service_id)) {
+ hs_version = HS_VERSION_TWO;
+ } else if (hs_address_is_valid(service_id)) {
+ hs_version = HS_VERSION_THREE;
+ } else {
connection_printf_to_buf(conn, "512 Malformed Onion Service id\r\n");
goto out;
}
@@ -4861,8 +5037,20 @@ handle_control_del_onion(control_connection_t *conn,
if (onion_services == NULL) {
connection_printf_to_buf(conn, "552 Unknown Onion Service id\r\n");
} else {
- int ret = rend_service_del_ephemeral(service_id);
- if (ret) {
+ int ret = -1;
+ switch (hs_version) {
+ case HS_VERSION_TWO:
+ ret = rend_service_del_ephemeral(service_id);
+ break;
+ case HS_VERSION_THREE:
+ ret = hs_service_del_ephemeral(service_id);
+ break;
+ default:
+ /* The ret value will be -1 thus hitting the warning below. This should
+ * never happen because of the check at the start of the function. */
+ break;
+ }
+ if (ret < 0) {
/* This should *NEVER* fail, since the service is on either the
* per-control connection list, or the global one.
*/
@@ -4932,9 +5120,16 @@ connection_control_closed(control_connection_t *conn)
* The list and it's contents are scrubbed/freed in connection_free_.
*/
if (conn->ephemeral_onion_services) {
- SMARTLIST_FOREACH(conn->ephemeral_onion_services, char *, cp, {
- rend_service_del_ephemeral(cp);
- });
+ SMARTLIST_FOREACH_BEGIN(conn->ephemeral_onion_services, char *, cp) {
+ if (rend_valid_v2_service_id(cp)) {
+ rend_service_del_ephemeral(cp);
+ } else if (hs_address_is_valid(cp)) {
+ hs_service_del_ephemeral(cp);
+ } else {
+ /* An invalid .onion in our list should NEVER happen */
+ tor_fragile_assert();
+ }
+ } SMARTLIST_FOREACH_END(cp);
}
if (conn->is_owning_control_connection) {
@@ -7012,27 +7207,33 @@ rend_hsaddress_str_or_unknown(const char *onion_address)
* <b>rend_query</b> is used to fetch requested onion address and auth type.
* <b>hs_dir</b> is the description of contacting hs directory.
* <b>desc_id_base32</b> is the ID of requested hs descriptor.
+ * <b>hsdir_index</b> is the HSDir fetch index value for v3, an hex string.
*/
void
-control_event_hs_descriptor_requested(const rend_data_t *rend_query,
+control_event_hs_descriptor_requested(const char *onion_address,
+ rend_auth_type_t auth_type,
const char *id_digest,
- const char *desc_id_base32)
+ const char *desc_id,
+ const char *hsdir_index)
{
- if (!id_digest || !rend_query || !desc_id_base32) {
- log_warn(LD_BUG, "Called with rend_query==%p, "
- "id_digest==%p, desc_id_base32==%p",
- rend_query, id_digest, desc_id_base32);
+ char *hsdir_index_field = NULL;
+
+ if (BUG(!id_digest || !desc_id)) {
return;
}
+ if (hsdir_index) {
+ tor_asprintf(&hsdir_index_field, " HSDIR_INDEX=%s", hsdir_index);
+ }
+
send_control_event(EVENT_HS_DESC,
- "650 HS_DESC REQUESTED %s %s %s %s\r\n",
- rend_hsaddress_str_or_unknown(
- rend_data_get_address(rend_query)),
- rend_auth_type_to_string(
- TO_REND_DATA_V2(rend_query)->auth_type),
+ "650 HS_DESC REQUESTED %s %s %s %s%s\r\n",
+ rend_hsaddress_str_or_unknown(onion_address),
+ rend_auth_type_to_string(auth_type),
node_describe_longname_by_id(id_digest),
- desc_id_base32);
+ desc_id,
+ hsdir_index_field ? hsdir_index_field : "");
+ tor_free(hsdir_index_field);
}
/** For an HS descriptor query <b>rend_data</b>, using the
@@ -7081,89 +7282,87 @@ get_desc_id_from_query(const rend_data_t *rend_data, const char *hsdir_fp)
/** send HS_DESC CREATED event when a local service generates a descriptor.
*
- * <b>service_id</b> is the descriptor onion address.
- * <b>desc_id_base32</b> is the descriptor ID.
- * <b>replica</b> is the the descriptor replica number.
+ * <b>onion_address</b> is service address.
+ * <b>desc_id</b> is the descriptor ID.
+ * <b>replica</b> is the the descriptor replica number. If it is negative, it
+ * is ignored.
*/
void
-control_event_hs_descriptor_created(const char *service_id,
- const char *desc_id_base32,
+control_event_hs_descriptor_created(const char *onion_address,
+ const char *desc_id,
int replica)
{
- if (!service_id || !desc_id_base32) {
- log_warn(LD_BUG, "Called with service_digest==%p, "
- "desc_id_base32==%p", service_id, desc_id_base32);
+ char *replica_field = NULL;
+
+ if (BUG(!onion_address || !desc_id)) {
return;
}
+ if (replica >= 0) {
+ tor_asprintf(&replica_field, " REPLICA=%d", replica);
+ }
+
send_control_event(EVENT_HS_DESC,
- "650 HS_DESC CREATED %s UNKNOWN UNKNOWN %s "
- "REPLICA=%d\r\n",
- service_id,
- desc_id_base32,
- replica);
+ "650 HS_DESC CREATED %s UNKNOWN UNKNOWN %s%s\r\n",
+ onion_address, desc_id,
+ replica_field ? replica_field : "");
+ tor_free(replica_field);
}
/** send HS_DESC upload event.
*
- * <b>service_id</b> is the descriptor onion address.
+ * <b>onion_address</b> is service address.
* <b>hs_dir</b> is the description of contacting hs directory.
- * <b>desc_id_base32</b> is the ID of requested hs descriptor.
+ * <b>desc_id</b> is the ID of requested hs descriptor.
*/
void
-control_event_hs_descriptor_upload(const char *service_id,
+control_event_hs_descriptor_upload(const char *onion_address,
const char *id_digest,
- const char *desc_id_base32)
+ const char *desc_id,
+ const char *hsdir_index)
{
- if (!service_id || !id_digest || !desc_id_base32) {
- log_warn(LD_BUG, "Called with service_digest==%p, "
- "desc_id_base32==%p, id_digest==%p", service_id,
- desc_id_base32, id_digest);
+ char *hsdir_index_field = NULL;
+
+ if (BUG(!onion_address || !id_digest || !desc_id)) {
return;
}
+ if (hsdir_index) {
+ tor_asprintf(&hsdir_index_field, " HSDIR_INDEX=%s", hsdir_index);
+ }
+
send_control_event(EVENT_HS_DESC,
- "650 HS_DESC UPLOAD %s UNKNOWN %s %s\r\n",
- service_id,
+ "650 HS_DESC UPLOAD %s UNKNOWN %s %s%s\r\n",
+ onion_address,
node_describe_longname_by_id(id_digest),
- desc_id_base32);
+ desc_id,
+ hsdir_index_field ? hsdir_index_field : "");
+ tor_free(hsdir_index_field);
}
/** send HS_DESC event after got response from hs directory.
*
* NOTE: this is an internal function used by following functions:
- * control_event_hs_descriptor_received
- * control_event_hs_descriptor_failed
+ * control_event_hsv2_descriptor_received
+ * control_event_hsv2_descriptor_failed
+ * control_event_hsv3_descriptor_failed
*
* So do not call this function directly.
*/
-void
-control_event_hs_descriptor_receive_end(const char *action,
- const char *onion_address,
- const rend_data_t *rend_data,
- const char *id_digest,
- const char *reason)
+static void
+event_hs_descriptor_receive_end(const char *action,
+ const char *onion_address,
+ const char *desc_id,
+ rend_auth_type_t auth_type,
+ const char *hsdir_id_digest,
+ const char *reason)
{
- char *desc_id_field = NULL;
char *reason_field = NULL;
- char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
- const char *desc_id = NULL;
- if (!action || !rend_data || !onion_address) {
- log_warn(LD_BUG, "Called with action==%p, rend_data==%p, "
- "onion_address==%p", action, rend_data, onion_address);
+ if (BUG(!action || !onion_address)) {
return;
}
- desc_id = get_desc_id_from_query(rend_data, id_digest);
- if (desc_id != NULL) {
- /* Set the descriptor ID digest to base32 so we can send it. */
- base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_id,
- DIGEST_LEN);
- /* Extra whitespace is needed before the value. */
- tor_asprintf(&desc_id_field, " %s", desc_id_base32);
- }
-
if (reason) {
tor_asprintf(&reason_field, " REASON=%s", reason);
}
@@ -7172,14 +7371,13 @@ control_event_hs_descriptor_receive_end(const char *action,
"650 HS_DESC %s %s %s %s%s%s\r\n",
action,
rend_hsaddress_str_or_unknown(onion_address),
- rend_auth_type_to_string(
- TO_REND_DATA_V2(rend_data)->auth_type),
- id_digest ?
- node_describe_longname_by_id(id_digest) : "UNKNOWN",
- desc_id_field ? desc_id_field : "",
+ rend_auth_type_to_string(auth_type),
+ hsdir_id_digest ?
+ node_describe_longname_by_id(hsdir_id_digest) :
+ "UNKNOWN",
+ desc_id ? desc_id : "",
reason_field ? reason_field : "");
- tor_free(desc_id_field);
tor_free(reason_field);
}
@@ -7199,9 +7397,7 @@ control_event_hs_descriptor_upload_end(const char *action,
{
char *reason_field = NULL;
- if (!action || !id_digest) {
- log_warn(LD_BUG, "Called with action==%p, id_digest==%p", action,
- id_digest);
+ if (BUG(!action || !id_digest)) {
return;
}
@@ -7224,17 +7420,54 @@ control_event_hs_descriptor_upload_end(const char *action,
* called when we successfully received a hidden service descriptor.
*/
void
-control_event_hs_descriptor_received(const char *onion_address,
- const rend_data_t *rend_data,
- const char *id_digest)
+control_event_hsv2_descriptor_received(const char *onion_address,
+ const rend_data_t *rend_data,
+ const char *hsdir_id_digest)
+{
+ char *desc_id_field = NULL;
+ const char *desc_id;
+
+ if (BUG(!rend_data || !hsdir_id_digest || !onion_address)) {
+ return;
+ }
+
+ desc_id = get_desc_id_from_query(rend_data, hsdir_id_digest);
+ if (desc_id != NULL) {
+ char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
+ /* Set the descriptor ID digest to base32 so we can send it. */
+ base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_id,
+ DIGEST_LEN);
+ /* Extra whitespace is needed before the value. */
+ tor_asprintf(&desc_id_field, " %s", desc_id_base32);
+ }
+
+ event_hs_descriptor_receive_end("RECEIVED", onion_address, desc_id_field,
+ TO_REND_DATA_V2(rend_data)->auth_type,
+ hsdir_id_digest, NULL);
+ tor_free(desc_id_field);
+}
+
+/* Send HS_DESC RECEIVED event
+ *
+ * Called when we successfully received a hidden service descriptor. */
+void
+control_event_hsv3_descriptor_received(const char *onion_address,
+ const char *desc_id,
+ const char *hsdir_id_digest)
{
- if (!rend_data || !id_digest || !onion_address) {
- log_warn(LD_BUG, "Called with rend_data==%p, id_digest==%p, "
- "onion_address==%p", rend_data, id_digest, onion_address);
+ char *desc_id_field = NULL;
+
+ if (BUG(!onion_address || !desc_id || !hsdir_id_digest)) {
return;
}
- control_event_hs_descriptor_receive_end("RECEIVED", onion_address,
- rend_data, id_digest, NULL);
+
+ /* Because DescriptorID is an optional positional value, we need to add a
+ * whitespace before in order to not be next to the HsDir value. */
+ tor_asprintf(&desc_id_field, " %s", desc_id);
+
+ event_hs_descriptor_receive_end("RECEIVED", onion_address, desc_id_field,
+ REND_NO_AUTH, hsdir_id_digest, NULL);
+ tor_free(desc_id_field);
}
/** send HS_DESC UPLOADED event
@@ -7245,9 +7478,7 @@ void
control_event_hs_descriptor_uploaded(const char *id_digest,
const char *onion_address)
{
- if (!id_digest) {
- log_warn(LD_BUG, "Called with id_digest==%p",
- id_digest);
+ if (BUG(!id_digest)) {
return;
}
@@ -7261,17 +7492,58 @@ control_event_hs_descriptor_uploaded(const char *id_digest,
* add it to REASON= field.
*/
void
-control_event_hs_descriptor_failed(const rend_data_t *rend_data,
- const char *id_digest,
- const char *reason)
+control_event_hsv2_descriptor_failed(const rend_data_t *rend_data,
+ const char *hsdir_id_digest,
+ const char *reason)
+{
+ char *desc_id_field = NULL;
+ const char *desc_id;
+
+ if (BUG(!rend_data)) {
+ return;
+ }
+
+ desc_id = get_desc_id_from_query(rend_data, hsdir_id_digest);
+ if (desc_id != NULL) {
+ char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
+ /* Set the descriptor ID digest to base32 so we can send it. */
+ base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_id,
+ DIGEST_LEN);
+ /* Extra whitespace is needed before the value. */
+ tor_asprintf(&desc_id_field, " %s", desc_id_base32);
+ }
+
+ event_hs_descriptor_receive_end("FAILED", rend_data_get_address(rend_data),
+ desc_id_field,
+ TO_REND_DATA_V2(rend_data)->auth_type,
+ hsdir_id_digest, reason);
+ tor_free(desc_id_field);
+}
+
+/** Send HS_DESC event to inform controller that the query to
+ * <b>onion_address</b> failed to retrieve hidden service descriptor
+ * <b>desc_id</b> from directory identified by <b>hsdir_id_digest</b>. If
+ * NULL, "UNKNOWN" is used. If <b>reason</b> is not NULL, add it to REASON=
+ * field. */
+void
+control_event_hsv3_descriptor_failed(const char *onion_address,
+ const char *desc_id,
+ const char *hsdir_id_digest,
+ const char *reason)
{
- if (!rend_data) {
- log_warn(LD_BUG, "Called with rend_data==%p", rend_data);
+ char *desc_id_field = NULL;
+
+ if (BUG(!onion_address || !desc_id || !reason)) {
return;
}
- control_event_hs_descriptor_receive_end("FAILED",
- rend_data_get_address(rend_data),
- rend_data, id_digest, reason);
+
+ /* Because DescriptorID is an optional positional value, we need to add a
+ * whitespace before in order to not be next to the HsDir value. */
+ tor_asprintf(&desc_id_field, " %s", desc_id);
+
+ event_hs_descriptor_receive_end("FAILED", onion_address, desc_id_field,
+ REND_NO_AUTH, hsdir_id_digest, reason);
+ tor_free(desc_id_field);
}
/** Send HS_DESC_CONTENT event after completion of a successful fetch from hs
@@ -7321,12 +7593,10 @@ control_event_hs_descriptor_upload_failed(const char *id_digest,
const char *onion_address,
const char *reason)
{
- if (!id_digest) {
- log_warn(LD_BUG, "Called with id_digest==%p",
- id_digest);
+ if (BUG(!id_digest)) {
return;
}
- control_event_hs_descriptor_upload_end("UPLOAD_FAILED", onion_address,
+ control_event_hs_descriptor_upload_end("FAILED", onion_address,
id_digest, reason);
}
diff --git a/src/or/control.h b/src/or/control.h
index 7ec182cb78..28ffeaed86 100644
--- a/src/or/control.h
+++ b/src/or/control.h
@@ -115,32 +115,39 @@ void control_event_transport_launched(const char *mode,
tor_addr_t *addr, uint16_t port);
const char *rend_auth_type_to_string(rend_auth_type_t auth_type);
MOCK_DECL(const char *, node_describe_longname_by_id,(const char *id_digest));
-void control_event_hs_descriptor_requested(const rend_data_t *rend_query,
- const char *desc_id_base32,
- const char *hs_dir);
-void control_event_hs_descriptor_created(const char *service_id,
- const char *desc_id_base32,
+void control_event_hs_descriptor_requested(const char *onion_address,
+ rend_auth_type_t auth_type,
+ const char *id_digest,
+ const char *desc_id,
+ const char *hsdir_index);
+void control_event_hs_descriptor_created(const char *onion_address,
+ const char *desc_id,
int replica);
-void control_event_hs_descriptor_upload(const char *service_id,
- const char *desc_id_base32,
- const char *hs_dir);
-void control_event_hs_descriptor_receive_end(const char *action,
- const char *onion_address,
- const rend_data_t *rend_data,
- const char *id_digest,
- const char *reason);
+void control_event_hs_descriptor_upload(const char *onion_address,
+ const char *desc_id,
+ const char *hs_dir,
+ const char *hsdir_index);
void control_event_hs_descriptor_upload_end(const char *action,
const char *onion_address,
const char *hs_dir,
const char *reason);
-void control_event_hs_descriptor_received(const char *onion_address,
- const rend_data_t *rend_data,
- const char *id_digest);
void control_event_hs_descriptor_uploaded(const char *hs_dir,
const char *onion_address);
-void control_event_hs_descriptor_failed(const rend_data_t *rend_data,
- const char *id_digest,
- const char *reason);
+/* Hidden service v2 HS_DESC specific. */
+void control_event_hsv2_descriptor_failed(const rend_data_t *rend_data,
+ const char *id_digest,
+ const char *reason);
+void control_event_hsv2_descriptor_received(const char *onion_address,
+ const rend_data_t *rend_data,
+ const char *id_digest);
+/* Hidden service v3 HS_DESC specific. */
+void control_event_hsv3_descriptor_failed(const char *onion_address,
+ const char *desc_id,
+ const char *hsdir_id_digest,
+ const char *reason);
+void control_event_hsv3_descriptor_received(const char *onion_address,
+ const char *desc_id,
+ const char *hsdir_id_digest);
void control_event_hs_descriptor_upload_failed(const char *hs_dir,
const char *onion_address,
const char *reason);
@@ -256,10 +263,22 @@ void format_cell_stats(char **event_string, circuit_t *circ,
cell_stats_t *cell_stats);
STATIC char *get_bw_samples(void);
-STATIC crypto_pk_t *add_onion_helper_keyarg(const char *arg, int discard_pk,
- const char **key_new_alg_out,
- char **key_new_blob_out,
- char **err_msg_out);
+/* ADD_ONION secret key to create an ephemeral service. The command supports
+ * multiple versions so this union stores the key and passes it to the HS
+ * subsystem depending on the requested version. */
+typedef union add_onion_secret_key_t {
+ /* Hidden service v2 secret key. */
+ crypto_pk_t *v2;
+ /* Hidden service v3 secret key. */
+ ed25519_secret_key_t *v3;
+} add_onion_secret_key_t;
+
+STATIC int add_onion_helper_keyarg(const char *arg, int discard_pk,
+ const char **key_new_alg_out,
+ char **key_new_blob_out,
+ add_onion_secret_key_t *decoded_key,
+ int *hs_version, char **err_msg_out);
+
STATIC rend_authorized_client_t *
add_onion_helper_clientauth(const char *arg, int *created, char **err_msg_out);
diff --git a/src/or/cpuworker.c b/src/or/cpuworker.c
index d9371b3446..9bec04d790 100644
--- a/src/or/cpuworker.c
+++ b/src/or/cpuworker.c
@@ -48,14 +48,25 @@ worker_state_new(void *arg)
ws->onion_keys = server_onion_keys_new();
return ws;
}
+
+#define worker_state_free(ws) \
+ FREE_AND_NULL(worker_state_t, worker_state_free_, (ws))
+
static void
-worker_state_free(void *arg)
+worker_state_free_(worker_state_t *ws)
{
- worker_state_t *ws = arg;
+ if (!ws)
+ return;
server_onion_keys_free(ws->onion_keys);
tor_free(ws);
}
+static void
+worker_state_free_void(void *arg)
+{
+ worker_state_free_(arg);
+}
+
static replyqueue_t *replyqueue = NULL;
static threadpool_t *threadpool = NULL;
static struct event *reply_event = NULL;
@@ -102,7 +113,7 @@ cpu_init(void)
threadpool = threadpool_new(n_threads,
replyqueue,
worker_state_new,
- worker_state_free,
+ worker_state_free_void,
NULL);
}
/* Total voodoo. Can we make this more sensible? */
@@ -198,7 +209,7 @@ cpuworkers_rotate_keyinfo(void)
if (threadpool_queue_update(threadpool,
worker_state_new,
update_state_threadfn,
- worker_state_free,
+ worker_state_free_void,
NULL)) {
log_warn(LD_OR, "Failed to queue key update for worker threads.");
}
diff --git a/src/or/dircollate.c b/src/or/dircollate.c
index d34ebe8af5..ce4534ff6c 100644
--- a/src/or/dircollate.c
+++ b/src/or/dircollate.c
@@ -41,9 +41,12 @@ typedef struct ddmap_entry_s {
vote_routerstatus_t *vrs_lst[FLEXIBLE_ARRAY_MEMBER];
} ddmap_entry_t;
+#define ddmap_entry_free(e) \
+ FREE_AND_NULL(ddmap_entry_t, ddmap_entry_free_, (e))
+
/** Release all storage held by e. */
static void
-ddmap_entry_free(ddmap_entry_t *e)
+ddmap_entry_free_(ddmap_entry_t *e)
{
tor_free(e);
}
@@ -158,7 +161,7 @@ dircollator_new(int n_votes, int n_authorities)
/** Release all storage held by <b>dc</b>. */
void
-dircollator_free(dircollator_t *dc)
+dircollator_free_(dircollator_t *dc)
{
if (!dc)
return;
diff --git a/src/or/dircollate.h b/src/or/dircollate.h
index 7932e18998..0584b2fe06 100644
--- a/src/or/dircollate.h
+++ b/src/or/dircollate.h
@@ -18,7 +18,9 @@
typedef struct dircollator_s dircollator_t;
dircollator_t *dircollator_new(int n_votes, int n_authorities);
-void dircollator_free(dircollator_t *obj);
+void dircollator_free_(dircollator_t *obj);
+#define dircollator_free(c) \
+ FREE_AND_NULL(dircollator_t, dircollator_free_, (c))
void dircollator_add_vote(dircollator_t *dc, networkstatus_t *v);
void dircollator_collate(dircollator_t *dc, int consensus_method);
diff --git a/src/or/directory.c b/src/or/directory.c
index e7a5da8139..dcdcff396f 100644
--- a/src/or/directory.c
+++ b/src/or/directory.c
@@ -25,6 +25,7 @@
#include "geoip.h"
#include "hs_cache.h"
#include "hs_common.h"
+#include "hs_control.h"
#include "hs_client.h"
#include "main.h"
#include "microdesc.h"
@@ -116,7 +117,8 @@ static void dir_routerdesc_download_failed(smartlist_t *failed,
int was_extrainfo,
int was_descriptor_digests);
static void dir_microdesc_download_failed(smartlist_t *failed,
- int status_code);
+ int status_code,
+ const char *dir_id);
static int client_likes_consensus(const struct consensus_cache_entry_t *ent,
const char *want_url);
@@ -469,7 +471,7 @@ directory_pick_generic_dirserver(dirinfo_type_t type, int pds_flags,
log_warn(LD_BUG, "Called when we have UseBridges set.");
if (should_use_directory_guards(options)) {
- const node_t *node = guards_choose_dirguard(guard_state_out);
+ const node_t *node = guards_choose_dirguard(dir_purpose, guard_state_out);
if (node)
rs = node->rs;
} else {
@@ -603,7 +605,7 @@ directory_get_from_dirserver,(
* sort of dir fetch we'll be doing, so it won't return a bridge
* that can't answer our question.
*/
- const node_t *node = guards_choose_dirguard(&guard_state);
+ const node_t *node = guards_choose_dirguard(dir_purpose, &guard_state);
if (node && node->ri) {
/* every bridge has a routerinfo. */
routerinfo_t *ri = node->ri;
@@ -1011,48 +1013,6 @@ directory_must_use_begindir(const or_options_t *options)
return !public_server_mode(options);
}
-struct directory_request_t {
- /**
- * These fields specify which directory we're contacting. Routerstatus,
- * if present, overrides the other fields.
- *
- * @{ */
- tor_addr_port_t or_addr_port;
- tor_addr_port_t dir_addr_port;
- char digest[DIGEST_LEN];
-
- const routerstatus_t *routerstatus;
- /** @} */
- /** One of DIR_PURPOSE_* other than DIR_PURPOSE_SERVER. Describes what
- * kind of operation we'll be doing (upload/download), and of what kind
- * of document. */
- uint8_t dir_purpose;
- /** One of ROUTER_PURPOSE_*; used for uploads and downloads of routerinfo
- * and extrainfo docs. */
- uint8_t router_purpose;
- /** Enum: determines whether to anonymize, and whether to use dirport or
- * orport. */
- dir_indirection_t indirection;
- /** Alias to the variable part of the URL for this request */
- const char *resource;
- /** Alias to the payload to upload (if any) */
- const char *payload;
- /** Number of bytes to upload from payload</b> */
- size_t payload_len;
- /** Value to send in an if-modified-since header, or 0 for none. */
- time_t if_modified_since;
- /** Hidden-service-specific information v2. */
- const rend_data_t *rend_query;
- /** Extra headers to append to the request */
- config_line_t *additional_headers;
- /** Hidden-service-specific information for v3+. */
- const hs_ident_dir_conn_t *hs_ident;
- /** Used internally to directory.c: gets informed when the attempt to
- * connect to the directory succeeds or fails, if that attempt bears on the
- * directory's usability as a directory guard. */
- circuit_guard_state_t *guard_state;
-};
-
/** Evaluate the situation and decide if we should use an encrypted
* "begindir-style" connection for this directory request.
* 0) If there is no DirPort, yes.
@@ -1142,7 +1102,7 @@ directory_request_new(uint8_t dir_purpose)
* Release all resources held by <b>req</b>.
*/
void
-directory_request_free(directory_request_t *req)
+directory_request_free_(directory_request_t *req)
{
if (req == NULL)
return;
@@ -2245,8 +2205,6 @@ static int handle_response_fetch_detached_signatures(dir_connection_t *,
const response_handler_args_t *);
static int handle_response_fetch_desc(dir_connection_t *,
const response_handler_args_t *);
-static int handle_response_fetch_microdesc(dir_connection_t *,
- const response_handler_args_t *);
static int handle_response_upload_dir(dir_connection_t *,
const response_handler_args_t *);
static int handle_response_upload_vote(dir_connection_t *,
@@ -2887,7 +2845,7 @@ handle_response_fetch_desc(dir_connection_t *conn,
conn->router_purpose,
conn->base_.address)) {
time_t now = approx_time();
- directory_info_has_arrived(now, 0, 0);
+ directory_info_has_arrived(now, 0, 1);
}
}
}
@@ -2914,7 +2872,7 @@ handle_response_fetch_desc(dir_connection_t *conn,
* Handler function: processes a response to a request for a group of
* microdescriptors
**/
-static int
+STATIC int
handle_response_fetch_microdesc(dir_connection_t *conn,
const response_handler_args_t *args)
{
@@ -2931,6 +2889,7 @@ handle_response_fetch_microdesc(dir_connection_t *conn,
conn->base_.port);
tor_assert(conn->requested_resource &&
!strcmpstart(conn->requested_resource, "d/"));
+ tor_assert_nonfatal(!tor_mem_is_zero(conn->identity_digest, DIGEST_LEN));
which = smartlist_new();
dir_split_resource_into_fingerprints(conn->requested_resource+2,
which, NULL,
@@ -2941,7 +2900,7 @@ handle_response_fetch_microdesc(dir_connection_t *conn,
"soon.",
status_code, escaped(reason), conn->base_.address,
(int)conn->base_.port, conn->requested_resource);
- dir_microdesc_download_failed(which, status_code);
+ dir_microdesc_download_failed(which, status_code, conn->identity_digest);
SMARTLIST_FOREACH(which, char *, cp, tor_free(cp));
smartlist_free(which);
return 0;
@@ -2953,7 +2912,7 @@ handle_response_fetch_microdesc(dir_connection_t *conn,
now, which);
if (smartlist_len(which)) {
/* Mark remaining ones as failed. */
- dir_microdesc_download_failed(which, status_code);
+ dir_microdesc_download_failed(which, status_code, conn->identity_digest);
}
if (mds && smartlist_len(mds)) {
control_event_bootstrap(BOOTSTRAP_STATUS_LOADING_DESCRIPTORS,
@@ -3132,10 +3091,19 @@ handle_response_fetch_hsdesc_v3(dir_connection_t *conn,
/* We got something: Try storing it in the cache. */
if (hs_cache_store_as_client(body, &conn->hs_ident->identity_pk) < 0) {
log_warn(LD_REND, "Failed to store hidden service descriptor");
+ /* Fire control port FAILED event. */
+ hs_control_desc_event_failed(conn->hs_ident, conn->identity_digest,
+ "BAD_DESC");
+ hs_control_desc_event_content(conn->hs_ident, conn->identity_digest,
+ NULL);
} else {
log_info(LD_REND, "Stored hidden service descriptor successfully.");
TO_CONN(conn)->purpose = DIR_PURPOSE_HAS_FETCHED_HSDESC;
hs_client_desc_has_arrived(conn->hs_ident);
+ /* Fire control port RECEIVED event. */
+ hs_control_desc_event_received(conn->hs_ident, conn->identity_digest);
+ hs_control_desc_event_content(conn->hs_ident, conn->identity_digest,
+ body);
}
break;
case 404:
@@ -3143,13 +3111,22 @@ handle_response_fetch_hsdesc_v3(dir_connection_t *conn,
* tries to clean this conn up. */
log_info(LD_REND, "Fetching hidden service v3 descriptor not found: "
"Retrying at another directory.");
- /* TODO: Inform the control port */
+ /* Fire control port FAILED event. */
+ hs_control_desc_event_failed(conn->hs_ident, conn->identity_digest,
+ "NOT_FOUND");
+ hs_control_desc_event_content(conn->hs_ident, conn->identity_digest,
+ NULL);
break;
case 400:
log_warn(LD_REND, "Fetching v3 hidden service descriptor failed: "
"http status 400 (%s). Dirserver didn't like our "
"query? Retrying at another directory.",
escaped(reason));
+ /* Fire control port FAILED event. */
+ hs_control_desc_event_failed(conn->hs_ident, conn->identity_digest,
+ "QUERY_REJECTED");
+ hs_control_desc_event_content(conn->hs_ident, conn->identity_digest,
+ NULL);
break;
default:
log_warn(LD_REND, "Fetching v3 hidden service descriptor failed: "
@@ -3157,6 +3134,11 @@ handle_response_fetch_hsdesc_v3(dir_connection_t *conn,
"'%s:%d'. Retrying at another directory.",
status_code, escaped(reason), TO_CONN(conn)->address,
TO_CONN(conn)->port);
+ /* Fire control port FAILED event. */
+ hs_control_desc_event_failed(conn->hs_ident, conn->identity_digest,
+ "UNEXPECTED");
+ hs_control_desc_event_content(conn->hs_ident, conn->identity_digest,
+ NULL);
break;
}
@@ -3178,9 +3160,9 @@ handle_response_fetch_renddesc_v2(dir_connection_t *conn,
const size_t body_len = args->body_len;
#define SEND_HS_DESC_FAILED_EVENT(reason) \
- (control_event_hs_descriptor_failed(conn->rend_data, \
- conn->identity_digest, \
- reason))
+ (control_event_hsv2_descriptor_failed(conn->rend_data, \
+ conn->identity_digest, \
+ reason))
#define SEND_HS_DESC_FAILED_CONTENT() \
(control_event_hs_descriptor_content( \
rend_data_get_address(conn->rend_data), \
@@ -3215,9 +3197,9 @@ handle_response_fetch_renddesc_v2(dir_connection_t *conn,
/* success. notify pending connections about this. */
log_info(LD_REND, "Successfully fetched v2 rendezvous "
"descriptor.");
- control_event_hs_descriptor_received(service_id,
- conn->rend_data,
- conn->identity_digest);
+ control_event_hsv2_descriptor_received(service_id,
+ conn->rend_data,
+ conn->identity_digest);
control_event_hs_descriptor_content(service_id,
conn->requested_resource,
conn->identity_digest,
@@ -3334,14 +3316,16 @@ handle_response_upload_hsdesc(dir_connection_t *conn,
case 200:
log_info(LD_REND, "Uploading hidden service descriptor: "
"finished with status 200 (%s)", escaped(reason));
- /* XXX: Trigger control event. */
+ hs_control_desc_event_uploaded(conn->hs_ident, conn->identity_digest);
break;
case 400:
- log_warn(LD_REND, "Uploading hidden service descriptor: http "
- "status 400 (%s) response from dirserver "
- "'%s:%d'. Malformed hidden service descriptor?",
- escaped(reason), conn->base_.address, conn->base_.port);
- /* XXX: Trigger control event. */
+ log_fn(LOG_PROTOCOL_WARN, LD_REND,
+ "Uploading hidden service descriptor: http "
+ "status 400 (%s) response from dirserver "
+ "'%s:%d'. Malformed hidden service descriptor?",
+ escaped(reason), conn->base_.address, conn->base_.port);
+ hs_control_desc_event_failed(conn->hs_ident, conn->identity_digest,
+ "UPLOAD_REJECTED");
break;
default:
log_warn(LD_REND, "Uploading hidden service descriptor: http "
@@ -3349,7 +3333,8 @@ handle_response_upload_hsdesc(dir_connection_t *conn,
"'%s:%d').",
status_code, escaped(reason), conn->base_.address,
conn->base_.port);
- /* XXX: Trigger control event. */
+ hs_control_desc_event_failed(conn->hs_ident, conn->identity_digest,
+ "UNEXPECTED");
break;
}
@@ -5793,13 +5778,14 @@ dir_routerdesc_download_failed(smartlist_t *failed, int status_code,
* every 10 or 60 seconds (FOO_DESCRIPTOR_RETRY_INTERVAL) in main.c. */
}
-/** Called when a connection to download microdescriptors has failed in whole
- * or in part. <b>failed</b> is a list of every microdesc digest we didn't
- * get. <b>status_code</b> is the http status code we received. Reschedule the
- * microdesc downloads as appropriate. */
+/** Called when a connection to download microdescriptors from relay with
+ * <b>dir_id</b> has failed in whole or in part. <b>failed</b> is a list
+ * of every microdesc digest we didn't get. <b>status_code</b> is the http
+ * status code we received. Reschedule the microdesc downloads as
+ * appropriate. */
static void
dir_microdesc_download_failed(smartlist_t *failed,
- int status_code)
+ int status_code, const char *dir_id)
{
networkstatus_t *consensus
= networkstatus_get_latest_consensus_by_flavor(FLAV_MICRODESC);
@@ -5810,17 +5796,26 @@ dir_microdesc_download_failed(smartlist_t *failed,
if (! consensus)
return;
+
+ /* We failed to fetch a microdescriptor from 'dir_id', note it down
+ * so that we don't try the same relay next time... */
+ microdesc_note_outdated_dirserver(dir_id);
+
SMARTLIST_FOREACH_BEGIN(failed, const char *, d) {
rs = router_get_mutable_consensus_status_by_descriptor_digest(consensus,d);
if (!rs)
continue;
dls = &rs->dl_status;
if (dls->n_download_failures >=
- get_options()->TestingMicrodescMaxDownloadTries)
+ get_options()->TestingMicrodescMaxDownloadTries) {
continue;
- {
+ }
+
+ { /* Increment the failure count for this md fetch */
char buf[BASE64_DIGEST256_LEN+1];
digest256_to_base64(buf, d);
+ log_info(LD_DIR, "Failed to download md %s from %s",
+ buf, hex_str(dir_id, DIGEST_LEN));
download_status_increment_failure(dls, status_code, buf,
server, now);
}
diff --git a/src/or/directory.h b/src/or/directory.h
index 904bdfae46..edf75ffe13 100644
--- a/src/or/directory.h
+++ b/src/or/directory.h
@@ -51,7 +51,9 @@ int directory_must_use_begindir(const or_options_t *options);
*/
typedef struct directory_request_t directory_request_t;
directory_request_t *directory_request_new(uint8_t dir_purpose);
-void directory_request_free(directory_request_t *req);
+void directory_request_free_(directory_request_t *req);
+#define directory_request_free(req) \
+ FREE_AND_NULL(directory_request_t, directory_request_free_, (req))
void directory_request_set_or_addr_port(directory_request_t *req,
const tor_addr_port_t *p);
void directory_request_set_dir_addr_port(directory_request_t *req,
@@ -183,6 +185,48 @@ typedef struct response_handler_args_t {
const char *headers;
} response_handler_args_t;
+struct directory_request_t {
+ /**
+ * These fields specify which directory we're contacting. Routerstatus,
+ * if present, overrides the other fields.
+ *
+ * @{ */
+ tor_addr_port_t or_addr_port;
+ tor_addr_port_t dir_addr_port;
+ char digest[DIGEST_LEN];
+
+ const routerstatus_t *routerstatus;
+ /** @} */
+ /** One of DIR_PURPOSE_* other than DIR_PURPOSE_SERVER. Describes what
+ * kind of operation we'll be doing (upload/download), and of what kind
+ * of document. */
+ uint8_t dir_purpose;
+ /** One of ROUTER_PURPOSE_*; used for uploads and downloads of routerinfo
+ * and extrainfo docs. */
+ uint8_t router_purpose;
+ /** Enum: determines whether to anonymize, and whether to use dirport or
+ * orport. */
+ dir_indirection_t indirection;
+ /** Alias to the variable part of the URL for this request */
+ const char *resource;
+ /** Alias to the payload to upload (if any) */
+ const char *payload;
+ /** Number of bytes to upload from payload</b> */
+ size_t payload_len;
+ /** Value to send in an if-modified-since header, or 0 for none. */
+ time_t if_modified_since;
+ /** Hidden-service-specific information v2. */
+ const rend_data_t *rend_query;
+ /** Extra headers to append to the request */
+ config_line_t *additional_headers;
+ /** Hidden-service-specific information for v3+. */
+ const hs_ident_dir_conn_t *hs_ident;
+ /** Used internally to directory.c: gets informed when the attempt to
+ * connect to the directory succeeds or fails, if that attempt bears on the
+ * directory's usability as a directory guard. */
+ struct circuit_guard_state_t *guard_state;
+};
+
struct get_handler_args_t;
STATIC int handle_get_hs_descriptor_v3(dir_connection_t *conn,
const struct get_handler_args_t *args);
@@ -193,6 +237,8 @@ STATIC void warn_disallowed_anonymous_compression_method(compress_method_t);
STATIC int handle_response_fetch_hsdesc_v3(dir_connection_t *conn,
const response_handler_args_t *args);
+STATIC int handle_response_fetch_microdesc(dir_connection_t *conn,
+ const response_handler_args_t *args);
STATIC int handle_response_fetch_consensus(dir_connection_t *conn,
const response_handler_args_t *args);
diff --git a/src/or/dirserv.c b/src/or/dirserv.c
index ddee92da55..d3bae241f9 100644
--- a/src/or/dirserv.c
+++ b/src/or/dirserv.c
@@ -1519,15 +1519,21 @@ dirserv_compute_performance_thresholds(digestmap_t *omit_as_sybil)
node->ri &&
node->ri->purpose != ROUTER_PURPOSE_BRIDGE)
continue;
+
+ routerinfo_t *ri = node->ri;
+ if (ri) {
+ node->is_exit = (!router_exit_policy_rejects_all(ri) &&
+ exit_policy_is_general_exit(ri->exit_policy));
+ }
+
if (router_counts_toward_thresholds(node, now, omit_as_sybil,
require_mbw)) {
- routerinfo_t *ri = node->ri;
const char *id = node->identity;
uint32_t bw_kb;
+
/* resolve spurious clang shallow analysis null pointer errors */
tor_assert(ri);
- node->is_exit = (!router_exit_policy_rejects_all(ri) &&
- exit_policy_is_general_exit(ri->exit_policy));
+
uptimes[n_active] = (uint32_t)real_uptime(ri, now);
mtbfs[n_active] = rep_hist_get_stability(id, now);
tks [n_active] = rep_hist_get_weighted_time_known(id, now);
@@ -1897,21 +1903,28 @@ version_from_platform(const char *platform)
/** Helper: write the router-status information in <b>rs</b> into a newly
* allocated character buffer. Use the same format as in network-status
* documents. If <b>version</b> is non-NULL, add a "v" line for the platform.
+ *
+ * consensus_method is the current consensus method when format is
+ * NS_V3_CONSENSUS or NS_V3_CONSENSUS_MICRODESC. It is ignored for other
+ * formats: pass ROUTERSTATUS_FORMAT_NO_CONSENSUS_METHOD.
+ *
* Return 0 on success, -1 on failure.
*
* The format argument has one of the following values:
* NS_V2 - Output an entry suitable for a V2 NS opinion document
* NS_V3_CONSENSUS - Output the first portion of a V3 NS consensus entry
+ * for consensus_method.
* NS_V3_CONSENSUS_MICRODESC - Output the first portion of a V3 microdesc
- * consensus entry.
+ * consensus entry for consensus_method.
* NS_V3_VOTE - Output a complete V3 NS vote. If <b>vrs</b> is present,
* it contains additional information for the vote.
- * NS_CONTROL_PORT - Output a NS document for the control port
+ * NS_CONTROL_PORT - Output a NS document for the control port.
*/
char *
routerstatus_format_entry(const routerstatus_t *rs, const char *version,
const char *protocols,
routerstatus_format_type_t format,
+ int consensus_method,
const vote_routerstatus_t *vrs)
{
char *summary;
@@ -1942,8 +1955,10 @@ routerstatus_format_entry(const routerstatus_t *rs, const char *version,
* networkstatus_type_t values, with an additional control port value
* added -MP */
- /* V3 microdesc consensuses don't have "a" lines. */
- if (format == NS_V3_CONSENSUS_MICRODESC)
+ /* V3 microdesc consensuses only have "a" lines in later consensus methods
+ */
+ if (format == NS_V3_CONSENSUS_MICRODESC &&
+ consensus_method < MIN_METHOD_FOR_A_LINES_IN_MICRODESC_CONSENSUS)
goto done;
/* Possible "a" line. At most one for now. */
@@ -1952,7 +1967,7 @@ routerstatus_format_entry(const routerstatus_t *rs, const char *version,
fmt_addrport(&rs->ipv6_addr, rs->ipv6_orport));
}
- if (format == NS_V3_CONSENSUS)
+ if (format == NS_V3_CONSENSUS || format == NS_V3_CONSENSUS_MICRODESC)
goto done;
smartlist_add_asprintf(chunks,
@@ -2213,7 +2228,8 @@ routers_make_ed_keys_unique(smartlist_t *routers)
}
/** Extract status information from <b>ri</b> and from other authority
- * functions and store it in <b>rs</b>>.
+ * functions and store it in <b>rs</b>. <b>rs</b> is zeroed out before it is
+ * set.
*
* We assume that ri-\>is_running has already been set, e.g. by
* dirserv_set_router_is_running(ri, now);
@@ -2279,6 +2295,9 @@ set_routerstatus_from_routerinfo(routerstatus_t *rs,
OR port and it's reachable so copy it to the routerstatus. */
tor_addr_copy(&rs->ipv6_addr, &ri->ipv6_addr);
rs->ipv6_orport = ri->ipv6_orport;
+ } else {
+ tor_addr_make_null(&rs->ipv6_addr, AF_INET6);
+ rs->ipv6_orport = 0;
}
if (options->TestingTorNetwork) {
@@ -3284,7 +3303,7 @@ dirserv_orconn_tls_done(const tor_addr_t *addr,
ri = node->ri;
if (get_options()->AuthDirTestEd25519LinkKeys &&
- node_supports_ed25519_link_authentication(node) &&
+ node_supports_ed25519_link_authentication(node, 1) &&
ri->cache_info.signing_key_cert) {
/* We allow the node to have an ed25519 key if we haven't been told one in
* the routerinfo, but if we *HAVE* been told one in the routerinfo, it
@@ -3367,7 +3386,7 @@ dirserv_single_reachability_test(time_t now, routerinfo_t *router)
tor_assert(node);
if (options->AuthDirTestEd25519LinkKeys &&
- node_supports_ed25519_link_authentication(node)) {
+ node_supports_ed25519_link_authentication(node, 1)) {
ed_id_key = &router->cache_info.signing_key_cert->signing_key;
} else {
ed_id_key = NULL;
@@ -3496,7 +3515,7 @@ spooled_resource_new_from_cache_entry(consensus_cache_entry_t *entry)
/** Release all storage held by <b>spooled</b>. */
void
-spooled_resource_free(spooled_resource_t *spooled)
+spooled_resource_free_(spooled_resource_t *spooled)
{
if (spooled == NULL)
return;
diff --git a/src/or/dirserv.h b/src/or/dirserv.h
index 46967a6cb2..0fd7b79150 100644
--- a/src/or/dirserv.h
+++ b/src/or/dirserv.h
@@ -150,6 +150,7 @@ char *routerstatus_format_entry(
const char *version,
const char *protocols,
routerstatus_format_type_t format,
+ int consensus_method,
const vote_routerstatus_t *vrs);
void dirserv_free_all(void);
void cached_dir_decref(cached_dir_t *d);
@@ -195,7 +196,9 @@ spooled_resource_t *spooled_resource_new(dir_spool_source_t source,
size_t digestlen);
spooled_resource_t *spooled_resource_new_from_cache_entry(
struct consensus_cache_entry_t *entry);
-void spooled_resource_free(spooled_resource_t *spooled);
+void spooled_resource_free_(spooled_resource_t *spooled);
+#define spooled_resource_free(sp) \
+ FREE_AND_NULL(spooled_resource_t, spooled_resource_free_, (sp))
void dirserv_spool_remove_missing_and_guess_size(dir_connection_t *conn,
time_t cutoff,
int compression,
diff --git a/src/or/dirvote.c b/src/or/dirvote.c
index ce82a5ef4a..a75d9e55a5 100644
--- a/src/or/dirvote.c
+++ b/src/or/dirvote.c
@@ -278,7 +278,9 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key,
vote_microdesc_hash_t *h;
rsf = routerstatus_format_entry(&vrs->status,
vrs->version, vrs->protocols,
- NS_V3_VOTE, vrs);
+ NS_V3_VOTE,
+ ROUTERSTATUS_FORMAT_NO_CONSENSUS_METHOD,
+ vrs);
if (rsf)
smartlist_add(chunks, rsf);
@@ -519,7 +521,7 @@ compute_routerstatus_consensus(smartlist_t *votes, int consensus_method,
/* compare_vote_rs_() sorts the items by identity digest (all the same),
* then by SD digest. That way, if we have a tie that the published_on
- * date cannot tie, we use the descriptor with the smaller digest.
+ * date cannot break, we use the descriptor with the smaller digest.
*/
smartlist_sort(votes, compare_vote_rs_);
SMARTLIST_FOREACH_BEGIN(votes, vote_routerstatus_t *, rs) {
@@ -795,6 +797,9 @@ dirvote_compute_params(smartlist_t *votes, int method, int total_authorities)
output = smartlist_new();
SMARTLIST_FOREACH_BEGIN(param_list, const char *, param) {
+ /* resolve spurious clang shallow analysis null pointer errors */
+ tor_assert(param);
+
const char *next_param;
int ok=0;
eq = strchr(param, '=');
@@ -807,8 +812,7 @@ dirvote_compute_params(smartlist_t *votes, int method, int total_authorities)
next_param = NULL;
else
next_param = smartlist_get(param_list, param_sl_idx+1);
- /* resolve spurious clang shallow analysis null pointer errors */
- tor_assert(param);
+
if (!next_param || strncmp(next_param, param, cur_param_len)) {
/* We've reached the end of a series. */
/* Make sure enough authorities voted on this param, unless the
@@ -1315,8 +1319,9 @@ compute_nth_protocol_set(int n, int n_voters, const smartlist_t *votes)
/** Given a list of vote networkstatus_t in <b>votes</b>, our public
* authority <b>identity_key</b>, our private authority <b>signing_key</b>,
* and the number of <b>total_authorities</b> that we believe exist in our
- * voting quorum, generate the text of a new v3 consensus vote, and return the
- * value in a newly allocated string.
+ * voting quorum, generate the text of a new v3 consensus or microdescriptor
+ * consensus (depending on <b>flavor</b>), and return the value in a newly
+ * allocated string.
*
* Note: this function DOES NOT check whether the votes are from
* recognized authorities. (dirvote_add_vote does that.)
@@ -2099,7 +2104,8 @@ networkstatus_compute_consensus(smartlist_t *votes,
char *buf;
/* Okay!! Now we can write the descriptor... */
/* First line goes into "buf". */
- buf = routerstatus_format_entry(&rs_out, NULL, NULL, rs_format, NULL);
+ buf = routerstatus_format_entry(&rs_out, NULL, NULL,
+ rs_format, consensus_method, NULL);
if (buf)
smartlist_add(chunks, buf);
}
@@ -2685,7 +2691,7 @@ get_detached_signatures_from_pending_consensuses(pending_consensus_t *pending,
/** Release all storage held in <b>s</b>. */
void
-ns_detached_signatures_free(ns_detached_signatures_t *s)
+ns_detached_signatures_free_(ns_detached_signatures_t *s)
{
if (!s)
return;
@@ -2843,10 +2849,13 @@ get_voting_schedule(const or_options_t *options, time_t now, int severity)
return new_voting_schedule;
}
+#define voting_schedule_free(s) \
+ FREE_AND_NULL(voting_schedule_t, voting_schedule_free_, (s))
+
/** Frees a voting_schedule_t. This should be used instead of the generic
* tor_free. */
static void
-voting_schedule_free(voting_schedule_t *voting_schedule_to_free)
+voting_schedule_free_(voting_schedule_t *voting_schedule_to_free)
{
if (!voting_schedule_to_free)
return;
@@ -3829,7 +3838,10 @@ dirvote_create_microdescriptor(const routerinfo_t *ri, int consensus_method)
smartlist_add_asprintf(chunks, "ntor-onion-key %s", kbuf);
}
+ /* We originally put a lines in the micrdescriptors, but then we worked out
+ * that we needed them in the microdesc consensus. See #20916. */
if (consensus_method >= MIN_METHOD_FOR_A_LINES &&
+ consensus_method < MIN_METHOD_FOR_NO_A_LINES_IN_MICRODESC &&
!tor_addr_is_null(&ri->ipv6_addr) && ri->ipv6_orport)
smartlist_add_asprintf(chunks, "a %s\n",
fmt_addrport(&ri->ipv6_addr, ri->ipv6_orport));
@@ -3938,7 +3950,9 @@ static const struct consensus_method_range_t {
{MIN_METHOD_FOR_P6_LINES, MIN_METHOD_FOR_NTOR_KEY - 1},
{MIN_METHOD_FOR_NTOR_KEY, MIN_METHOD_FOR_ID_HASH_IN_MD - 1},
{MIN_METHOD_FOR_ID_HASH_IN_MD, MIN_METHOD_FOR_ED25519_ID_IN_MD - 1},
- {MIN_METHOD_FOR_ED25519_ID_IN_MD, MAX_SUPPORTED_CONSENSUS_METHOD},
+ {MIN_METHOD_FOR_ED25519_ID_IN_MD,
+ MIN_METHOD_FOR_NO_A_LINES_IN_MICRODESC - 1},
+ {MIN_METHOD_FOR_NO_A_LINES_IN_MICRODESC, MAX_SUPPORTED_CONSENSUS_METHOD},
{-1, -1}
};
diff --git a/src/or/dirvote.h b/src/or/dirvote.h
index 72a35fea6d..deeb27bfe1 100644
--- a/src/or/dirvote.h
+++ b/src/or/dirvote.h
@@ -51,11 +51,15 @@
#define MIN_VOTE_INTERVAL_TESTING_INITIAL \
((MIN_VOTE_SECONDS_TESTING)+(MIN_DIST_SECONDS_TESTING)+1)
+/* A placeholder for routerstatus_format_entry() when the consensus method
+ * argument is not applicable. */
+#define ROUTERSTATUS_FORMAT_NO_CONSENSUS_METHOD 0
+
/** The lowest consensus method that we currently support. */
#define MIN_SUPPORTED_CONSENSUS_METHOD 13
/** The highest consensus method that we currently support. */
-#define MAX_SUPPORTED_CONSENSUS_METHOD 26
+#define MAX_SUPPORTED_CONSENSUS_METHOD 28
/** Lowest consensus method where microdesc consensuses omit any entry
* with no microdesc. */
@@ -115,6 +119,14 @@
* instead of 0. See #14881 */
#define MIN_METHOD_FOR_INIT_BW_WEIGHTS_ONE 26
+/** Lowest consensus method where the microdesc consensus contains relay IPv6
+ * addresses. See #23826 and #20916. */
+#define MIN_METHOD_FOR_A_LINES_IN_MICRODESC_CONSENSUS 27
+
+/** Lowest consensus method where microdescriptors do not contain relay IPv6
+ * addresses. See #23828 and #20916. */
+#define MIN_METHOD_FOR_NO_A_LINES_IN_MICRODESC 28
+
/** Default bandwidth to clip unmeasured bandwidths to using method >=
* MIN_METHOD_TO_CLIP_UNMEASURED_BW. (This is not a consensus method; do not
* get confused with the above macros.) */
@@ -136,7 +148,9 @@ int networkstatus_add_detached_signatures(networkstatus_t *target,
int severity,
const char **msg_out);
char *networkstatus_get_detached_signatures(smartlist_t *consensuses);
-void ns_detached_signatures_free(ns_detached_signatures_t *s);
+void ns_detached_signatures_free_(ns_detached_signatures_t *s);
+#define ns_detached_signatures_free(s) \
+ FREE_AND_NULL(ns_detached_signatures_t, ns_detached_signatures_free_, (s))
/* cert manipulation */
authority_cert_t *authority_cert_dup(authority_cert_t *cert);
diff --git a/src/or/dns.c b/src/or/dns.c
index 4194a29a6b..1f00fe5b4d 100644
--- a/src/or/dns.c
+++ b/src/or/dns.c
@@ -457,7 +457,7 @@ purge_expired_resolves(time_t now)
if (!pendconn->base_.marked_for_close) {
connection_edge_end(pendconn, END_STREAM_REASON_TIMEOUT);
circuit_detach_stream(circuit_get_by_edge_conn(pendconn), pendconn);
- connection_free(TO_CONN(pendconn));
+ connection_free_(TO_CONN(pendconn));
}
tor_free(pend);
}
@@ -670,7 +670,7 @@ dns_resolve(edge_connection_t *exitconn)
/* If we made the connection pending, then we freed it already in
* dns_cancel_pending_resolve(). If we marked it for close, it'll
* get freed from the main loop. Otherwise, can free it now. */
- connection_free(TO_CONN(exitconn));
+ connection_free_(TO_CONN(exitconn));
}
break;
default:
@@ -1101,7 +1101,7 @@ dns_cancel_pending_resolve,(const char *address))
if (circ)
circuit_detach_stream(circ, pendconn);
if (!pendconn->base_.marked_for_close)
- connection_free(TO_CONN(pendconn));
+ connection_free_(TO_CONN(pendconn));
resolve->pending_connections = pend->next;
tor_free(pend);
}
@@ -1230,7 +1230,7 @@ inform_pending_connections(cached_resolve_t *resolve)
/* This detach must happen after we send the resolved cell. */
circuit_detach_stream(circuit_get_by_edge_conn(pendconn), pendconn);
}
- connection_free(TO_CONN(pendconn));
+ connection_free_(TO_CONN(pendconn));
} else {
circuit_t *circ;
if (pendconn->base_.purpose == EXIT_PURPOSE_CONNECT) {
@@ -1259,7 +1259,7 @@ inform_pending_connections(cached_resolve_t *resolve)
circ = circuit_get_by_edge_conn(pendconn);
tor_assert(circ);
circuit_detach_stream(circ, pendconn);
- connection_free(TO_CONN(pendconn));
+ connection_free_(TO_CONN(pendconn));
}
}
resolve->pending_connections = pend->next;
@@ -1578,10 +1578,11 @@ evdns_callback(int result, char type, int count, int ttl, void *addresses,
escaped_safe_str(hostname));
tor_free(escaped_address);
} else if (count) {
- log_warn(LD_EXIT, "eventdns returned only non-IPv4 answers for %s.",
+ log_info(LD_EXIT, "eventdns returned only unrecognized answer types "
+ " for %s.",
escaped_safe_str(string_address));
} else {
- log_warn(LD_BUG, "eventdns returned no addresses or error for %s!",
+ log_info(LD_EXIT, "eventdns returned no addresses or error for %s.",
escaped_safe_str(string_address));
}
}
@@ -1665,7 +1666,7 @@ launch_resolve,(cached_resolve_t *resolve))
tor_addr_t a;
int r;
- if (get_options()->DisableNetwork)
+ if (net_is_disabled())
return -1;
/* What? Nameservers not configured? Sounds like a bug. */
@@ -1900,7 +1901,7 @@ launch_test_addresses(evutil_socket_t fd, short event, void *args)
(void)event;
(void)args;
- if (options->DisableNetwork)
+ if (net_is_disabled())
return;
log_info(LD_EXIT, "Launching checks to see whether our nameservers like to "
diff --git a/src/or/dnsserv.c b/src/or/dnsserv.c
index d254717a54..9385561d99 100644
--- a/src/or/dnsserv.c
+++ b/src/or/dnsserv.c
@@ -172,7 +172,7 @@ evdns_server_callback(struct evdns_server_request *req, void *data_)
if (connection_add(ENTRY_TO_CONN(entry_conn)) < 0) {
log_warn(LD_APP, "Couldn't register dummy connection for DNS request");
evdns_server_request_respond(req, DNS_ERR_SERVERFAILED);
- connection_free(ENTRY_TO_CONN(entry_conn));
+ connection_free_(ENTRY_TO_CONN(entry_conn));
return;
}
@@ -249,7 +249,7 @@ dnsserv_launch_request(const char *name, int reverse,
if (connection_add(TO_CONN(conn))<0) {
log_warn(LD_APP, "Couldn't register dummy connection for RESOLVE request");
- connection_free(TO_CONN(conn));
+ connection_free_(TO_CONN(conn));
return -1;
}
diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c
index 76a8f591b9..cbdb36aa43 100644
--- a/src/or/entrynodes.c
+++ b/src/or/entrynodes.c
@@ -740,7 +740,8 @@ node_is_possible_guard(const node_t *node)
node->is_stable &&
node->is_fast &&
node->is_valid &&
- node_is_dir(node));
+ node_is_dir(node) &&
+ !router_digest_is_me(node->identity));
}
/**
@@ -966,7 +967,7 @@ entry_guard_learned_bridge_identity(const tor_addr_port_t *addrport,
* violate it.
*/
STATIC int
-num_reachable_filtered_guards(guard_selection_t *gs,
+num_reachable_filtered_guards(const guard_selection_t *gs,
const entry_guard_restriction_t *rst)
{
int n_reachable_filtered_guards = 0;
@@ -1460,6 +1461,94 @@ guard_in_node_family(const entry_guard_t *guard, const node_t *node)
}
}
+/* Allocate and return a new exit guard restriction (where <b>exit_id</b> is of
+ * size DIGEST_LEN) */
+STATIC entry_guard_restriction_t *
+guard_create_exit_restriction(const uint8_t *exit_id)
+{
+ entry_guard_restriction_t *rst = NULL;
+ rst = tor_malloc_zero(sizeof(entry_guard_restriction_t));
+ rst->type = RST_EXIT_NODE;
+ memcpy(rst->exclude_id, exit_id, DIGEST_LEN);
+ return rst;
+}
+
+/** If we have fewer than this many possible usable guards, don't set
+ * MD-availability-based restrictions: we might blacklist all of them. */
+#define MIN_GUARDS_FOR_MD_RESTRICTION 10
+
+/** Return true if we should set md dirserver restrictions. We might not want
+ * to set those if our guard options are too restricted, since we don't want
+ * to blacklist all of them. */
+static int
+should_set_md_dirserver_restriction(void)
+{
+ const guard_selection_t *gs = get_guard_selection_info();
+ int num_usable_guards = num_reachable_filtered_guards(gs, NULL);
+
+ /* Don't set restriction if too few reachable filtered guards. */
+ if (num_usable_guards < MIN_GUARDS_FOR_MD_RESTRICTION) {
+ log_info(LD_GUARD, "Not setting md restriction: only %d"
+ " usable guards.", num_usable_guards);
+ return 0;
+ }
+
+ /* We have enough usable guards: set MD restriction */
+ return 1;
+}
+
+/** Allocate and return an outdated md guard restriction. Return NULL if no
+ * such restriction is needed. */
+STATIC entry_guard_restriction_t *
+guard_create_dirserver_md_restriction(void)
+{
+ entry_guard_restriction_t *rst = NULL;
+
+ if (!should_set_md_dirserver_restriction()) {
+ log_debug(LD_GUARD, "Not setting md restriction: too few "
+ "filtered guards.");
+ return NULL;
+ }
+
+ rst = tor_malloc_zero(sizeof(entry_guard_restriction_t));
+ rst->type = RST_OUTDATED_MD_DIRSERVER;
+
+ return rst;
+}
+
+/* Return True if <b>guard</b> obeys the exit restriction <b>rst</b>. */
+static int
+guard_obeys_exit_restriction(const entry_guard_t *guard,
+ const entry_guard_restriction_t *rst)
+{
+ tor_assert(rst->type == RST_EXIT_NODE);
+
+ // Exclude the exit ID and all of its family.
+ const node_t *node = node_get_by_id((const char*)rst->exclude_id);
+ if (node && guard_in_node_family(guard, node))
+ return 0;
+
+ return tor_memneq(guard->identity, rst->exclude_id, DIGEST_LEN);
+}
+
+/** Return True if <b>guard</b> should be used as a dirserver for fetching
+ * microdescriptors. */
+static int
+guard_obeys_md_dirserver_restriction(const entry_guard_t *guard)
+{
+ /* If this guard is an outdated dirserver, don't use it. */
+ if (microdesc_relay_is_outdated_dirserver(guard->identity)) {
+ log_info(LD_GENERAL, "Skipping %s dirserver: outdated",
+ hex_str(guard->identity, DIGEST_LEN));
+ return 0;
+ }
+
+ log_debug(LD_GENERAL, "%s dirserver obeys md restrictions",
+ hex_str(guard->identity, DIGEST_LEN));
+
+ return 1;
+}
+
/**
* Return true iff <b>guard</b> obeys the restrictions defined in <b>rst</b>.
* (If <b>rst</b> is NULL, there are no restrictions.)
@@ -1472,13 +1561,14 @@ entry_guard_obeys_restriction(const entry_guard_t *guard,
if (! rst)
return 1; // No restriction? No problem.
- // Only one kind of restriction exists right now: excluding an exit
- // ID and all of its family.
- const node_t *node = node_get_by_id((const char*)rst->exclude_id);
- if (node && guard_in_node_family(guard, node))
- return 0;
+ if (rst->type == RST_EXIT_NODE) {
+ return guard_obeys_exit_restriction(guard, rst);
+ } else if (rst->type == RST_OUTDATED_MD_DIRSERVER) {
+ return guard_obeys_md_dirserver_restriction(guard);
+ }
- return tor_memneq(guard->identity, rst->exclude_id, DIGEST_LEN);
+ tor_assert_nonfatal_unreached();
+ return 0;
}
/**
@@ -2105,8 +2195,8 @@ entry_guard_has_higher_priority(entry_guard_t *a, entry_guard_t *b)
}
/** Release all storage held in <b>restriction</b> */
-static void
-entry_guard_restriction_free(entry_guard_restriction_t *rst)
+STATIC void
+entry_guard_restriction_free_(entry_guard_restriction_t *rst)
{
tor_free(rst);
}
@@ -2115,7 +2205,7 @@ entry_guard_restriction_free(entry_guard_restriction_t *rst)
* Release all storage held in <b>state</b>.
*/
void
-circuit_guard_state_free(circuit_guard_state_t *state)
+circuit_guard_state_free_(circuit_guard_state_t *state)
{
if (!state)
return;
@@ -3018,7 +3108,7 @@ get_guard_state_for_bridge_desc_fetch(const char *digest)
/** Release all storage held by <b>e</b>. */
STATIC void
-entry_guard_free(entry_guard_t *e)
+entry_guard_free_(entry_guard_t *e)
{
if (!e)
return;
@@ -3358,8 +3448,8 @@ guards_choose_guard(cpath_build_state_t *state,
/* We're building to a targeted exit node, so that node can't be
* chosen as our guard for this circuit. Remember that fact in a
* restriction. */
- rst = tor_malloc_zero(sizeof(entry_guard_restriction_t));
- memcpy(rst->exclude_id, exit_id, DIGEST_LEN);
+ rst = guard_create_exit_restriction(exit_id);
+ tor_assert(rst);
}
if (entry_guard_pick_for_circuit(get_guard_selection_info(),
GUARD_USAGE_TRAFFIC,
@@ -3411,12 +3501,20 @@ remove_all_entry_guards(void)
/** Helper: pick a directory guard, with whatever algorithm is used. */
const node_t *
-guards_choose_dirguard(circuit_guard_state_t **guard_state_out)
+guards_choose_dirguard(uint8_t dir_purpose,
+ circuit_guard_state_t **guard_state_out)
{
const node_t *r = NULL;
+ entry_guard_restriction_t *rst = NULL;
+
+ /* If we are fetching microdescs, don't query outdated dirservers. */
+ if (dir_purpose == DIR_PURPOSE_FETCH_MICRODESC) {
+ rst = guard_create_dirserver_md_restriction();
+ }
+
if (entry_guard_pick_for_circuit(get_guard_selection_info(),
GUARD_USAGE_DIRGUARD,
- NULL,
+ rst,
&r,
guard_state_out) < 0) {
tor_assert(r == NULL);
@@ -3503,7 +3601,7 @@ entry_guards_get_err_str_if_dir_info_missing(int using_mds,
/** Free one guard selection context */
STATIC void
-guard_selection_free(guard_selection_t *gs)
+guard_selection_free_(guard_selection_t *gs)
{
if (!gs) return;
diff --git a/src/or/entrynodes.h b/src/or/entrynodes.h
index 86f0517df2..21ba706c5b 100644
--- a/src/or/entrynodes.h
+++ b/src/or/entrynodes.h
@@ -272,22 +272,28 @@ struct guard_selection_s {
struct entry_guard_handle_t;
+/** Types of restrictions we impose when picking guard nodes */
+typedef enum guard_restriction_type_t {
+ /* Don't pick the same guard node as our exit node (or its family) */
+ RST_EXIT_NODE = 0,
+ /* Don't pick dirguards that have previously shown to be outdated */
+ RST_OUTDATED_MD_DIRSERVER = 1
+} guard_restriction_type_t;
+
/**
* A restriction to remember which entry guards are off-limits for a given
* circuit.
*
- * Right now, we only use restrictions to block a single guard and its family
- * from being selected; this mechanism is designed to be more extensible in
- * the future, however.
- *
* Note: This mechanism is NOT for recording which guards are never to be
* used: only which guards cannot be used on <em>one particular circuit</em>.
*/
struct entry_guard_restriction_t {
- /**
- * The guard's RSA identity digest must not equal this; and it must not
- * be in the same family as any node with this digest.
- */
+ /* What type of restriction are we imposing? */
+ guard_restriction_type_t type;
+
+ /* In case of restriction type RST_EXIT_NODE, the guard's RSA identity
+ * digest must not equal this; and it must not be in the same family as any
+ * node with this digest. */
uint8_t exclude_id[DIGEST_LEN];
};
@@ -316,7 +322,8 @@ struct circuit_guard_state_t {
int guards_update_all(void);
const node_t *guards_choose_guard(cpath_build_state_t *state,
circuit_guard_state_t **guard_state_out);
-const node_t *guards_choose_dirguard(circuit_guard_state_t **guard_state_out);
+const node_t *guards_choose_dirguard(uint8_t dir_purpose,
+ circuit_guard_state_t **guard_state_out);
#if 1
/* XXXX NM I would prefer that all of this stuff be private to
@@ -349,7 +356,10 @@ typedef enum {
GUARD_USAGE_DIRGUARD = 1
} guard_usage_t;
-void circuit_guard_state_free(circuit_guard_state_t *state);
+#define circuit_guard_state_free(val) \
+ FREE_AND_NULL(circuit_guard_state_t, circuit_guard_state_free_, (val))
+
+void circuit_guard_state_free_(circuit_guard_state_t *state);
int entry_guard_pick_for_circuit(guard_selection_t *gs,
guard_usage_t usage,
entry_guard_restriction_t *rst,
@@ -469,6 +479,9 @@ STATIC double get_meaningful_restriction_threshold(void);
STATIC double get_extreme_restriction_threshold(void);
HANDLE_DECL(entry_guard, entry_guard_t, STATIC)
+#define entry_guard_handle_free(h) \
+ FREE_AND_NULL(entry_guard_handle_t, entry_guard_handle_free_, (h))
+
STATIC guard_selection_type_t guard_selection_infer_type(
guard_selection_type_t type_in,
const char *name);
@@ -476,7 +489,9 @@ STATIC guard_selection_t *guard_selection_new(const char *name,
guard_selection_type_t type);
STATIC guard_selection_t *get_guard_selection_by_name(
const char *name, guard_selection_type_t type, int create_if_absent);
-STATIC void guard_selection_free(guard_selection_t *gs);
+STATIC void guard_selection_free_(guard_selection_t *gs);
+#define guard_selection_free(gs) \
+ FREE_AND_NULL(guard_selection_t, guard_selection_free_, (gs))
MOCK_DECL(STATIC int, entry_guard_is_listed,
(guard_selection_t *gs, const entry_guard_t *guard));
STATIC const char *choose_guard_selection(const or_options_t *options,
@@ -497,7 +512,9 @@ STATIC entry_guard_t *entry_guard_add_to_sample(guard_selection_t *gs,
STATIC entry_guard_t *entry_guards_expand_sample(guard_selection_t *gs);
STATIC char *entry_guard_encode_for_state(entry_guard_t *guard);
STATIC entry_guard_t *entry_guard_parse_from_state(const char *s);
-STATIC void entry_guard_free(entry_guard_t *e);
+#define entry_guard_free(e) \
+ FREE_AND_NULL(entry_guard_t, entry_guard_free_, (e))
+STATIC void entry_guard_free_(entry_guard_t *e);
STATIC void entry_guards_update_filtered_sets(guard_selection_t *gs);
STATIC int entry_guards_all_primary_guards_are_down(guard_selection_t *gs);
/**
@@ -518,7 +535,7 @@ STATIC void entry_guard_consider_retry(entry_guard_t *guard);
STATIC void make_guard_confirmed(guard_selection_t *gs, entry_guard_t *guard);
STATIC void entry_guards_update_confirmed(guard_selection_t *gs);
STATIC void entry_guards_update_primary(guard_selection_t *gs);
-STATIC int num_reachable_filtered_guards(guard_selection_t *gs,
+STATIC int num_reachable_filtered_guards(const guard_selection_t *gs,
const entry_guard_restriction_t *rst);
STATIC void sampled_guards_update_from_consensus(guard_selection_t *gs);
/**
@@ -554,6 +571,17 @@ STATIC unsigned entry_guards_note_guard_success(guard_selection_t *gs,
unsigned old_state);
STATIC int entry_guard_has_higher_priority(entry_guard_t *a, entry_guard_t *b);
STATIC char *getinfo_helper_format_single_entry_guard(const entry_guard_t *e);
+
+STATIC entry_guard_restriction_t *guard_create_exit_restriction(
+ const uint8_t *exit_id);
+
+STATIC entry_guard_restriction_t *guard_create_dirserver_md_restriction(void);
+
+STATIC void entry_guard_restriction_free_(entry_guard_restriction_t *rst);
+#define entry_guard_restriction_free(rst) \
+ FREE_AND_NULL(entry_guard_restriction_t, \
+ entry_guard_restriction_free_, (rst))
+
#endif /* defined(ENTRYNODES_PRIVATE) */
void remove_all_entry_guards_for_guard_selection(guard_selection_t *gs);
diff --git a/src/or/ext_orport.c b/src/or/ext_orport.c
index 28377a3f36..16a250fa58 100644
--- a/src/or/ext_orport.c
+++ b/src/or/ext_orport.c
@@ -40,7 +40,7 @@ ext_or_cmd_new(uint16_t len)
/** Deallocate the Extended ORPort message in <b>cmd</b>. */
void
-ext_or_cmd_free(ext_or_cmd_t *cmd)
+ext_or_cmd_free_(ext_or_cmd_t *cmd)
{
tor_free(cmd);
}
diff --git a/src/or/ext_orport.h b/src/or/ext_orport.h
index af2b97e77c..09acbc407e 100644
--- a/src/or/ext_orport.h
+++ b/src/or/ext_orport.h
@@ -10,7 +10,11 @@
int connection_ext_or_start_auth(or_connection_t *or_conn);
ext_or_cmd_t *ext_or_cmd_new(uint16_t len);
-void ext_or_cmd_free(ext_or_cmd_t *cmd);
+
+#define ext_or_cmd_free(cmd) \
+ FREE_AND_NULL(ext_or_cmd_t, ext_or_cmd_free_, (cmd))
+
+void ext_or_cmd_free_(ext_or_cmd_t *cmd);
void connection_or_set_ext_or_identifier(or_connection_t *conn);
void connection_or_remove_from_ext_or_id_map(or_connection_t *conn);
void connection_or_clear_ext_or_id_map(void);
diff --git a/src/or/fp_pair.c b/src/or/fp_pair.c
index f730106d06..c938e76678 100644
--- a/src/or/fp_pair.c
+++ b/src/or/fp_pair.c
@@ -196,7 +196,7 @@ fp_pair_map_remove(fp_pair_map_t *map, const fp_pair_t *key)
*/
void
-fp_pair_map_free(fp_pair_map_t *map, void (*free_val)(void*))
+fp_pair_map_free_(fp_pair_map_t *map, void (*free_val)(void*))
{
fp_pair_map_entry_t **ent, **next, *this;
diff --git a/src/or/fp_pair.h b/src/or/fp_pair.h
index f7c060b459..4498a16101 100644
--- a/src/or/fp_pair.h
+++ b/src/or/fp_pair.h
@@ -26,7 +26,12 @@ void * fp_pair_map_get(const fp_pair_map_t *map, const fp_pair_t *key);
void * fp_pair_map_get_by_digests(const fp_pair_map_t *map,
const char *first, const char *second);
void * fp_pair_map_remove(fp_pair_map_t *map, const fp_pair_t *key);
-void fp_pair_map_free(fp_pair_map_t *map, void (*free_val)(void*));
+void fp_pair_map_free_(fp_pair_map_t *map, void (*free_val)(void*));
+#define fp_pair_map_free(map, free_val) do { \
+ fp_pair_map_free_((map), (free_val)); \
+ (map) = NULL; \
+ } while (0)
+
int fp_pair_map_isempty(const fp_pair_map_t *map);
int fp_pair_map_size(const fp_pair_map_t *map);
fp_pair_map_iter_t * fp_pair_map_iter_init(fp_pair_map_t *map);
diff --git a/src/or/geoip.c b/src/or/geoip.c
index c976b8d276..d7411e6aaa 100644
--- a/src/or/geoip.c
+++ b/src/or/geoip.c
@@ -527,9 +527,12 @@ HT_PROTOTYPE(clientmap, clientmap_entry_t, node, clientmap_entry_hash,
HT_GENERATE2(clientmap, clientmap_entry_t, node, clientmap_entry_hash,
clientmap_entries_eq, 0.6, tor_reallocarray_, tor_free_)
+#define clientmap_entry_free(ent) \
+ FREE_AND_NULL(clientmap_entry_t, clientmap_entry_free_, ent)
+
/** Free all storage held by <b>ent</b>. */
static void
-clientmap_entry_free(clientmap_entry_t *ent)
+clientmap_entry_free_(clientmap_entry_t *ent)
{
if (!ent)
return;
diff --git a/src/or/git_revision.h b/src/or/git_revision.h
index 1ceaeedf16..5613cb4335 100644
--- a/src/or/git_revision.h
+++ b/src/or/git_revision.h
@@ -8,5 +8,5 @@
extern const char tor_git_revision[];
-#endif
+#endif /* !defined(TOR_GIT_REVISION_H) */
diff --git a/src/or/hs_cache.c b/src/or/hs_cache.c
index 3ebe13fb4d..1a8fdbd03b 100644
--- a/src/or/hs_cache.c
+++ b/src/or/hs_cache.c
@@ -52,9 +52,12 @@ lookup_v3_desc_as_dir(const uint8_t *key)
return digest256map_get(hs_cache_v3_dir, key);
}
+#define cache_dir_desc_free(val) \
+ FREE_AND_NULL(hs_cache_dir_descriptor_t, cache_dir_desc_free_, (val))
+
/* Free a directory descriptor object. */
static void
-cache_dir_desc_free(hs_cache_dir_descriptor_t *desc)
+cache_dir_desc_free_(hs_cache_dir_descriptor_t *desc)
{
if (desc == NULL) {
return;
@@ -67,10 +70,9 @@ cache_dir_desc_free(hs_cache_dir_descriptor_t *desc)
/* Helper function: Use by the free all function using the digest256map
* interface to cache entries. */
static void
-cache_dir_desc_free_(void *ptr)
+cache_dir_desc_free_void(void *ptr)
{
- hs_cache_dir_descriptor_t *desc = ptr;
- cache_dir_desc_free(desc);
+ cache_dir_desc_free_(ptr);
}
/* Create a new directory cache descriptor object from a encoded descriptor.
@@ -417,9 +419,12 @@ cache_client_desc_new(const char *desc_str,
return client_desc;
}
+#define cache_client_desc_free(val) \
+ FREE_AND_NULL(hs_cache_client_descriptor_t, cache_client_desc_free_, (val))
+
/** Free memory allocated by <b>desc</b>. */
static void
-cache_client_desc_free(hs_cache_client_descriptor_t *desc)
+cache_client_desc_free_(hs_cache_client_descriptor_t *desc)
{
if (desc == NULL) {
return;
@@ -433,7 +438,7 @@ cache_client_desc_free(hs_cache_client_descriptor_t *desc)
/** Helper function: Use by the free all function to clear the client cache */
static void
-cache_client_desc_free_(void *ptr)
+cache_client_desc_free_void(void *ptr)
{
hs_cache_client_descriptor_t *desc = ptr;
cache_client_desc_free(desc);
@@ -448,18 +453,21 @@ cache_intro_state_new(void)
return state;
}
+#define cache_intro_state_free(val) \
+ FREE_AND_NULL(hs_cache_intro_state_t, cache_intro_state_free_, (val))
+
/* Free an hs_cache_intro_state_t object. */
static void
-cache_intro_state_free(hs_cache_intro_state_t *state)
+cache_intro_state_free_(hs_cache_intro_state_t *state)
{
tor_free(state);
}
/* Helper function: use by the free all function. */
static void
-cache_intro_state_free_(void *state)
+cache_intro_state_free_void(void *state)
{
- cache_intro_state_free(state);
+ cache_intro_state_free_(state);
}
/* Return a newly allocated and initialized hs_cache_client_intro_state_t
@@ -472,22 +480,26 @@ cache_client_intro_state_new(void)
return cache;
}
+#define cache_client_intro_state_free(val) \
+ FREE_AND_NULL(hs_cache_client_intro_state_t, \
+ cache_client_intro_state_free_, (val))
+
/* Free a cache client intro state object. */
static void
-cache_client_intro_state_free(hs_cache_client_intro_state_t *cache)
+cache_client_intro_state_free_(hs_cache_client_intro_state_t *cache)
{
if (cache == NULL) {
return;
}
- digest256map_free(cache->intro_points, cache_intro_state_free_);
+ digest256map_free(cache->intro_points, cache_intro_state_free_void);
tor_free(cache);
}
/* Helper function: use by the free all function. */
static void
-cache_client_intro_state_free_(void *entry)
+cache_client_intro_state_free_void(void *entry)
{
- cache_client_intro_state_free(entry);
+ cache_client_intro_state_free_(entry);
}
/* For the given service identity key service_pk and an introduction
@@ -706,6 +718,24 @@ cache_clean_v3_as_client(time_t now)
}
/** Public API: Given the HS ed25519 identity public key in <b>key</b>, return
+ * its HS encoded descriptor if it's stored in our cache, or NULL if not. */
+const char *
+hs_cache_lookup_encoded_as_client(const ed25519_public_key_t *key)
+{
+ hs_cache_client_descriptor_t *cached_desc = NULL;
+
+ tor_assert(key);
+
+ cached_desc = lookup_v3_desc_as_client(key->pubkey);
+ if (cached_desc) {
+ tor_assert(cached_desc->encoded_desc);
+ return cached_desc->encoded_desc;
+ }
+
+ return NULL;
+}
+
+/** Public API: Given the HS ed25519 identity public key in <b>key</b>, return
* its HS descriptor if it's stored in our cache, or NULL if not. */
const hs_descriptor_t *
hs_cache_lookup_as_client(const ed25519_public_key_t *key)
@@ -933,14 +963,14 @@ hs_cache_init(void)
void
hs_cache_free_all(void)
{
- digest256map_free(hs_cache_v3_dir, cache_dir_desc_free_);
+ digest256map_free(hs_cache_v3_dir, cache_dir_desc_free_void);
hs_cache_v3_dir = NULL;
- digest256map_free(hs_cache_v3_client, cache_client_desc_free_);
+ digest256map_free(hs_cache_v3_client, cache_client_desc_free_void);
hs_cache_v3_client = NULL;
digest256map_free(hs_cache_client_intro_state,
- cache_client_intro_state_free_);
+ cache_client_intro_state_free_void);
hs_cache_client_intro_state = NULL;
}
diff --git a/src/or/hs_cache.h b/src/or/hs_cache.h
index 2dcc518a71..a141634cc4 100644
--- a/src/or/hs_cache.h
+++ b/src/or/hs_cache.h
@@ -81,6 +81,8 @@ int hs_cache_lookup_as_dir(uint32_t version, const char *query,
const hs_descriptor_t *
hs_cache_lookup_as_client(const ed25519_public_key_t *key);
+const char *
+hs_cache_lookup_encoded_as_client(const ed25519_public_key_t *key);
int hs_cache_store_as_client(const char *desc_str,
const ed25519_public_key_t *identity_pk);
void hs_cache_clean_as_client(time_t now);
diff --git a/src/or/hs_circuit.c b/src/or/hs_circuit.c
index ee952f4d68..a232a40c80 100644
--- a/src/or/hs_circuit.c
+++ b/src/or/hs_circuit.c
@@ -13,6 +13,7 @@
#include "circuitlist.h"
#include "circuituse.h"
#include "config.h"
+#include "nodelist.h"
#include "policies.h"
#include "relay.h"
#include "rendservice.h"
@@ -553,76 +554,99 @@ retry_service_rendezvous_point(const origin_circuit_t *circ)
return;
}
-/* Using an extend info object ei, set all possible link specifiers in lspecs.
- * legacy ID is mandatory thus MUST be present in ei. If IPv4 is not present,
- * logs a BUG() warning, and returns an empty smartlist. Clients never make
- * direct connections to rendezvous points, so they should always have an
- * IPv4 address in ei. */
+/* Add all possible link specifiers in node to lspecs.
+ * legacy ID is mandatory thus MUST be present in node. If the primary address
+ * is not IPv4, log a BUG() warning, and return an empty smartlist.
+ * Includes ed25519 id and IPv6 link specifiers if present in the node. */
static void
-get_lspecs_from_extend_info(const extend_info_t *ei, smartlist_t *lspecs)
+get_lspecs_from_node(const node_t *node, smartlist_t *lspecs)
{
link_specifier_t *ls;
+ tor_addr_port_t ap;
- tor_assert(ei);
+ tor_assert(node);
tor_assert(lspecs);
- /* We require IPv4, we will add IPv6 support in a later tor version */
- if (BUG(!tor_addr_is_v4(&ei->addr))) {
+ /* Get the relay's IPv4 address. */
+ node_get_prim_orport(node, &ap);
+
+ /* We expect the node's primary address to be a valid IPv4 address.
+ * This conforms to the protocol, which requires either an IPv4 or IPv6
+ * address (or both). */
+ if (BUG(!tor_addr_is_v4(&ap.addr)) ||
+ BUG(!tor_addr_port_is_valid_ap(&ap, 0))) {
return;
}
ls = link_specifier_new();
link_specifier_set_ls_type(ls, LS_IPV4);
- link_specifier_set_un_ipv4_addr(ls, tor_addr_to_ipv4h(&ei->addr));
- link_specifier_set_un_ipv4_port(ls, ei->port);
+ link_specifier_set_un_ipv4_addr(ls, tor_addr_to_ipv4h(&ap.addr));
+ link_specifier_set_un_ipv4_port(ls, ap.port);
/* Four bytes IPv4 and two bytes port. */
- link_specifier_set_ls_len(ls, sizeof(ei->addr.addr.in_addr) +
- sizeof(ei->port));
+ link_specifier_set_ls_len(ls, sizeof(ap.addr.addr.in_addr) +
+ sizeof(ap.port));
smartlist_add(lspecs, ls);
- /* Legacy ID is mandatory. */
+ /* Legacy ID is mandatory and will always be present in node. */
ls = link_specifier_new();
link_specifier_set_ls_type(ls, LS_LEGACY_ID);
- memcpy(link_specifier_getarray_un_legacy_id(ls), ei->identity_digest,
+ memcpy(link_specifier_getarray_un_legacy_id(ls), node->identity,
link_specifier_getlen_un_legacy_id(ls));
link_specifier_set_ls_len(ls, link_specifier_getlen_un_legacy_id(ls));
smartlist_add(lspecs, ls);
- /* ed25519 ID is only included if the extend_info has it. */
- if (!ed25519_public_key_is_zero(&ei->ed_identity)) {
+ /* ed25519 ID is only included if the node has it. */
+ if (!ed25519_public_key_is_zero(&node->ed25519_id)) {
ls = link_specifier_new();
link_specifier_set_ls_type(ls, LS_ED25519_ID);
- memcpy(link_specifier_getarray_un_ed25519_id(ls), &ei->ed_identity,
+ memcpy(link_specifier_getarray_un_ed25519_id(ls), &node->ed25519_id,
link_specifier_getlen_un_ed25519_id(ls));
link_specifier_set_ls_len(ls, link_specifier_getlen_un_ed25519_id(ls));
smartlist_add(lspecs, ls);
}
+
+ /* Check for IPv6. If so, include it as well. */
+ if (node_has_ipv6_orport(node)) {
+ ls = link_specifier_new();
+ node_get_pref_ipv6_orport(node, &ap);
+ link_specifier_set_ls_type(ls, LS_IPV6);
+ size_t addr_len = link_specifier_getlen_un_ipv6_addr(ls);
+ const uint8_t *in6_addr = tor_addr_to_in6_addr8(&ap.addr);
+ uint8_t *ipv6_array = link_specifier_getarray_un_ipv6_addr(ls);
+ memcpy(ipv6_array, in6_addr, addr_len);
+ link_specifier_set_un_ipv6_port(ls, ap.port);
+ /* Sixteen bytes IPv6 and two bytes port. */
+ link_specifier_set_ls_len(ls, addr_len + sizeof(ap.port));
+ smartlist_add(lspecs, ls);
+ }
}
-/* Using the given descriptor intro point ip, the extend information of the
- * rendezvous point rp_ei and the service's subcredential, populate the
+/* Using the given descriptor intro point ip, the node of the
+ * rendezvous point rp_node and the service's subcredential, populate the
* already allocated intro1_data object with the needed key material and link
* specifiers.
*
- * This can't fail but the ip MUST be a valid object containing the needed
- * keys and authentication method. */
+ * If rp_node has an invalid primary address, intro1_data->link_specifiers
+ * will be an empty list. Otherwise, this function can't fail. The ip
+ * MUST be a valid object containing the needed keys and authentication
+ * method. */
static void
setup_introduce1_data(const hs_desc_intro_point_t *ip,
- const extend_info_t *rp_ei,
+ const node_t *rp_node,
const uint8_t *subcredential,
hs_cell_introduce1_data_t *intro1_data)
{
smartlist_t *rp_lspecs;
tor_assert(ip);
- tor_assert(rp_ei);
+ tor_assert(rp_node);
tor_assert(subcredential);
tor_assert(intro1_data);
/* Build the link specifiers from the extend information of the rendezvous
* circuit that we've picked previously. */
rp_lspecs = smartlist_new();
- get_lspecs_from_extend_info(rp_ei, rp_lspecs);
+ get_lspecs_from_node(rp_node, rp_lspecs);
/* Populate the introduce1 data object. */
memset(intro1_data, 0, sizeof(hs_cell_introduce1_data_t));
@@ -633,7 +657,7 @@ setup_introduce1_data(const hs_desc_intro_point_t *ip,
intro1_data->auth_pk = &ip->auth_key_cert->signed_key;
intro1_data->enc_pk = &ip->enc_key;
intro1_data->subcredential = subcredential;
- intro1_data->onion_pk = &rp_ei->curve25519_onion_key;
+ intro1_data->onion_pk = node_get_curve25519_onion_key(rp_node);
intro1_data->link_specifiers = rp_lspecs;
}
@@ -1077,11 +1101,21 @@ hs_circ_send_introduce1(origin_circuit_t *intro_circ,
tor_assert(ip);
tor_assert(subcredential);
+ /* It is undefined behavior in hs_cell_introduce1_data_clear() if intro1_data
+ * has been declared on the stack but not initialized. Here, we set it to 0.
+ */
+ memset(&intro1_data, 0, sizeof(hs_cell_introduce1_data_t));
+
/* This takes various objects in order to populate the introduce1 data
* object which is used to build the content of the cell. */
- setup_introduce1_data(ip, rend_circ->build_state->chosen_exit,
- subcredential, &intro1_data);
- /* If we didn't get any link specifiers, it's because our extend info was
+ const node_t *exit_node = build_state_get_exit_node(rend_circ->build_state);
+ if (exit_node == NULL) {
+ log_info(LD_REND, "Unable to get rendezvous point for circuit %u. "
+ "Failing.", TO_CIRCUIT(intro_circ)->n_circ_id);
+ goto done;
+ }
+ setup_introduce1_data(ip, exit_node, subcredential, &intro1_data);
+ /* If we didn't get any link specifiers, it's because our node was
* bad. */
if (BUG(!intro1_data.link_specifiers) ||
!smartlist_len(intro1_data.link_specifiers)) {
diff --git a/src/or/hs_circuit.h b/src/or/hs_circuit.h
index 0a1186dbaa..b92fb4e494 100644
--- a/src/or/hs_circuit.h
+++ b/src/or/hs_circuit.h
@@ -67,7 +67,7 @@ create_rp_circuit_identifier(const hs_service_t *service,
const curve25519_public_key_t *server_pk,
const hs_ntor_rend_cell_keys_t *keys);
-#endif
+#endif /* defined(HS_CIRCUIT_PRIVATE) */
#endif /* !defined(TOR_HS_CIRCUIT_H) */
diff --git a/src/or/hs_circuitmap.c b/src/or/hs_circuitmap.c
index 97d6053e9b..e3d364d7cd 100644
--- a/src/or/hs_circuitmap.c
+++ b/src/or/hs_circuitmap.c
@@ -106,9 +106,12 @@ hs_token_new(hs_token_type_t type, size_t token_len,
return hs_token;
}
+#define hs_token_free(val) \
+ FREE_AND_NULL(hs_token_t, hs_token_free_, (val))
+
/** Free memory allocated by this <b>hs_token</b>. */
static void
-hs_token_free(hs_token_t *hs_token)
+hs_token_free_(hs_token_t *hs_token)
{
if (!hs_token) {
return;
diff --git a/src/or/hs_client.c b/src/or/hs_client.c
index 9ac653c721..666860155c 100644
--- a/src/or/hs_client.c
+++ b/src/or/hs_client.c
@@ -21,6 +21,7 @@
#include "config.h"
#include "directory.h"
#include "hs_client.h"
+#include "hs_control.h"
#include "router.h"
#include "routerset.h"
#include "circuitlist.h"
@@ -349,6 +350,10 @@ directory_launch_v3_desc_fetch(const ed25519_public_key_t *onion_identity_pk,
safe_str_client(base64_blinded_pubkey),
safe_str_client(routerstatus_describe(hsdir)));
+ /* Fire a REQUESTED event on the control port. */
+ hs_control_desc_event_requested(onion_identity_pk, base64_blinded_pubkey,
+ hsdir);
+
/* Cleanup memory. */
memwipe(&blinded_pubkey, 0, sizeof(blinded_pubkey));
memwipe(base64_blinded_pubkey, 0, sizeof(base64_blinded_pubkey));
diff --git a/src/or/hs_common.c b/src/or/hs_common.c
index f79aeb5981..fcc524ae1c 100644
--- a/src/or/hs_common.c
+++ b/src/or/hs_common.c
@@ -224,7 +224,7 @@ get_time_period_length(void)
return sr_state_get_protocol_run_duration() / 60;
}
- int32_t time_period_length = networkstatus_get_param(NULL, "hsdir-interval",
+ int32_t time_period_length = networkstatus_get_param(NULL, "hsdir_interval",
HS_TIME_PERIOD_LENGTH_DEFAULT,
HS_TIME_PERIOD_LENGTH_MIN,
HS_TIME_PERIOD_LENGTH_MAX);
@@ -329,7 +329,7 @@ rend_data_alloc(uint32_t version)
/** Free all storage associated with <b>data</b> */
void
-rend_data_free(rend_data_t *data)
+rend_data_free_(rend_data_t *data)
{
if (!data) {
return;
diff --git a/src/or/hs_common.h b/src/or/hs_common.h
index c95e59a6f8..40fa1bc466 100644
--- a/src/or/hs_common.h
+++ b/src/or/hs_common.h
@@ -130,6 +130,17 @@ typedef enum {
HS_AUTH_KEY_TYPE_ED25519 = 2,
} hs_auth_key_type_t;
+/* Return value when adding an ephemeral service through the ADD_ONION
+ * control port command. Both v2 and v3 share these. */
+typedef enum {
+ RSAE_BADAUTH = -5, /**< Invalid auth_type/auth_clients */
+ RSAE_BADVIRTPORT = -4, /**< Invalid VIRTPORT/TARGET(s) */
+ RSAE_ADDREXISTS = -3, /**< Onion address collision */
+ RSAE_BADPRIVKEY = -2, /**< Invalid public key */
+ RSAE_INTERNAL = -1, /**< Internal error */
+ RSAE_OKAY = 0 /**< Service added as expected */
+} hs_service_add_ephemeral_status_t;
+
/* Represents the mapping from a virtual port of a rendezvous service to a
* real port on some IP. */
typedef struct rend_service_port_config_t {
@@ -181,7 +192,9 @@ void hs_build_blinded_keypair(const ed25519_keypair_t *kp,
ed25519_keypair_t *kp_out);
int hs_service_requires_uptime_circ(const smartlist_t *ports);
-void rend_data_free(rend_data_t *data);
+void rend_data_free_(rend_data_t *data);
+#define rend_data_free(data) \
+ FREE_AND_NULL(rend_data_t, rend_data_free_, (data))
rend_data_t *rend_data_dup(const rend_data_t *data);
rend_data_t *rend_data_client_create(const char *onion_address,
const char *desc_id,
diff --git a/src/or/hs_control.c b/src/or/hs_control.c
new file mode 100644
index 0000000000..87b4e3fca8
--- /dev/null
+++ b/src/or/hs_control.c
@@ -0,0 +1,258 @@
+/* Copyright (c) 2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file hs_control.c
+ * \brief Contains control port event related code.
+ **/
+
+#include "or.h"
+#include "control.h"
+#include "hs_common.h"
+#include "hs_control.h"
+#include "hs_descriptor.h"
+#include "hs_service.h"
+#include "nodelist.h"
+
+/* Send on the control port the "HS_DESC REQUESTED [...]" event.
+ *
+ * The onion_pk is the onion service public key, base64_blinded_pk is the
+ * base64 encoded blinded key for the service and hsdir_rs is the routerstatus
+ * object of the HSDir that this request is for. */
+void
+hs_control_desc_event_requested(const ed25519_public_key_t *onion_pk,
+ const char *base64_blinded_pk,
+ const routerstatus_t *hsdir_rs)
+{
+ char onion_address[HS_SERVICE_ADDR_LEN_BASE32 + 1];
+ const uint8_t *hsdir_index;
+ const node_t *hsdir_node;
+
+ tor_assert(onion_pk);
+ tor_assert(base64_blinded_pk);
+ tor_assert(hsdir_rs);
+
+ hs_build_address(onion_pk, HS_VERSION_THREE, onion_address);
+
+ /* Get the node from the routerstatus object to get the HSDir index used for
+ * this request. We can't have a routerstatus entry without a node and we
+ * can't pick a node without an hsdir_index. */
+ hsdir_node = node_get_by_id(hsdir_rs->identity_digest);
+ tor_assert(hsdir_node);
+ tor_assert(hsdir_node->hsdir_index);
+ /* This is a fetch event. */
+ hsdir_index = hsdir_node->hsdir_index->fetch;
+
+ /* Trigger the event. */
+ control_event_hs_descriptor_requested(onion_address, REND_NO_AUTH,
+ hsdir_rs->identity_digest,
+ base64_blinded_pk,
+ hex_str((const char *) hsdir_index,
+ DIGEST256_LEN));
+ memwipe(onion_address, 0, sizeof(onion_address));
+}
+
+/* Send on the control port the "HS_DESC FAILED [...]" event.
+ *
+ * Using a directory connection identifier, the HSDir identity digest and a
+ * reason for the failure. None can be NULL. */
+void
+hs_control_desc_event_failed(const hs_ident_dir_conn_t *ident,
+ const char *hsdir_id_digest,
+ const char *reason)
+{
+ char onion_address[HS_SERVICE_ADDR_LEN_BASE32 + 1];
+ char base64_blinded_pk[ED25519_BASE64_LEN + 1];
+
+ tor_assert(ident);
+ tor_assert(hsdir_id_digest);
+ tor_assert(reason);
+
+ /* Build onion address and encoded blinded key. */
+ IF_BUG_ONCE(ed25519_public_to_base64(base64_blinded_pk,
+ &ident->blinded_pk) < 0) {
+ return;
+ }
+ hs_build_address(&ident->identity_pk, HS_VERSION_THREE, onion_address);
+
+ control_event_hsv3_descriptor_failed(onion_address, base64_blinded_pk,
+ hsdir_id_digest, reason);
+}
+
+/* Send on the control port the "HS_DESC RECEIVED [...]" event.
+ *
+ * Using a directory connection identifier and the HSDir identity digest.
+ * None can be NULL. */
+void
+hs_control_desc_event_received(const hs_ident_dir_conn_t *ident,
+ const char *hsdir_id_digest)
+{
+ char onion_address[HS_SERVICE_ADDR_LEN_BASE32 + 1];
+ char base64_blinded_pk[ED25519_BASE64_LEN + 1];
+
+ tor_assert(ident);
+ tor_assert(hsdir_id_digest);
+
+ /* Build onion address and encoded blinded key. */
+ IF_BUG_ONCE(ed25519_public_to_base64(base64_blinded_pk,
+ &ident->blinded_pk) < 0) {
+ return;
+ }
+ hs_build_address(&ident->identity_pk, HS_VERSION_THREE, onion_address);
+
+ control_event_hsv3_descriptor_received(onion_address, base64_blinded_pk,
+ hsdir_id_digest);
+}
+
+/* Send on the control port the "HS_DESC CREATED [...]" event.
+ *
+ * Using the onion address of the descriptor's service and the blinded public
+ * key of the descriptor as a descriptor ID. None can be NULL. */
+void
+hs_control_desc_event_created(const char *onion_address,
+ const ed25519_public_key_t *blinded_pk)
+{
+ char base64_blinded_pk[ED25519_BASE64_LEN + 1];
+
+ tor_assert(onion_address);
+ tor_assert(blinded_pk);
+
+ /* Build base64 encoded blinded key. */
+ IF_BUG_ONCE(ed25519_public_to_base64(base64_blinded_pk, blinded_pk) < 0) {
+ return;
+ }
+
+ /* Version 3 doesn't use the replica number in its descriptor ID computation
+ * so we pass negative value so the control port subsystem can ignore it. */
+ control_event_hs_descriptor_created(onion_address, base64_blinded_pk, -1);
+}
+
+/* Send on the control port the "HS_DESC UPLOAD [...]" event.
+ *
+ * Using the onion address of the descriptor's service, the HSDir identity
+ * digest, the blinded public key of the descriptor as a descriptor ID and the
+ * HSDir index for this particular request. None can be NULL. */
+void
+hs_control_desc_event_upload(const char *onion_address,
+ const char *hsdir_id_digest,
+ const ed25519_public_key_t *blinded_pk,
+ const uint8_t *hsdir_index)
+{
+ char base64_blinded_pk[ED25519_BASE64_LEN + 1];
+
+ tor_assert(onion_address);
+ tor_assert(hsdir_id_digest);
+ tor_assert(blinded_pk);
+ tor_assert(hsdir_index);
+
+ /* Build base64 encoded blinded key. */
+ IF_BUG_ONCE(ed25519_public_to_base64(base64_blinded_pk, blinded_pk) < 0) {
+ return;
+ }
+
+ control_event_hs_descriptor_upload(onion_address, hsdir_id_digest,
+ base64_blinded_pk,
+ hex_str((const char *) hsdir_index,
+ DIGEST256_LEN));
+}
+
+/* Send on the control port the "HS_DESC UPLOADED [...]" event.
+ *
+ * Using the directory connection identifier and the HSDir identity digest.
+ * None can be NULL. */
+void
+hs_control_desc_event_uploaded(const hs_ident_dir_conn_t *ident,
+ const char *hsdir_id_digest)
+{
+ char onion_address[HS_SERVICE_ADDR_LEN_BASE32 + 1];
+
+ tor_assert(ident);
+ tor_assert(hsdir_id_digest);
+
+ hs_build_address(&ident->identity_pk, HS_VERSION_THREE, onion_address);
+
+ control_event_hs_descriptor_uploaded(hsdir_id_digest, onion_address);
+}
+
+/* Send on the control port the "HS_DESC_CONTENT [...]" event.
+ *
+ * Using the directory connection identifier, the HSDir identity digest and
+ * the body of the descriptor (as it was received from the directory). None
+ * can be NULL. */
+void
+hs_control_desc_event_content(const hs_ident_dir_conn_t *ident,
+ const char *hsdir_id_digest,
+ const char *body)
+{
+ char onion_address[HS_SERVICE_ADDR_LEN_BASE32 + 1];
+ char base64_blinded_pk[ED25519_BASE64_LEN + 1];
+
+ tor_assert(ident);
+ tor_assert(hsdir_id_digest);
+
+ /* Build onion address and encoded blinded key. */
+ IF_BUG_ONCE(ed25519_public_to_base64(base64_blinded_pk,
+ &ident->blinded_pk) < 0) {
+ return;
+ }
+ hs_build_address(&ident->identity_pk, HS_VERSION_THREE, onion_address);
+
+ control_event_hs_descriptor_content(onion_address, base64_blinded_pk,
+ hsdir_id_digest, body);
+}
+
+/* Handle the "HSPOST [...]" command. The body is an encoded descriptor for
+ * the given onion_address. The descriptor will be uploaded to each directory
+ * in hsdirs_rs. If NULL, the responsible directories for the current time
+ * period will be selected.
+ *
+ * Return -1 on if the descriptor plaintext section is not decodable. Else, 0
+ * on success. */
+int
+hs_control_hspost_command(const char *body, const char *onion_address,
+ const smartlist_t *hsdirs_rs)
+{
+ int ret = -1;
+ ed25519_public_key_t identity_pk;
+ hs_desc_plaintext_data_t plaintext;
+ smartlist_t *hsdirs = NULL;
+
+ tor_assert(body);
+ tor_assert(onion_address);
+
+ /* This can't fail because we require the caller to pass us a valid onion
+ * address that has passed hs_address_is_valid(). */
+ if (BUG(hs_parse_address(onion_address, &identity_pk, NULL, NULL) < 0)) {
+ goto done; // LCOV_EXCL_LINE
+ }
+
+ /* Only decode the plaintext part which is what the directory will do to
+ * validate before caching. */
+ if (hs_desc_decode_plaintext(body, &plaintext) < 0) {
+ goto done;
+ }
+
+ /* No HSDir(s) given, we'll compute what the current ones should be. */
+ if (hsdirs_rs == NULL) {
+ hsdirs = smartlist_new();
+ hs_get_responsible_hsdirs(&plaintext.blinded_pubkey,
+ hs_get_time_period_num(0),
+ 0, /* Always the current descriptor which uses
+ * the first hsdir index. */
+ 0, /* It is for storing on a directory. */
+ hsdirs);
+ hsdirs_rs = hsdirs;
+ }
+
+ SMARTLIST_FOREACH_BEGIN(hsdirs_rs, const routerstatus_t *, rs) {
+ hs_service_upload_desc_to_dir(body, plaintext.version, &identity_pk,
+ &plaintext.blinded_pubkey, rs);
+ } SMARTLIST_FOREACH_END(rs);
+ ret = 0;
+
+ done:
+ /* We don't have ownership of the objects in this list. */
+ smartlist_free(hsdirs);
+ return ret;
+}
+
diff --git a/src/or/hs_control.h b/src/or/hs_control.h
new file mode 100644
index 0000000000..95c46e655e
--- /dev/null
+++ b/src/or/hs_control.h
@@ -0,0 +1,52 @@
+/* Copyright (c) 2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file hs_control.h
+ * \brief Header file containing control port event related code.
+ **/
+
+#ifndef TOR_HS_CONTROL_H
+#define TOR_HS_CONTROL_H
+
+#include "hs_ident.h"
+
+/* Event "HS_DESC REQUESTED [...]" */
+void hs_control_desc_event_requested(const ed25519_public_key_t *onion_pk,
+ const char *base64_blinded_pk,
+ const routerstatus_t *hsdir_rs);
+
+/* Event "HS_DESC FAILED [...]" */
+void hs_control_desc_event_failed(const hs_ident_dir_conn_t *ident,
+ const char *hsdir_id_digest,
+ const char *reason);
+
+/* Event "HS_DESC RECEIVED [...]" */
+void hs_control_desc_event_received(const hs_ident_dir_conn_t *ident,
+ const char *hsdir_id_digest);
+
+/* Event "HS_DESC CREATED [...]" */
+void hs_control_desc_event_created(const char *onion_address,
+ const ed25519_public_key_t *blinded_pk);
+
+/* Event "HS_DESC UPLOAD [...]" */
+void hs_control_desc_event_upload(const char *onion_address,
+ const char *hsdir_id_digest,
+ const ed25519_public_key_t *blinded_pk,
+ const uint8_t *hsdir_index);
+
+/* Event "HS_DESC UPLOADED [...]" */
+void hs_control_desc_event_uploaded(const hs_ident_dir_conn_t *ident,
+ const char *hsdir_id_digest);
+
+/* Event "HS_DESC_CONTENT [...]" */
+void hs_control_desc_event_content(const hs_ident_dir_conn_t *ident,
+ const char *hsdir_id_digest,
+ const char *body);
+
+/* Command "HSPOST [...]" */
+int hs_control_hspost_command(const char *body, const char *onion_address,
+ const smartlist_t *hsdirs_rs);
+
+#endif /* !defined(TOR_HS_CONTROL_H) */
+
diff --git a/src/or/hs_descriptor.c b/src/or/hs_descriptor.c
index 1708866944..789bc1d046 100644
--- a/src/or/hs_descriptor.c
+++ b/src/or/hs_descriptor.c
@@ -2367,7 +2367,7 @@ hs_desc_encode_descriptor,(const hs_descriptor_t *desc,
/* Free the descriptor plaintext data object. */
void
-hs_desc_plaintext_data_free(hs_desc_plaintext_data_t *desc)
+hs_desc_plaintext_data_free_(hs_desc_plaintext_data_t *desc)
{
desc_plaintext_data_free_contents(desc);
tor_free(desc);
@@ -2375,7 +2375,7 @@ hs_desc_plaintext_data_free(hs_desc_plaintext_data_t *desc)
/* Free the descriptor encrypted data object. */
void
-hs_desc_encrypted_data_free(hs_desc_encrypted_data_t *desc)
+hs_desc_encrypted_data_free_(hs_desc_encrypted_data_t *desc)
{
desc_encrypted_data_free_contents(desc);
tor_free(desc);
@@ -2383,7 +2383,7 @@ hs_desc_encrypted_data_free(hs_desc_encrypted_data_t *desc)
/* Free the given descriptor object. */
void
-hs_descriptor_free(hs_descriptor_t *desc)
+hs_descriptor_free_(hs_descriptor_t *desc)
{
if (!desc) {
return;
@@ -2448,7 +2448,7 @@ hs_desc_intro_point_new(void)
/* Free a descriptor intro point object. */
void
-hs_desc_intro_point_free(hs_desc_intro_point_t *ip)
+hs_desc_intro_point_free_(hs_desc_intro_point_t *ip)
{
if (ip == NULL) {
return;
@@ -2467,7 +2467,7 @@ hs_desc_intro_point_free(hs_desc_intro_point_t *ip)
/* Free the given descriptor link specifier. */
void
-hs_desc_link_specifier_free(hs_desc_link_specifier_t *ls)
+hs_desc_link_specifier_free_(hs_desc_link_specifier_t *ls)
{
if (ls == NULL) {
return;
diff --git a/src/or/hs_descriptor.h b/src/or/hs_descriptor.h
index 52bec8e244..09979410e1 100644
--- a/src/or/hs_descriptor.h
+++ b/src/or/hs_descriptor.h
@@ -208,11 +208,20 @@ hs_desc_is_supported_version(uint32_t version)
/* Public API. */
-void hs_descriptor_free(hs_descriptor_t *desc);
-void hs_desc_plaintext_data_free(hs_desc_plaintext_data_t *desc);
-void hs_desc_encrypted_data_free(hs_desc_encrypted_data_t *desc);
+void hs_descriptor_free_(hs_descriptor_t *desc);
+#define hs_descriptor_free(desc) \
+ FREE_AND_NULL(hs_descriptor_t, hs_descriptor_free_, (desc))
+void hs_desc_plaintext_data_free_(hs_desc_plaintext_data_t *desc);
+#define hs_desc_plaintext_data_free(desc) \
+ FREE_AND_NULL(hs_desc_plaintext_data_t, hs_desc_plaintext_data_free_, (desc))
+void hs_desc_encrypted_data_free_(hs_desc_encrypted_data_t *desc);
+#define hs_desc_encrypted_data_free(desc) \
+ FREE_AND_NULL(hs_desc_encrypted_data_t, hs_desc_encrypted_data_free_, (desc))
+
+void hs_desc_link_specifier_free_(hs_desc_link_specifier_t *ls);
+#define hs_desc_link_specifier_free(ls) \
+ FREE_AND_NULL(hs_desc_link_specifier_t, hs_desc_link_specifier_free_, (ls))
-void hs_desc_link_specifier_free(hs_desc_link_specifier_t *ls);
hs_desc_link_specifier_t *hs_desc_link_specifier_new(
const extend_info_t *info, uint8_t type);
void hs_descriptor_clear_intro_points(hs_descriptor_t *desc);
@@ -234,7 +243,9 @@ size_t hs_desc_obj_size(const hs_descriptor_t *data);
size_t hs_desc_plaintext_obj_size(const hs_desc_plaintext_data_t *data);
hs_desc_intro_point_t *hs_desc_intro_point_new(void);
-void hs_desc_intro_point_free(hs_desc_intro_point_t *ip);
+void hs_desc_intro_point_free_(hs_desc_intro_point_t *ip);
+#define hs_desc_intro_point_free(ip) \
+ FREE_AND_NULL(hs_desc_intro_point_t, hs_desc_intro_point_free_, (ip))
link_specifier_t *hs_desc_lspec_to_trunnel(
const hs_desc_link_specifier_t *spec);
diff --git a/src/or/hs_ident.c b/src/or/hs_ident.c
index b0e4e36a9b..0bce2f625b 100644
--- a/src/or/hs_ident.c
+++ b/src/or/hs_ident.c
@@ -25,7 +25,7 @@ hs_ident_circuit_new(const ed25519_public_key_t *identity_pk,
/* Free the given circuit identifier. */
void
-hs_ident_circuit_free(hs_ident_circuit_t *ident)
+hs_ident_circuit_free_(hs_ident_circuit_t *ident)
{
if (ident == NULL) {
return;
@@ -56,7 +56,7 @@ hs_ident_dir_conn_dup(const hs_ident_dir_conn_t *src)
/* Free the given directory connection identifier. */
void
-hs_ident_dir_conn_free(hs_ident_dir_conn_t *ident)
+hs_ident_dir_conn_free_(hs_ident_dir_conn_t *ident)
{
if (ident == NULL) {
return;
@@ -93,7 +93,7 @@ hs_ident_edge_conn_new(const ed25519_public_key_t *identity_pk)
/* Free the given edge connection identifier. */
void
-hs_ident_edge_conn_free(hs_ident_edge_conn_t *ident)
+hs_ident_edge_conn_free_(hs_ident_edge_conn_t *ident)
{
if (ident == NULL) {
return;
diff --git a/src/or/hs_ident.h b/src/or/hs_ident.h
index 03150d25ea..91ec389aa4 100644
--- a/src/or/hs_ident.h
+++ b/src/or/hs_ident.h
@@ -119,12 +119,16 @@ typedef struct hs_ident_edge_conn_t {
hs_ident_circuit_t *hs_ident_circuit_new(
const ed25519_public_key_t *identity_pk,
hs_ident_circuit_type_t circuit_type);
-void hs_ident_circuit_free(hs_ident_circuit_t *ident);
+void hs_ident_circuit_free_(hs_ident_circuit_t *ident);
+#define hs_ident_circuit_free(id) \
+ FREE_AND_NULL(hs_ident_circuit_t, hs_ident_circuit_free_, (id))
hs_ident_circuit_t *hs_ident_circuit_dup(const hs_ident_circuit_t *src);
/* Directory connection identifier API. */
hs_ident_dir_conn_t *hs_ident_dir_conn_dup(const hs_ident_dir_conn_t *src);
-void hs_ident_dir_conn_free(hs_ident_dir_conn_t *ident);
+void hs_ident_dir_conn_free_(hs_ident_dir_conn_t *ident);
+#define hs_ident_dir_conn_free(id) \
+ FREE_AND_NULL(hs_ident_dir_conn_t, hs_ident_dir_conn_free_, (id))
void hs_ident_dir_conn_init(const ed25519_public_key_t *identity_pk,
const ed25519_public_key_t *blinded_pk,
hs_ident_dir_conn_t *ident);
@@ -132,7 +136,9 @@ void hs_ident_dir_conn_init(const ed25519_public_key_t *identity_pk,
/* Edge connection identifier API. */
hs_ident_edge_conn_t *hs_ident_edge_conn_new(
const ed25519_public_key_t *identity_pk);
-void hs_ident_edge_conn_free(hs_ident_edge_conn_t *ident);
+void hs_ident_edge_conn_free_(hs_ident_edge_conn_t *ident);
+#define hs_ident_edge_conn_free(id) \
+ FREE_AND_NULL(hs_ident_edge_conn_t, hs_ident_edge_conn_free_, (id))
/* Validators */
int hs_ident_intro_circ_is_valid(const hs_ident_circuit_t *ident);
diff --git a/src/or/hs_service.c b/src/or/hs_service.c
index a2082b3914..4190f1a038 100644
--- a/src/or/hs_service.c
+++ b/src/or/hs_service.c
@@ -30,6 +30,7 @@
#include "hs_circuit.h"
#include "hs_common.h"
#include "hs_config.h"
+#include "hs_control.h"
#include "hs_circuit.h"
#include "hs_descriptor.h"
#include "hs_ident.h"
@@ -352,7 +353,7 @@ service_free_all(void)
/* Free a given service intro point object. */
STATIC void
-service_intro_point_free(hs_service_intro_point_t *ip)
+service_intro_point_free_(hs_service_intro_point_t *ip)
{
if (!ip) {
return;
@@ -368,9 +369,9 @@ service_intro_point_free(hs_service_intro_point_t *ip)
/* Helper: free an hs_service_intro_point_t object. This function is used by
* digest256map_free() which requires a void * pointer. */
static void
-service_intro_point_free_(void *obj)
+service_intro_point_free_void(void *obj)
{
- service_intro_point_free(obj);
+ service_intro_point_free_(obj);
}
/* Return a newly allocated service intro point and fully initialized from the
@@ -1027,7 +1028,7 @@ load_service_keys(hs_service_t *service)
/* Free a given service descriptor object and all key material is wiped. */
STATIC void
-service_descriptor_free(hs_service_descriptor_t *desc)
+service_descriptor_free_(hs_service_descriptor_t *desc)
{
if (!desc) {
return;
@@ -1036,7 +1037,7 @@ service_descriptor_free(hs_service_descriptor_t *desc)
memwipe(&desc->signing_kp, 0, sizeof(desc->signing_kp));
memwipe(&desc->blinded_kp, 0, sizeof(desc->blinded_kp));
/* Cleanup all intro points. */
- digest256map_free(desc->intro_points.map, service_intro_point_free_);
+ digest256map_free(desc->intro_points.map, service_intro_point_free_void);
digestmap_free(desc->intro_points.failed_id, tor_free_);
if (desc->previous_hsdirs) {
SMARTLIST_FOREACH(desc->previous_hsdirs, char *, s, tor_free(s));
@@ -1431,6 +1432,9 @@ build_service_descriptor(hs_service_t *service, time_t now,
/* Assign newly built descriptor to the next slot. */
*desc_out = desc;
+ /* Fire a CREATED control port event. */
+ hs_control_desc_event_created(service->onion_address,
+ &desc->blinded_kp.pubkey);
return;
err:
@@ -1572,7 +1576,7 @@ pick_intro_point(unsigned int direct_conn, smartlist_t *exclude_nodes)
/* Let's do a basic sanity check here so that we don't end up advertising the
* ed25519 identity key of relays that don't actually support the link
* protocol */
- if (!node_supports_ed25519_link_authentication(node)) {
+ if (!node_supports_ed25519_link_authentication(node, 0)) {
tor_assert_nonfatal(ed25519_public_key_is_zero(&info->ed_identity));
} else {
/* Make sure we *do* have an ed key if we support the link authentication.
@@ -2199,16 +2203,12 @@ static void
upload_descriptor_to_hsdir(const hs_service_t *service,
hs_service_descriptor_t *desc, const node_t *hsdir)
{
- char version_str[4] = {0}, *encoded_desc = NULL;
- directory_request_t *dir_req;
- hs_ident_dir_conn_t ident;
+ char *encoded_desc = NULL;
tor_assert(service);
tor_assert(desc);
tor_assert(hsdir);
- memset(&ident, 0, sizeof(ident));
-
/* Let's avoid doing that if tor is configured to not publish. */
if (!get_options()->PublishHidServDescriptors) {
log_info(LD_REND, "Service %s not publishing descriptor. "
@@ -2224,29 +2224,10 @@ upload_descriptor_to_hsdir(const hs_service_t *service,
goto end;
}
- /* Setup the connection identifier. */
- hs_ident_dir_conn_init(&service->keys.identity_pk, &desc->blinded_kp.pubkey,
- &ident);
-
- /* This is our resource when uploading which is used to construct the URL
- * with the version number: "/tor/hs/<version>/publish". */
- tor_snprintf(version_str, sizeof(version_str), "%u",
- service->config.version);
-
- /* Build the directory request for this HSDir. */
- dir_req = directory_request_new(DIR_PURPOSE_UPLOAD_HSDESC);
- directory_request_set_routerstatus(dir_req, hsdir->rs);
- directory_request_set_indirection(dir_req, DIRIND_ANONYMOUS);
- directory_request_set_resource(dir_req, version_str);
- directory_request_set_payload(dir_req, encoded_desc,
- strlen(encoded_desc));
- /* The ident object is copied over the directory connection object once
- * the directory request is initiated. */
- directory_request_upload_set_hs_ident(dir_req, &ident);
-
- /* Initiate the directory request to the hsdir.*/
- directory_initiate_request(dir_req);
- directory_request_free(dir_req);
+ /* Time to upload the descriptor to the directory. */
+ hs_service_upload_desc_to_dir(encoded_desc, service->config.version,
+ &service->keys.identity_pk,
+ &desc->blinded_kp.pubkey, hsdir->rs);
/* Add this node to previous_hsdirs list */
service_desc_note_upload(desc, hsdir);
@@ -2263,9 +2244,12 @@ upload_descriptor_to_hsdir(const hs_service_t *service,
desc->desc->plaintext_data.revision_counter,
safe_str_client(node_describe(hsdir)),
safe_str_client(hex_str((const char *) index, 32)));
+
+ /* Fire a UPLOAD control port event. */
+ hs_control_desc_event_upload(service->onion_address, hsdir->identity,
+ &desc->blinded_kp.pubkey, index);
}
- /* XXX: Inform control port of the upload event (#20699). */
end:
tor_free(encoded_desc);
return;
@@ -2900,6 +2884,205 @@ service_add_fnames_to_list(const hs_service_t *service, smartlist_t *list)
/* Public API */
/* ========== */
+/* Upload an encoded descriptor in encoded_desc of the given version. This
+ * descriptor is for the service identity_pk and blinded_pk used to setup the
+ * directory connection identifier. It is uploaded to the directory hsdir_rs
+ * routerstatus_t object.
+ *
+ * NOTE: This function does NOT check for PublishHidServDescriptors because it
+ * is only used by the control port command HSPOST outside of this subsystem.
+ * Inside this code, upload_descriptor_to_hsdir() should be used. */
+void
+hs_service_upload_desc_to_dir(const char *encoded_desc,
+ const uint8_t version,
+ const ed25519_public_key_t *identity_pk,
+ const ed25519_public_key_t *blinded_pk,
+ const routerstatus_t *hsdir_rs)
+{
+ char version_str[4] = {0};
+ directory_request_t *dir_req;
+ hs_ident_dir_conn_t ident;
+
+ tor_assert(encoded_desc);
+ tor_assert(identity_pk);
+ tor_assert(blinded_pk);
+ tor_assert(hsdir_rs);
+
+ /* Setup the connection identifier. */
+ memset(&ident, 0, sizeof(ident));
+ hs_ident_dir_conn_init(identity_pk, blinded_pk, &ident);
+
+ /* This is our resource when uploading which is used to construct the URL
+ * with the version number: "/tor/hs/<version>/publish". */
+ tor_snprintf(version_str, sizeof(version_str), "%u", version);
+
+ /* Build the directory request for this HSDir. */
+ dir_req = directory_request_new(DIR_PURPOSE_UPLOAD_HSDESC);
+ directory_request_set_routerstatus(dir_req, hsdir_rs);
+ directory_request_set_indirection(dir_req, DIRIND_ANONYMOUS);
+ directory_request_set_resource(dir_req, version_str);
+ directory_request_set_payload(dir_req, encoded_desc,
+ strlen(encoded_desc));
+ /* The ident object is copied over the directory connection object once
+ * the directory request is initiated. */
+ directory_request_upload_set_hs_ident(dir_req, &ident);
+
+ /* Initiate the directory request to the hsdir.*/
+ directory_initiate_request(dir_req);
+ directory_request_free(dir_req);
+}
+
+/* Add the ephemeral service using the secret key sk and ports. Both max
+ * streams parameter will be set in the newly created service.
+ *
+ * Ownership of sk and ports is passed to this routine. Regardless of
+ * success/failure, callers should not touch these values after calling this
+ * routine, and may assume that correct cleanup has been done on failure.
+ *
+ * Return an appropriate hs_service_add_ephemeral_status_t. */
+hs_service_add_ephemeral_status_t
+hs_service_add_ephemeral(ed25519_secret_key_t *sk, smartlist_t *ports,
+ int max_streams_per_rdv_circuit,
+ int max_streams_close_circuit, char **address_out)
+{
+ hs_service_add_ephemeral_status_t ret;
+ hs_service_t *service = NULL;
+
+ tor_assert(sk);
+ tor_assert(ports);
+ tor_assert(address_out);
+
+ service = hs_service_new(get_options());
+
+ /* Setup the service configuration with specifics. A default service is
+ * HS_VERSION_TWO so explicitely set it. */
+ service->config.version = HS_VERSION_THREE;
+ service->config.max_streams_per_rdv_circuit = max_streams_per_rdv_circuit;
+ service->config.max_streams_close_circuit = !!max_streams_close_circuit;
+ service->config.is_ephemeral = 1;
+ smartlist_free(service->config.ports);
+ service->config.ports = ports;
+
+ /* Handle the keys. */
+ memcpy(&service->keys.identity_sk, sk, sizeof(service->keys.identity_sk));
+ if (ed25519_public_key_generate(&service->keys.identity_pk,
+ &service->keys.identity_sk) < 0) {
+ log_warn(LD_CONFIG, "Unable to generate ed25519 public key"
+ "for v3 service.");
+ ret = RSAE_BADPRIVKEY;
+ goto err;
+ }
+
+ /* Make sure we have at least one port. */
+ if (smartlist_len(service->config.ports) == 0) {
+ log_warn(LD_CONFIG, "At least one VIRTPORT/TARGET must be specified "
+ "for v3 service.");
+ ret = RSAE_BADVIRTPORT;
+ goto err;
+ }
+
+ /* The only way the registration can fail is if the service public key
+ * already exists. */
+ if (BUG(register_service(hs_service_map, service) < 0)) {
+ log_warn(LD_CONFIG, "Onion Service private key collides with an "
+ "existing v3 service.");
+ ret = RSAE_ADDREXISTS;
+ goto err;
+ }
+
+ /* Last step is to build the onion address. */
+ hs_build_address(&service->keys.identity_pk,
+ (uint8_t) service->config.version,
+ service->onion_address);
+ *address_out = tor_strdup(service->onion_address);
+
+ log_info(LD_CONFIG, "Added ephemeral v3 onion service: %s",
+ safe_str_client(service->onion_address));
+ ret = RSAE_OKAY;
+ goto end;
+
+ err:
+ hs_service_free(service);
+
+ end:
+ memwipe(sk, 0, sizeof(ed25519_secret_key_t));
+ tor_free(sk);
+ return ret;
+}
+
+/* For the given onion address, delete the ephemeral service. Return 0 on
+ * success else -1 on error. */
+int
+hs_service_del_ephemeral(const char *address)
+{
+ uint8_t version;
+ ed25519_public_key_t pk;
+ hs_service_t *service = NULL;
+
+ tor_assert(address);
+
+ if (hs_parse_address(address, &pk, NULL, &version) < 0) {
+ log_warn(LD_CONFIG, "Requested malformed v3 onion address for removal.");
+ goto err;
+ }
+
+ if (version != HS_VERSION_THREE) {
+ log_warn(LD_CONFIG, "Requested version of onion address for removal "
+ "is not supported.");
+ goto err;
+ }
+
+ service = find_service(hs_service_map, &pk);
+ if (service == NULL) {
+ log_warn(LD_CONFIG, "Requested non-existent v3 hidden service for "
+ "removal.");
+ goto err;
+ }
+
+ if (!service->config.is_ephemeral) {
+ log_warn(LD_CONFIG, "Requested non-ephemeral v3 hidden service for "
+ "removal.");
+ goto err;
+ }
+
+ /* Close circuits, remove from map and finally free. */
+ close_service_circuits(service);
+ remove_service(hs_service_map, service);
+ hs_service_free(service);
+
+ log_info(LD_CONFIG, "Removed ephemeral v3 hidden service: %s",
+ safe_str_client(address));
+ return 0;
+
+ err:
+ return -1;
+}
+
+/* Using the ed25519 public key pk, find a service for that key and return the
+ * current encoded descriptor as a newly allocated string or NULL if not
+ * found. This is used by the control port subsystem. */
+char *
+hs_service_lookup_current_desc(const ed25519_public_key_t *pk)
+{
+ const hs_service_t *service;
+
+ tor_assert(pk);
+
+ service = find_service(hs_service_map, pk);
+ if (service && service->desc_current) {
+ char *encoded_desc = NULL;
+ /* No matter what is the result (which should never be a failure), return
+ * the encoded variable, if success it will contain the right thing else
+ * it will be NULL. */
+ hs_desc_encode_descriptor(service->desc_current->desc,
+ &service->desc_current->signing_kp,
+ &encoded_desc);
+ return encoded_desc;
+ }
+
+ return NULL;
+}
+
/* Return the number of service we have configured and usable. */
unsigned int
hs_service_get_num_services(void)
@@ -2928,7 +3111,9 @@ hs_service_intro_circ_has_closed(origin_circuit_t *circ)
get_objects_from_ident(circ->hs_ident, &service, &ip, &desc);
if (service == NULL) {
- log_warn(LD_REND, "Unable to find any hidden service associated "
+ /* This is possible if the circuits are closed and the service is
+ * immediately deleted. */
+ log_info(LD_REND, "Unable to find any hidden service associated "
"identity key %s on intro circuit %u.",
ed25519_fmt(&circ->hs_ident->identity_pk),
TO_CIRCUIT(circ)->n_circ_id);
@@ -3256,7 +3441,7 @@ hs_service_new(const or_options_t *options)
* also takes care of wiping service keys from memory. It is safe to pass a
* NULL pointer. */
void
-hs_service_free(hs_service_t *service)
+hs_service_free_(hs_service_t *service)
{
if (service == NULL) {
return;
diff --git a/src/or/hs_service.h b/src/or/hs_service.h
index ed1053d850..d163eeef28 100644
--- a/src/or/hs_service.h
+++ b/src/or/hs_service.h
@@ -249,7 +249,8 @@ void hs_service_free_all(void);
/* Service new/free functions. */
hs_service_t *hs_service_new(const or_options_t *options);
-void hs_service_free(hs_service_t *service);
+void hs_service_free_(hs_service_t *service);
+#define hs_service_free(s) FREE_AND_NULL(hs_service_t, hs_service_free_, (s))
unsigned int hs_service_get_num_services(void);
void hs_service_stage_services(const smartlist_t *service_list);
@@ -271,15 +272,33 @@ int hs_service_receive_introduce2(origin_circuit_t *circ,
void hs_service_intro_circ_has_closed(origin_circuit_t *circ);
+char *hs_service_lookup_current_desc(const ed25519_public_key_t *pk);
+
+hs_service_add_ephemeral_status_t
+hs_service_add_ephemeral(ed25519_secret_key_t *sk, smartlist_t *ports,
+ int max_streams_per_rdv_circuit,
+ int max_streams_close_circuit, char **address_out);
+int hs_service_del_ephemeral(const char *address);
+
+/* Used outside of the HS subsystem by the control port command HSPOST. */
+void hs_service_upload_desc_to_dir(const char *encoded_desc,
+ const uint8_t version,
+ const ed25519_public_key_t *identity_pk,
+ const ed25519_public_key_t *blinded_pk,
+ const routerstatus_t *hsdir_rs);
+
#ifdef HS_SERVICE_PRIVATE
#ifdef TOR_UNIT_TESTS
-
/* Useful getters for unit tests. */
STATIC unsigned int get_hs_service_map_size(void);
STATIC int get_hs_service_staging_list_size(void);
STATIC hs_service_ht *get_hs_service_map(void);
STATIC hs_service_t *get_first_service(void);
+STATIC hs_service_intro_point_t *service_intro_point_find_by_ident(
+ const hs_service_t *service,
+ const hs_ident_circuit_t *ident);
+#endif
/* Service accessors. */
STATIC hs_service_t *find_service(hs_service_ht *map,
@@ -290,7 +309,10 @@ STATIC int register_service(hs_service_ht *map, hs_service_t *service);
STATIC hs_service_intro_point_t *service_intro_point_new(
const extend_info_t *ei,
unsigned int is_legacy);
-STATIC void service_intro_point_free(hs_service_intro_point_t *ip);
+STATIC void service_intro_point_free_(hs_service_intro_point_t *ip);
+#define service_intro_point_free(ip) \
+ FREE_AND_NULL(hs_service_intro_point_t, \
+ service_intro_point_free_, (ip))
STATIC void service_intro_point_add(digest256map_t *map,
hs_service_intro_point_t *ip);
STATIC void service_intro_point_remove(const hs_service_t *service,
@@ -298,9 +320,6 @@ STATIC void service_intro_point_remove(const hs_service_t *service,
STATIC hs_service_intro_point_t *service_intro_point_find(
const hs_service_t *service,
const ed25519_public_key_t *auth_key);
-STATIC hs_service_intro_point_t *service_intro_point_find_by_ident(
- const hs_service_t *service,
- const hs_ident_circuit_t *ident);
/* Service descriptor functions. */
STATIC hs_service_descriptor_t *service_descriptor_new(void);
STATIC hs_service_descriptor_t *service_desc_find_by_intro(
@@ -326,7 +345,10 @@ STATIC void run_upload_descriptor_event(time_t now);
STATIC char *
encode_desc_rev_counter_for_state(const hs_service_descriptor_t *desc);
-STATIC void service_descriptor_free(hs_service_descriptor_t *desc);
+STATIC void service_descriptor_free_(hs_service_descriptor_t *desc);
+#define service_descriptor_free(d) \
+ FREE_AND_NULL(hs_service_descriptor_t, \
+ service_descriptor_free_, (d))
STATIC uint64_t
check_state_line_for_service_rev_counter(const char *state_line,
@@ -346,8 +368,6 @@ STATIC void service_desc_schedule_upload(hs_service_descriptor_t *desc,
STATIC int service_desc_hsdirs_changed(const hs_service_t *service,
const hs_service_descriptor_t *desc);
-#endif /* defined(TOR_UNIT_TESTS) */
-
#endif /* defined(HS_SERVICE_PRIVATE) */
#endif /* !defined(TOR_HS_SERVICE_H) */
diff --git a/src/or/include.am b/src/or/include.am
index b783f4855a..1c66cd2de3 100644
--- a/src/or/include.am
+++ b/src/or/include.am
@@ -60,6 +60,7 @@ LIBTOR_A_SOURCES = \
src/or/hs_client.c \
src/or/hs_common.c \
src/or/hs_config.c \
+ src/or/hs_control.c \
src/or/hs_descriptor.c \
src/or/hs_ident.c \
src/or/hs_intropoint.c \
@@ -196,11 +197,12 @@ ORHEADERS = \
src/or/hibernate.h \
src/or/hs_cache.h \
src/or/hs_cell.h \
- src/or/hs_config.h \
src/or/hs_circuit.h \
src/or/hs_circuitmap.h \
src/or/hs_client.h \
src/or/hs_common.h \
+ src/or/hs_config.h \
+ src/or/hs_control.h \
src/or/hs_descriptor.h \
src/or/hs_ident.h \
src/or/hs_intropoint.h \
diff --git a/src/or/main.c b/src/or/main.c
index 97dcdcb3c2..aae98dd8ab 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -1471,7 +1471,9 @@ run_scheduled_events(time_t now)
/* Maybe enough time elapsed for us to reconsider a circuit. */
circuit_upgrade_circuits_from_guard_wait();
- if (options->UseBridges && !options->DisableNetwork) {
+ if (options->UseBridges && !net_is_disabled()) {
+ /* Note: this check uses net_is_disabled(), not should_delay_dir_fetches()
+ * -- the latter is only for fetching consensus-derived directory info. */
fetch_bridge_descriptors(options, now);
}
@@ -1577,7 +1579,7 @@ rotate_onion_key_callback(time_t now, const or_options_t *options)
if (router_rebuild_descriptor(1)<0) {
log_info(LD_CONFIG, "Couldn't rebuild router descriptor");
}
- if (advertised_server_mode() && !options->DisableNetwork)
+ if (advertised_server_mode() && !net_is_disabled())
router_upload_dir_desc_to_dirservers(0);
return ONION_KEY_CONSENSUS_CHECK_INTERVAL;
}
@@ -1942,9 +1944,11 @@ check_descriptor_callback(time_t now, const or_options_t *options)
* address has changed. */
#define CHECK_DESCRIPTOR_INTERVAL (60)
+ (void)options;
+
/* 2b. Once per minute, regenerate and upload the descriptor if the old
* one is inaccurate. */
- if (!options->DisableNetwork) {
+ if (!net_is_disabled()) {
check_descriptor_bandwidth_changed(now);
check_descriptor_ipaddress_changed(now);
mark_my_descriptor_dirty_if_too_old(now);
@@ -1976,7 +1980,7 @@ check_for_reachability_bw_callback(time_t now, const or_options_t *options)
* 20 minutes of our uptime. */
if (server_mode(options) &&
(have_completed_a_circuit() || !any_predicted_circuits(now)) &&
- !we_are_hibernating()) {
+ !net_is_disabled()) {
if (stats_n_seconds_working < TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT) {
consider_testing_reachability(1, dirport_reachability_count==0);
if (++dirport_reachability_count > 5)
@@ -2478,7 +2482,7 @@ do_hup(void)
/* retry appropriate downloads */
router_reset_status_download_failures();
router_reset_descriptor_download_failures();
- if (!options->DisableNetwork)
+ if (!net_is_disabled())
update_networkstatus_downloads(time(NULL));
/* We'll retry routerstatus downloads in about 10 seconds; no need to
@@ -3203,7 +3207,7 @@ tor_init(int argc, char *argv[])
log_notice(LD_GENERAL, "%s", rust_str);
}
tor_free(rust_str);
-#endif
+#endif /* defined(HAVE_RUST) */
if (network_init()<0) {
log_err(LD_BUG,"Error initializing network; exiting.");
@@ -3270,7 +3274,7 @@ try_locking(const or_options_t *options, int err_if_locked)
if (lockfile)
return 0;
else {
- char *fname = options_get_datadir_fname2_suffix(options, "lock",NULL,NULL);
+ char *fname = options_get_datadir_fname(options, "lock");
int already_locked = 0;
tor_lockfile_t *lf = tor_lockfile_lock(fname, 0, &already_locked);
tor_free(fname);
@@ -3546,7 +3550,7 @@ sandbox_init_filter(void)
int i;
sandbox_cfg_allow_openat_filename(&cfg,
- get_datadir_fname("cached-status"));
+ get_cachedir_fname("cached-status"));
#define OPEN(name) \
sandbox_cfg_allow_open_filename(&cfg, tor_strdup(name))
@@ -3567,21 +3571,38 @@ sandbox_init_filter(void)
OPEN_DATADIR2(name, name2 suffix); \
} while (0)
+#define OPEN_KEY_DIRECTORY() \
+ sandbox_cfg_allow_open_filename(&cfg, tor_strdup(options->KeyDirectory))
+#define OPEN_CACHEDIR(name) \
+ sandbox_cfg_allow_open_filename(&cfg, get_cachedir_fname(name))
+#define OPEN_CACHEDIR_SUFFIX(name, suffix) do { \
+ OPEN_CACHEDIR(name); \
+ OPEN_CACHEDIR(name suffix); \
+ } while (0)
+#define OPEN_KEYDIR(name) \
+ sandbox_cfg_allow_open_filename(&cfg, get_keydir_fname(name))
+#define OPEN_KEYDIR_SUFFIX(name, suffix) do { \
+ OPEN_KEYDIR(name); \
+ OPEN_KEYDIR(name suffix); \
+ } while (0)
+
OPEN(options->DataDirectory);
- OPEN_DATADIR("keys");
- OPEN_DATADIR_SUFFIX("cached-certs", ".tmp");
- OPEN_DATADIR_SUFFIX("cached-consensus", ".tmp");
- OPEN_DATADIR_SUFFIX("unverified-consensus", ".tmp");
- OPEN_DATADIR_SUFFIX("unverified-microdesc-consensus", ".tmp");
- OPEN_DATADIR_SUFFIX("cached-microdesc-consensus", ".tmp");
- OPEN_DATADIR_SUFFIX("cached-microdescs", ".tmp");
- OPEN_DATADIR_SUFFIX("cached-microdescs.new", ".tmp");
- OPEN_DATADIR_SUFFIX("cached-descriptors", ".tmp");
- OPEN_DATADIR_SUFFIX("cached-descriptors.new", ".tmp");
- OPEN_DATADIR("cached-descriptors.tmp.tmp");
- OPEN_DATADIR_SUFFIX("cached-extrainfo", ".tmp");
- OPEN_DATADIR_SUFFIX("cached-extrainfo.new", ".tmp");
- OPEN_DATADIR("cached-extrainfo.tmp.tmp");
+ OPEN_KEY_DIRECTORY();
+
+ OPEN_CACHEDIR_SUFFIX("cached-certs", ".tmp");
+ OPEN_CACHEDIR_SUFFIX("cached-consensus", ".tmp");
+ OPEN_CACHEDIR_SUFFIX("unverified-consensus", ".tmp");
+ OPEN_CACHEDIR_SUFFIX("unverified-microdesc-consensus", ".tmp");
+ OPEN_CACHEDIR_SUFFIX("cached-microdesc-consensus", ".tmp");
+ OPEN_CACHEDIR_SUFFIX("cached-microdescs", ".tmp");
+ OPEN_CACHEDIR_SUFFIX("cached-microdescs.new", ".tmp");
+ OPEN_CACHEDIR_SUFFIX("cached-descriptors", ".tmp");
+ OPEN_CACHEDIR_SUFFIX("cached-descriptors.new", ".tmp");
+ OPEN_CACHEDIR("cached-descriptors.tmp.tmp");
+ OPEN_CACHEDIR_SUFFIX("cached-extrainfo", ".tmp");
+ OPEN_CACHEDIR_SUFFIX("cached-extrainfo.new", ".tmp");
+ OPEN_CACHEDIR("cached-extrainfo.tmp.tmp");
+
OPEN_DATADIR_SUFFIX("state", ".tmp");
OPEN_DATADIR_SUFFIX("sr-state", ".tmp");
OPEN_DATADIR_SUFFIX("unparseable-desc", ".tmp");
@@ -3625,20 +3646,31 @@ sandbox_init_filter(void)
get_datadir_fname2(prefix, name suffix), \
get_datadir_fname2(prefix, name))
- RENAME_SUFFIX("cached-certs", ".tmp");
- RENAME_SUFFIX("cached-consensus", ".tmp");
- RENAME_SUFFIX("unverified-consensus", ".tmp");
- RENAME_SUFFIX("unverified-microdesc-consensus", ".tmp");
- RENAME_SUFFIX("cached-microdesc-consensus", ".tmp");
- RENAME_SUFFIX("cached-microdescs", ".tmp");
- RENAME_SUFFIX("cached-microdescs", ".new");
- RENAME_SUFFIX("cached-microdescs.new", ".tmp");
- RENAME_SUFFIX("cached-descriptors", ".tmp");
- RENAME_SUFFIX("cached-descriptors", ".new");
- RENAME_SUFFIX("cached-descriptors.new", ".tmp");
- RENAME_SUFFIX("cached-extrainfo", ".tmp");
- RENAME_SUFFIX("cached-extrainfo", ".new");
- RENAME_SUFFIX("cached-extrainfo.new", ".tmp");
+#define RENAME_CACHEDIR_SUFFIX(name, suffix) \
+ sandbox_cfg_allow_rename(&cfg, \
+ get_cachedir_fname(name suffix), \
+ get_cachedir_fname(name))
+
+#define RENAME_KEYDIR_SUFFIX(name, suffix) \
+ sandbox_cfg_allow_rename(&cfg, \
+ get_keydir_fname(name suffix), \
+ get_keydir_fname(name))
+
+ RENAME_CACHEDIR_SUFFIX("cached-certs", ".tmp");
+ RENAME_CACHEDIR_SUFFIX("cached-consensus", ".tmp");
+ RENAME_CACHEDIR_SUFFIX("unverified-consensus", ".tmp");
+ RENAME_CACHEDIR_SUFFIX("unverified-microdesc-consensus", ".tmp");
+ RENAME_CACHEDIR_SUFFIX("cached-microdesc-consensus", ".tmp");
+ RENAME_CACHEDIR_SUFFIX("cached-microdescs", ".tmp");
+ RENAME_CACHEDIR_SUFFIX("cached-microdescs", ".new");
+ RENAME_CACHEDIR_SUFFIX("cached-microdescs.new", ".tmp");
+ RENAME_CACHEDIR_SUFFIX("cached-descriptors", ".tmp");
+ RENAME_CACHEDIR_SUFFIX("cached-descriptors", ".new");
+ RENAME_CACHEDIR_SUFFIX("cached-descriptors.new", ".tmp");
+ RENAME_CACHEDIR_SUFFIX("cached-extrainfo", ".tmp");
+ RENAME_CACHEDIR_SUFFIX("cached-extrainfo", ".new");
+ RENAME_CACHEDIR_SUFFIX("cached-extrainfo.new", ".tmp");
+
RENAME_SUFFIX("state", ".tmp");
RENAME_SUFFIX("sr-state", ".tmp");
RENAME_SUFFIX("unparseable-desc", ".tmp");
@@ -3650,14 +3682,21 @@ sandbox_init_filter(void)
#define STAT_DATADIR(name) \
sandbox_cfg_allow_stat_filename(&cfg, get_datadir_fname(name))
+#define STAT_CACHEDIR(name) \
+ sandbox_cfg_allow_stat_filename(&cfg, get_cachedir_fname(name))
+
#define STAT_DATADIR2(name, name2) \
sandbox_cfg_allow_stat_filename(&cfg, get_datadir_fname2((name), (name2)))
+#define STAT_KEY_DIRECTORY() \
+ sandbox_cfg_allow_stat_filename(&cfg, tor_strdup(options->KeyDirectory))
+
STAT_DATADIR(NULL);
STAT_DATADIR("lock");
STAT_DATADIR("state");
STAT_DATADIR("router-stability");
- STAT_DATADIR("cached-extrainfo.new");
+
+ STAT_CACHEDIR("cached-extrainfo.new");
{
smartlist_t *files = smartlist_new();
@@ -3722,22 +3761,20 @@ sandbox_init_filter(void)
// orport
if (server_mode(get_options())) {
- OPEN_DATADIR2_SUFFIX("keys", "secret_id_key", ".tmp");
- OPEN_DATADIR2_SUFFIX("keys", "secret_onion_key", ".tmp");
- OPEN_DATADIR2_SUFFIX("keys", "secret_onion_key_ntor", ".tmp");
- OPEN_DATADIR2("keys", "secret_id_key.old");
- OPEN_DATADIR2("keys", "secret_onion_key.old");
- OPEN_DATADIR2("keys", "secret_onion_key_ntor.old");
-
- OPEN_DATADIR2_SUFFIX("keys", "ed25519_master_id_secret_key", ".tmp");
- OPEN_DATADIR2_SUFFIX("keys", "ed25519_master_id_secret_key_encrypted",
- ".tmp");
- OPEN_DATADIR2_SUFFIX("keys", "ed25519_master_id_public_key", ".tmp");
- OPEN_DATADIR2_SUFFIX("keys", "ed25519_signing_secret_key", ".tmp");
- OPEN_DATADIR2_SUFFIX("keys", "ed25519_signing_secret_key_encrypted",
- ".tmp");
- OPEN_DATADIR2_SUFFIX("keys", "ed25519_signing_public_key", ".tmp");
- OPEN_DATADIR2_SUFFIX("keys", "ed25519_signing_cert", ".tmp");
+ OPEN_KEYDIR_SUFFIX("secret_id_key", ".tmp");
+ OPEN_KEYDIR_SUFFIX("secret_onion_key", ".tmp");
+ OPEN_KEYDIR_SUFFIX("secret_onion_key_ntor", ".tmp");
+ OPEN_KEYDIR("secret_id_key.old");
+ OPEN_KEYDIR("secret_onion_key.old");
+ OPEN_KEYDIR("secret_onion_key_ntor.old");
+
+ OPEN_KEYDIR_SUFFIX("ed25519_master_id_secret_key", ".tmp");
+ OPEN_KEYDIR_SUFFIX("ed25519_master_id_secret_key_encrypted", ".tmp");
+ OPEN_KEYDIR_SUFFIX("ed25519_master_id_public_key", ".tmp");
+ OPEN_KEYDIR_SUFFIX("ed25519_signing_secret_key", ".tmp");
+ OPEN_KEYDIR_SUFFIX("ed25519_signing_secret_key_encrypted", ".tmp");
+ OPEN_KEYDIR_SUFFIX("ed25519_signing_public_key", ".tmp");
+ OPEN_KEYDIR_SUFFIX("ed25519_signing_cert", ".tmp");
OPEN_DATADIR2_SUFFIX("stats", "bridge-stats", ".tmp");
OPEN_DATADIR2_SUFFIX("stats", "dirreq-stats", ".tmp");
@@ -3756,11 +3793,13 @@ sandbox_init_filter(void)
OPEN("/etc/resolv.conf");
RENAME_SUFFIX("fingerprint", ".tmp");
- RENAME_SUFFIX2("keys", "secret_onion_key_ntor", ".tmp");
- RENAME_SUFFIX2("keys", "secret_id_key", ".tmp");
- RENAME_SUFFIX2("keys", "secret_id_key.old", ".tmp");
- RENAME_SUFFIX2("keys", "secret_onion_key", ".tmp");
- RENAME_SUFFIX2("keys", "secret_onion_key.old", ".tmp");
+ RENAME_KEYDIR_SUFFIX("secret_onion_key_ntor", ".tmp");
+
+ RENAME_KEYDIR_SUFFIX("secret_id_key", ".tmp");
+ RENAME_KEYDIR_SUFFIX("secret_id_key.old", ".tmp");
+ RENAME_KEYDIR_SUFFIX("secret_onion_key", ".tmp");
+ RENAME_KEYDIR_SUFFIX("secret_onion_key.old", ".tmp");
+
RENAME_SUFFIX2("stats", "bridge-stats", ".tmp");
RENAME_SUFFIX2("stats", "dirreq-stats", ".tmp");
RENAME_SUFFIX2("stats", "entry-stats", ".tmp");
@@ -3771,20 +3810,20 @@ sandbox_init_filter(void)
RENAME_SUFFIX("hashed-fingerprint", ".tmp");
RENAME_SUFFIX("router-stability", ".tmp");
- RENAME_SUFFIX2("keys", "ed25519_master_id_secret_key", ".tmp");
- RENAME_SUFFIX2("keys", "ed25519_master_id_secret_key_encrypted", ".tmp");
- RENAME_SUFFIX2("keys", "ed25519_master_id_public_key", ".tmp");
- RENAME_SUFFIX2("keys", "ed25519_signing_secret_key", ".tmp");
- RENAME_SUFFIX2("keys", "ed25519_signing_cert", ".tmp");
+ RENAME_KEYDIR_SUFFIX("ed25519_master_id_secret_key", ".tmp");
+ RENAME_KEYDIR_SUFFIX("ed25519_master_id_secret_key_encrypted", ".tmp");
+ RENAME_KEYDIR_SUFFIX("ed25519_master_id_public_key", ".tmp");
+ RENAME_KEYDIR_SUFFIX("ed25519_signing_secret_key", ".tmp");
+ RENAME_KEYDIR_SUFFIX("ed25519_signing_cert", ".tmp");
sandbox_cfg_allow_rename(&cfg,
- get_datadir_fname2("keys", "secret_onion_key"),
- get_datadir_fname2("keys", "secret_onion_key.old"));
+ get_keydir_fname("secret_onion_key"),
+ get_keydir_fname("secret_onion_key.old"));
sandbox_cfg_allow_rename(&cfg,
- get_datadir_fname2("keys", "secret_onion_key_ntor"),
- get_datadir_fname2("keys", "secret_onion_key_ntor.old"));
+ get_keydir_fname("secret_onion_key_ntor"),
+ get_keydir_fname("secret_onion_key_ntor.old"));
- STAT_DATADIR("keys");
+ STAT_KEY_DIRECTORY();
OPEN_DATADIR("stats");
STAT_DATADIR("stats");
STAT_DATADIR2("stats", "dirreq-stats");
diff --git a/src/or/microdesc.c b/src/or/microdesc.c
index 18a6fbded7..d8a4660af1 100644
--- a/src/or/microdesc.c
+++ b/src/or/microdesc.c
@@ -74,6 +74,102 @@ HT_GENERATE2(microdesc_map, microdesc_t, node,
microdesc_hash_, microdesc_eq_, 0.6,
tor_reallocarray_, tor_free_)
+/************************* md fetch fail cache *****************************/
+
+/* If we end up with too many outdated dirservers, something probably went
+ * wrong so clean up the list. */
+#define TOO_MANY_OUTDATED_DIRSERVERS 30
+
+/** List of dirservers with outdated microdesc information. The smartlist is
+ * filled with the hex digests of outdated dirservers. */
+static smartlist_t *outdated_dirserver_list = NULL;
+
+/** Note that we failed to fetch a microdescriptor from the relay with
+ * <b>relay_digest</b> (of size DIGEST_LEN). */
+void
+microdesc_note_outdated_dirserver(const char *relay_digest)
+{
+ char relay_hexdigest[HEX_DIGEST_LEN+1];
+
+ /* Don't register outdated dirservers if we don't have a live consensus,
+ * since we might be trying to fetch microdescriptors that are not even
+ * currently active. */
+ if (!networkstatus_get_live_consensus(approx_time())) {
+ return;
+ }
+
+ if (!outdated_dirserver_list) {
+ outdated_dirserver_list = smartlist_new();
+ }
+
+ tor_assert(outdated_dirserver_list);
+
+ /* If the list grows too big, clean it up */
+ if (BUG(smartlist_len(outdated_dirserver_list) >
+ TOO_MANY_OUTDATED_DIRSERVERS)) {
+ microdesc_reset_outdated_dirservers_list();
+ }
+
+ /* Turn the binary relay digest to a hex since smartlists have better support
+ * for strings than digests. */
+ base16_encode(relay_hexdigest,sizeof(relay_hexdigest),
+ relay_digest, DIGEST_LEN);
+
+ /* Make sure we don't add a dirauth as an outdated dirserver */
+ if (router_get_trusteddirserver_by_digest(relay_digest)) {
+ log_info(LD_GENERAL, "Auth %s gave us outdated dirinfo.", relay_hexdigest);
+ return;
+ }
+
+ /* Don't double-add outdated dirservers */
+ if (smartlist_contains_string(outdated_dirserver_list, relay_hexdigest)) {
+ return;
+ }
+
+ /* Add it to the list of outdated dirservers */
+ smartlist_add_strdup(outdated_dirserver_list, relay_hexdigest);
+
+ log_info(LD_GENERAL, "Noted %s as outdated md dirserver", relay_hexdigest);
+}
+
+/** Return True if the relay with <b>relay_digest</b> (size DIGEST_LEN) is an
+ * outdated dirserver */
+int
+microdesc_relay_is_outdated_dirserver(const char *relay_digest)
+{
+ char relay_hexdigest[HEX_DIGEST_LEN+1];
+
+ if (!outdated_dirserver_list) {
+ return 0;
+ }
+
+ /* Convert identity digest to hex digest */
+ base16_encode(relay_hexdigest, sizeof(relay_hexdigest),
+ relay_digest, DIGEST_LEN);
+
+ /* Last time we tried to fetch microdescs, was this directory mirror missing
+ * any mds we asked for? */
+ if (smartlist_contains_string(outdated_dirserver_list, relay_hexdigest)) {
+ return 1;
+ }
+
+ return 0;
+}
+
+/** Reset the list of outdated dirservers. */
+void
+microdesc_reset_outdated_dirservers_list(void)
+{
+ if (!outdated_dirserver_list) {
+ return;
+ }
+
+ SMARTLIST_FOREACH(outdated_dirserver_list, char *, cp, tor_free(cp));
+ smartlist_clear(outdated_dirserver_list);
+}
+
+/****************************************************************************/
+
/** Write the body of <b>md</b> into <b>f</b>, with appropriate annotations.
* On success, return the total number of bytes written, and set
* *<b>annotation_len_out</b> to the number of bytes written as
@@ -142,8 +238,8 @@ get_microdesc_cache_noload(void)
if (PREDICT_UNLIKELY(the_microdesc_cache==NULL)) {
microdesc_cache_t *cache = tor_malloc_zero(sizeof(*cache));
HT_INIT(microdesc_map, &cache->map);
- cache->cache_fname = get_datadir_fname("cached-microdescs");
- cache->journal_fname = get_datadir_fname("cached-microdescs.new");
+ cache->cache_fname = get_cachedir_fname("cached-microdescs");
+ cache->journal_fname = get_cachedir_fname("cached-microdescs.new");
the_microdesc_cache = cache;
}
return the_microdesc_cache;
@@ -789,6 +885,11 @@ microdesc_free_all(void)
tor_free(the_microdesc_cache->journal_fname);
tor_free(the_microdesc_cache);
}
+
+ if (outdated_dirserver_list) {
+ SMARTLIST_FOREACH(outdated_dirserver_list, char *, cp, tor_free(cp));
+ smartlist_free(outdated_dirserver_list);
+ }
}
/** If there is a microdescriptor in <b>cache</b> whose sha256 digest is
diff --git a/src/or/microdesc.h b/src/or/microdesc.h
index b40d66b3e3..83a90bd8ff 100644
--- a/src/or/microdesc.h
+++ b/src/or/microdesc.h
@@ -38,8 +38,10 @@ smartlist_t *microdesc_list_missing_digest256(networkstatus_t *ns,
digest256map_t *skip);
void microdesc_free_(microdesc_t *md, const char *fname, int line);
-#define microdesc_free(md) \
- microdesc_free_((md), __FILE__, __LINE__)
+#define microdesc_free(md) do { \
+ microdesc_free_((md), __FILE__, __LINE__); \
+ (md) = NULL; \
+ } while (0)
void microdesc_free_all(void);
void update_microdesc_downloads(time_t now);
@@ -50,5 +52,9 @@ int we_fetch_microdescriptors(const or_options_t *options);
int we_fetch_router_descriptors(const or_options_t *options);
int we_use_microdescriptors_for_circuits(const or_options_t *options);
+void microdesc_note_outdated_dirserver(const char *relay_digest);
+int microdesc_relay_is_outdated_dirserver(const char *relay_digest);
+void microdesc_reset_outdated_dirservers_list(void);
+
#endif /* !defined(TOR_MICRODESC_H) */
diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c
index e4a6a76749..2843d06262 100644
--- a/src/or/networkstatus.c
+++ b/src/or/networkstatus.c
@@ -52,6 +52,7 @@
#include "dirserv.h"
#include "dirvote.h"
#include "entrynodes.h"
+#include "hibernate.h"
#include "main.h"
#include "microdesc.h"
#include "networkstatus.h"
@@ -196,7 +197,7 @@ networkstatus_read_cached_consensus_impl(int flav,
tor_snprintf(buf, sizeof(buf), "%s-%s-consensus", prefix, flavorname);
}
- char *filename = get_datadir_fname(buf);
+ char *filename = get_cachedir_fname(buf);
char *result = read_file_to_str(filename, RFTS_IGNORE_MISSING, NULL);
tor_free(filename);
return result;
@@ -254,7 +255,7 @@ router_reload_consensus_networkstatus(void)
/** Free all storage held by the vote_routerstatus object <b>rs</b>. */
void
-vote_routerstatus_free(vote_routerstatus_t *rs)
+vote_routerstatus_free_(vote_routerstatus_t *rs)
{
vote_microdesc_hash_t *h, *next;
if (!rs)
@@ -272,7 +273,7 @@ vote_routerstatus_free(vote_routerstatus_t *rs)
/** Free all storage held by the routerstatus object <b>rs</b>. */
void
-routerstatus_free(routerstatus_t *rs)
+routerstatus_free_(routerstatus_t *rs)
{
if (!rs)
return;
@@ -282,7 +283,7 @@ routerstatus_free(routerstatus_t *rs)
/** Free all storage held in <b>sig</b> */
void
-document_signature_free(document_signature_t *sig)
+document_signature_free_(document_signature_t *sig)
{
tor_free(sig->signature);
tor_free(sig);
@@ -300,7 +301,7 @@ document_signature_dup(const document_signature_t *sig)
/** Free all storage held in <b>ns</b>. */
void
-networkstatus_vote_free(networkstatus_t *ns)
+networkstatus_vote_free_(networkstatus_t *ns)
{
if (!ns)
return;
@@ -1208,6 +1209,14 @@ should_delay_dir_fetches(const or_options_t *options, const char **msg_out)
return 1;
}
+ if (we_are_hibernating()) {
+ if (msg_out) {
+ *msg_out = "We are hibernating or shutting down.";
+ }
+ log_info(LD_DIR, "Delaying dir fetches (Hibernating or shutting down)");
+ return 1;
+ }
+
if (options->UseBridges) {
if (!any_bridge_descriptors_known()) {
if (msg_out) {
@@ -1785,15 +1794,15 @@ networkstatus_set_current_consensus(const char *consensus,
}
if (!strcmp(flavor, "ns")) {
- consensus_fname = get_datadir_fname("cached-consensus");
- unverified_fname = get_datadir_fname("unverified-consensus");
+ consensus_fname = get_cachedir_fname("cached-consensus");
+ unverified_fname = get_cachedir_fname("unverified-consensus");
if (current_ns_consensus) {
current_digests = &current_ns_consensus->digests;
current_valid_after = current_ns_consensus->valid_after;
}
} else if (!strcmp(flavor, "microdesc")) {
- consensus_fname = get_datadir_fname("cached-microdesc-consensus");
- unverified_fname = get_datadir_fname("unverified-microdesc-consensus");
+ consensus_fname = get_cachedir_fname("cached-microdesc-consensus");
+ unverified_fname = get_cachedir_fname("unverified-microdesc-consensus");
if (current_md_consensus) {
current_digests = &current_md_consensus->digests;
current_valid_after = current_md_consensus->valid_after;
@@ -1802,9 +1811,9 @@ networkstatus_set_current_consensus(const char *consensus,
cached_dir_t *cur;
char buf[128];
tor_snprintf(buf, sizeof(buf), "cached-%s-consensus", flavor);
- consensus_fname = get_datadir_fname(buf);
+ consensus_fname = get_cachedir_fname(buf);
tor_snprintf(buf, sizeof(buf), "unverified-%s-consensus", flavor);
- unverified_fname = get_datadir_fname(buf);
+ unverified_fname = get_cachedir_fname(buf);
cur = dirserv_get_consensus(flavor);
if (cur) {
current_digests = &cur->digests;
@@ -2014,6 +2023,9 @@ networkstatus_set_current_consensus(const char *consensus,
tor_free(flavormsg);
}
+ /* We got a new consesus. Reset our md fetch fail cache */
+ microdesc_reset_outdated_dirservers_list();
+
router_dir_info_changed();
result = 0;
@@ -2197,7 +2209,9 @@ signed_descs_update_status_from_consensus_networkstatus(smartlist_t *descs)
char *
networkstatus_getinfo_helper_single(const routerstatus_t *rs)
{
- return routerstatus_format_entry(rs, NULL, NULL, NS_CONTROL_PORT, NULL);
+ return routerstatus_format_entry(rs, NULL, NULL, NS_CONTROL_PORT,
+ ROUTERSTATUS_FORMAT_NO_CONSENSUS_METHOD,
+ NULL);
}
/** Alloc and return a string describing routerstatuses for the most
@@ -2210,13 +2224,13 @@ networkstatus_getinfo_helper_single(const routerstatus_t *rs)
char *
networkstatus_getinfo_by_purpose(const char *purpose_string, time_t now)
{
- time_t cutoff = now - ROUTER_MAX_AGE_TO_PUBLISH;
+ const time_t cutoff = now - ROUTER_MAX_AGE_TO_PUBLISH;
char *answer;
routerlist_t *rl = router_get_routerlist();
smartlist_t *statuses;
- uint8_t purpose = router_purpose_from_string(purpose_string);
+ const uint8_t purpose = router_purpose_from_string(purpose_string);
routerstatus_t rs;
- int bridge_auth = authdir_mode_bridge(get_options());
+ const int bridge_auth = authdir_mode_bridge(get_options());
if (purpose == ROUTER_PURPOSE_UNKNOWN) {
log_info(LD_DIR, "Unrecognized purpose '%s' when listing router statuses.",
@@ -2233,6 +2247,7 @@ networkstatus_getinfo_by_purpose(const char *purpose_string, time_t now)
continue;
if (ri->purpose != purpose)
continue;
+ /* TODO: modifying the running flag in a getinfo is a bad idea */
if (bridge_auth && ri->purpose == ROUTER_PURPOSE_BRIDGE)
dirserv_set_router_is_running(ri, now);
/* then generate and write out status lines for each of them */
@@ -2251,7 +2266,6 @@ void
networkstatus_dump_bridge_status_to_file(time_t now)
{
char *status = networkstatus_getinfo_by_purpose("bridge", now);
- const or_options_t *options = get_options();
char *fname = NULL;
char *thresholds = NULL;
char *published_thresholds_and_status = NULL;
@@ -2273,8 +2287,7 @@ networkstatus_dump_bridge_status_to_file(time_t now)
"published %s\nflag-thresholds %s\n%s%s",
published, thresholds, fingerprint_line ? fingerprint_line : "",
status);
- tor_asprintf(&fname, "%s"PATH_SEPARATOR"networkstatus-bridges",
- options->DataDirectory);
+ fname = get_datadir_fname("networkstatus-bridges");
write_str_to_file(fname,published_thresholds_and_status,0);
tor_free(thresholds);
tor_free(published_thresholds_and_status);
diff --git a/src/or/networkstatus.h b/src/or/networkstatus.h
index 39a0f753d8..791e32adc4 100644
--- a/src/or/networkstatus.h
+++ b/src/or/networkstatus.h
@@ -18,8 +18,12 @@ void networkstatus_reset_warnings(void);
void networkstatus_reset_download_failures(void);
char *networkstatus_read_cached_consensus(const char *flavorname);
int router_reload_consensus_networkstatus(void);
-void routerstatus_free(routerstatus_t *rs);
-void networkstatus_vote_free(networkstatus_t *ns);
+void routerstatus_free_(routerstatus_t *rs);
+#define routerstatus_free(rs) \
+ FREE_AND_NULL(routerstatus_t, routerstatus_free_, (rs))
+void networkstatus_vote_free_(networkstatus_t *ns);
+#define networkstatus_vote_free(ns) \
+ FREE_AND_NULL(networkstatus_t, networkstatus_vote_free_, (ns))
networkstatus_voter_info_t *networkstatus_get_voter_by_id(
networkstatus_t *vote,
const char *identity);
@@ -124,12 +128,16 @@ int32_t networkstatus_get_bw_weight(networkstatus_t *ns, const char *weight,
int32_t default_val);
const char *networkstatus_get_flavor_name(consensus_flavor_t flav);
int networkstatus_parse_flavor_name(const char *flavname);
-void document_signature_free(document_signature_t *sig);
+void document_signature_free_(document_signature_t *sig);
+#define document_signature_free(sig) \
+ FREE_AND_NULL(document_signature_t, document_signature_free_, (sig))
document_signature_t *document_signature_dup(const document_signature_t *sig);
void networkstatus_free_all(void);
int networkstatus_get_weight_scale_param(networkstatus_t *ns);
-void vote_routerstatus_free(vote_routerstatus_t *rs);
+void vote_routerstatus_free_(vote_routerstatus_t *rs);
+#define vote_routerstatus_free(rs) \
+ FREE_AND_NULL(vote_routerstatus_t, vote_routerstatus_free_, (rs))
#ifdef NETWORKSTATUS_PRIVATE
#ifdef TOR_UNIT_TESTS
diff --git a/src/or/nodelist.c b/src/or/nodelist.c
index f2e979be8b..e6eaefb216 100644
--- a/src/or/nodelist.c
+++ b/src/or/nodelist.c
@@ -65,7 +65,9 @@
#include <string.h>
static void nodelist_drop_node(node_t *node, int remove_from_ht);
-static void node_free(node_t *node);
+#define node_free(val) \
+ FREE_AND_NULL(node_t, node_free_, (val))
+static void node_free_(node_t *node);
/** count_usable_descriptors counts descriptors with these flag(s)
*/
@@ -656,7 +658,7 @@ nodelist_find_nodes_with_microdesc(const microdesc_t *md)
/** Release storage held by <b>node</b> */
static void
-node_free(node_t *node)
+node_free_(node_t *node)
{
if (!node)
return;
@@ -951,23 +953,29 @@ node_ed25519_id_matches(const node_t *node, const ed25519_public_key_t *id)
}
/** Return true iff <b>node</b> supports authenticating itself
- * by ed25519 ID during the link handshake in a way that we can understand
- * when we probe it. */
+ * by ed25519 ID during the link handshake. If <b>compatible_with_us</b>,
+ * it needs to be using a link authentication method that we understand.
+ * If not, any plausible link authentication method will do. */
int
-node_supports_ed25519_link_authentication(const node_t *node)
+node_supports_ed25519_link_authentication(const node_t *node,
+ int compatible_with_us)
{
- /* XXXX Oh hm. What if some day in the future there are link handshake
- * versions that aren't 3 but which are ed25519 */
if (! node_get_ed25519_id(node))
return 0;
if (node->ri) {
const char *protos = node->ri->protocol_list;
if (protos == NULL)
return 0;
- return protocol_list_supports_protocol(protos, PRT_LINKAUTH, 3);
+ if (compatible_with_us)
+ return protocol_list_supports_protocol(protos, PRT_LINKAUTH, 3);
+ else
+ return protocol_list_supports_protocol_or_later(protos, PRT_LINKAUTH, 3);
}
if (node->rs) {
- return node->rs->supports_ed25519_link_handshake;
+ if (compatible_with_us)
+ return node->rs->supports_ed25519_link_handshake_compat;
+ else
+ return node->rs->supports_ed25519_link_handshake_any;
}
tor_assert_nonfatal_unreached_once();
return 0;
@@ -1633,6 +1641,18 @@ node_has_curve25519_onion_key(const node_t *node)
return 0;
}
+/** Return the curve25519 key of <b>node</b>, or NULL if none. */
+const curve25519_public_key_t *
+node_get_curve25519_onion_key(const node_t *node)
+{
+ if (node->ri)
+ return node->ri->onion_curve25519_pkey;
+ else if (node->md)
+ return node->md->onion_curve25519_pkey;
+ else
+ return NULL;
+}
+
/** Refresh the country code of <b>ri</b>. This function MUST be called on
* each router when the GeoIP database is reloaded, and on all new routers. */
void
diff --git a/src/or/nodelist.h b/src/or/nodelist.h
index 754990ac8d..e879b4e8ff 100644
--- a/src/or/nodelist.h
+++ b/src/or/nodelist.h
@@ -65,7 +65,8 @@ const smartlist_t *node_get_declared_family(const node_t *node);
const ed25519_public_key_t *node_get_ed25519_id(const node_t *node);
int node_ed25519_id_matches(const node_t *node,
const ed25519_public_key_t *id);
-int node_supports_ed25519_link_authentication(const node_t *node);
+int node_supports_ed25519_link_authentication(const node_t *node,
+ int compatible_with_us);
int node_supports_v3_hsdir(const node_t *node);
int node_supports_ed25519_hs_intro(const node_t *node);
int node_supports_v3_rendezvous_point(const node_t *node);
@@ -85,6 +86,8 @@ int node_get_prim_dirport(const node_t *node, tor_addr_port_t *ap_out);
void node_get_pref_dirport(const node_t *node, tor_addr_port_t *ap_out);
void node_get_pref_ipv6_dirport(const node_t *node, tor_addr_port_t *ap_out);
int node_has_curve25519_onion_key(const node_t *node);
+const curve25519_public_key_t *node_get_curve25519_onion_key(
+ const node_t *node);
MOCK_DECL(smartlist_t *, nodelist_get_list, (void));
diff --git a/src/or/onion.c b/src/or/onion.c
index 7e1e89df1b..bd80c2f503 100644
--- a/src/or/onion.c
+++ b/src/or/onion.c
@@ -423,7 +423,7 @@ server_onion_keys_new(void)
/** Release all storage held in <b>keys</b>. */
void
-server_onion_keys_free(server_onion_keys_t *keys)
+server_onion_keys_free_(server_onion_keys_t *keys)
{
if (! keys)
return;
diff --git a/src/or/onion.h b/src/or/onion.h
index 95544dfac1..3b738debeb 100644
--- a/src/or/onion.h
+++ b/src/or/onion.h
@@ -31,7 +31,9 @@ typedef struct server_onion_keys_t {
#define MAX_ONIONSKIN_REPLY_LEN 255
server_onion_keys_t *server_onion_keys_new(void);
-void server_onion_keys_free(server_onion_keys_t *keys);
+void server_onion_keys_free_(server_onion_keys_t *keys);
+#define server_onion_keys_free(keys) \
+ FREE_AND_NULL(server_onion_keys_t, server_onion_keys_free_, (keys))
void onion_handshake_state_release(onion_handshake_state_t *state);
diff --git a/src/or/onion_fast.c b/src/or/onion_fast.c
index 146943a273..56c954829e 100644
--- a/src/or/onion_fast.c
+++ b/src/or/onion_fast.c
@@ -32,7 +32,7 @@
/** Release all state held in <b>victim</b>. */
void
-fast_handshake_state_free(fast_handshake_state_t *victim)
+fast_handshake_state_free_(fast_handshake_state_t *victim)
{
if (! victim)
return;
diff --git a/src/or/onion_fast.h b/src/or/onion_fast.h
index 3a5aefea3f..c56712e2c2 100644
--- a/src/or/onion_fast.h
+++ b/src/or/onion_fast.h
@@ -19,7 +19,9 @@ typedef struct fast_handshake_state_t {
uint8_t state[DIGEST_LEN];
} fast_handshake_state_t;
-void fast_handshake_state_free(fast_handshake_state_t *victim);
+void fast_handshake_state_free_(fast_handshake_state_t *victim);
+#define fast_handshake_state_free(st) \
+ FREE_AND_NULL(fast_handshake_state_t, fast_handshake_state_free_, (st))
int fast_onionskin_create(fast_handshake_state_t **handshake_state_out,
uint8_t *handshake_out);
diff --git a/src/or/onion_ntor.c b/src/or/onion_ntor.c
index 902260b54b..b167cb61fb 100644
--- a/src/or/onion_ntor.c
+++ b/src/or/onion_ntor.c
@@ -28,7 +28,7 @@
/** Free storage held in an ntor handshake state. */
void
-ntor_handshake_state_free(ntor_handshake_state_t *state)
+ntor_handshake_state_free_(ntor_handshake_state_t *state)
{
if (!state)
return;
diff --git a/src/or/onion_ntor.h b/src/or/onion_ntor.h
index 02dea2dfc1..f7c962b7d0 100644
--- a/src/or/onion_ntor.h
+++ b/src/or/onion_ntor.h
@@ -17,7 +17,9 @@ typedef struct ntor_handshake_state_t ntor_handshake_state_t;
/** Length of an ntor reply, as sent from server to client. */
#define NTOR_REPLY_LEN 64
-void ntor_handshake_state_free(ntor_handshake_state_t *state);
+void ntor_handshake_state_free_(ntor_handshake_state_t *state);
+#define ntor_handshake_state_free(state) \
+ FREE_AND_NULL(ntor_handshake_state_t, ntor_handshake_state_free_, (state))
int onion_skin_ntor_create(const uint8_t *router_id,
const curve25519_public_key_t *router_key,
diff --git a/src/or/or.h b/src/or/or.h
index a68f1c3c47..b078022326 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -1166,8 +1166,8 @@ typedef struct packed_cell_t {
/** Next cell queued on this circuit. */
TOR_SIMPLEQ_ENTRY(packed_cell_t) next;
char body[CELL_MAX_NETWORK_SIZE]; /**< Cell as packed for network. */
- uint32_t inserted_time; /**< Time (in milliseconds since epoch, with high
- * bits truncated) when this cell was inserted. */
+ uint32_t inserted_timestamp; /**< Time (in timestamp units) when this cell
+ * was inserted */
} packed_cell_t;
/** A queue of cells on a circuit, waiting to be added to the
@@ -2316,8 +2316,12 @@ typedef struct routerstatus_t {
unsigned int supports_extend2_cells:1;
/** True iff this router has a protocol list that allows it to negotiate
- * ed25519 identity keys on a link handshake. */
- unsigned int supports_ed25519_link_handshake:1;
+ * ed25519 identity keys on a link handshake with us. */
+ unsigned int supports_ed25519_link_handshake_compat:1;
+
+ /** True iff this router has a protocol list that allows it to negotiate
+ * ed25519 identity keys on a link handshake, at all. */
+ unsigned int supports_ed25519_link_handshake_any:1;
/** True iff this router has a protocol list that allows it to be an
* introduction point supporting ed25519 authentication key which is part of
@@ -3637,8 +3641,21 @@ typedef struct {
char *SyslogIdentityTag; /**< Identity tag to add for syslog logging. */
char *DebugLogFile; /**< Where to send verbose log messages. */
- char *DataDirectory; /**< OR only: where to store long-term data. */
+ char *DataDirectory_option; /**< Where to store long-term data, as
+ * configured by the user. */
+ char *DataDirectory; /**< Where to store long-term data, as modified. */
int DataDirectoryGroupReadable; /**< Boolean: Is the DataDirectory g+r? */
+
+ char *KeyDirectory_option; /**< Where to store keys, as
+ * configured by the user. */
+ char *KeyDirectory; /**< Where to store keys data, as modified. */
+ int KeyDirectoryGroupReadable; /**< Boolean: Is the KeyDirectory g+r? */
+
+ char *CacheDirectory_option; /**< Where to store cached data, as
+ * configured by the user. */
+ char *CacheDirectory; /**< Where to store cached data, as modified. */
+ int CacheDirectoryGroupReadable; /**< Boolean: Is the CacheDirectory g+r? */
+
char *Nickname; /**< OR only: nickname of this onion router. */
char *Address; /**< OR only: configured address for this onion router. */
char *PidFile; /**< Where to store PID of Tor process. */
diff --git a/src/or/policies.c b/src/or/policies.c
index 1f80130710..fc033c5593 100644
--- a/src/or/policies.c
+++ b/src/or/policies.c
@@ -1792,14 +1792,14 @@ policies_parse_exit_policy_reject_private(
/* Reject public IPv4 addresses on any interface */
public_addresses = get_interface_address6_list(LOG_INFO, AF_INET, 0);
addr_policy_append_reject_addr_list_filter(dest, public_addresses, 1, 0);
- free_interface_address6_list(public_addresses);
+ interface_address6_list_free(public_addresses);
/* Don't look for IPv6 addresses if we're configured as IPv4-only */
if (ipv6_exit) {
/* Reject public IPv6 addresses on any interface */
public_addresses = get_interface_address6_list(LOG_INFO, AF_INET6, 0);
addr_policy_append_reject_addr_list_filter(dest, public_addresses, 0, 1);
- free_interface_address6_list(public_addresses);
+ interface_address6_list_free(public_addresses);
}
}
@@ -2794,7 +2794,7 @@ write_short_policy(const short_policy_t *policy)
/** Release all storage held in <b>policy</b>. */
void
-short_policy_free(short_policy_t *policy)
+short_policy_free_(short_policy_t *policy)
{
tor_free(policy);
}
@@ -3044,7 +3044,7 @@ getinfo_helper_policies(control_connection_t *conn,
/** Release all storage held by <b>p</b>. */
void
-addr_policy_list_free(smartlist_t *lst)
+addr_policy_list_free_(smartlist_t *lst)
{
if (!lst)
return;
@@ -3054,7 +3054,7 @@ addr_policy_list_free(smartlist_t *lst)
/** Release all storage held by <b>p</b>. */
void
-addr_policy_free(addr_policy_t *p)
+addr_policy_free_(addr_policy_t *p)
{
if (!p)
return;
diff --git a/src/or/policies.h b/src/or/policies.h
index cd97ee7f59..35220a812f 100644
--- a/src/or/policies.h
+++ b/src/or/policies.h
@@ -115,15 +115,21 @@ int getinfo_helper_policies(control_connection_t *conn,
int policy_write_item(char *buf, size_t buflen, const addr_policy_t *item,
int format_for_desc);
-void addr_policy_list_free(smartlist_t *p);
-void addr_policy_free(addr_policy_t *p);
+void addr_policy_list_free_(smartlist_t *p);
+#define addr_policy_list_free(lst) \
+ FREE_AND_NULL(smartlist_t, addr_policy_list_free_, (lst))
+void addr_policy_free_(addr_policy_t *p);
+#define addr_policy_free(p) \
+ FREE_AND_NULL(addr_policy_t, addr_policy_free_, (p))
void policies_free_all(void);
char *policy_summarize(smartlist_t *policy, sa_family_t family);
short_policy_t *parse_short_policy(const char *summary);
char *write_short_policy(const short_policy_t *policy);
-void short_policy_free(short_policy_t *policy);
+void short_policy_free_(short_policy_t *policy);
+#define short_policy_free(p) \
+ FREE_AND_NULL(short_policy_t, short_policy_free_, (p))
int short_policy_is_reject_star(const short_policy_t *policy);
addr_policy_result_t compare_tor_addr_to_short_policy(
const tor_addr_t *addr, uint16_t port,
diff --git a/src/or/proto_socks.c b/src/or/proto_socks.c
index 7649fcc4be..91633d02af 100644
--- a/src/or/proto_socks.c
+++ b/src/or/proto_socks.c
@@ -66,7 +66,7 @@ socks_request_new(void)
/** Free all storage held in the socks_request_t <b>req</b>. */
void
-socks_request_free(socks_request_t *req)
+socks_request_free_(socks_request_t *req)
{
if (!req)
return;
diff --git a/src/or/proto_socks.h b/src/or/proto_socks.h
index a714151414..02e0aca7e9 100644
--- a/src/or/proto_socks.h
+++ b/src/or/proto_socks.h
@@ -11,7 +11,9 @@ struct socks_request_t;
struct buf_t;
struct socks_request_t *socks_request_new(void);
-void socks_request_free(struct socks_request_t *req);
+void socks_request_free_(struct socks_request_t *req);
+#define socks_request_free(req) \
+ FREE_AND_NULL(socks_request_t, socks_request_free_, (req))
int fetch_from_buf_socks(struct buf_t *buf, socks_request_t *req,
int log_sockstype, int safe_socks);
int fetch_from_buf_socks_client(buf_t *buf, int state, char **reason);
diff --git a/src/or/protover.c b/src/or/protover.c
index 0e74deb112..1a5f4ac91f 100644
--- a/src/or/protover.c
+++ b/src/or/protover.c
@@ -34,6 +34,7 @@ static int protocol_list_contains(const smartlist_t *protos,
protocol_type_t pr, uint32_t ver);
/** Mapping between protocol type string and protocol type. */
+/// C_RUST_COUPLED: src/rust/protover/protover.rs `PROTOCOL_NAMES`
static const struct {
protocol_type_t protover_type;
const char *name;
@@ -95,7 +96,7 @@ str_to_protocol_type(const char *s, protocol_type_t *pr_out)
* Release all space held by a single proto_entry_t structure
*/
STATIC void
-proto_entry_free(proto_entry_t *entry)
+proto_entry_free_(proto_entry_t *entry)
{
if (!entry)
return;
@@ -282,8 +283,45 @@ protocol_list_supports_protocol(const char *list, protocol_type_t tp,
return contains;
}
+/**
+ * Return true iff "list" encodes a protocol list that includes support for
+ * the indicated protocol and version, or some later version.
+ */
+int
+protocol_list_supports_protocol_or_later(const char *list,
+ protocol_type_t tp,
+ uint32_t version)
+{
+ /* NOTE: This is a pretty inefficient implementation. If it ever shows
+ * up in profiles, we should memoize it.
+ */
+ smartlist_t *protocols = parse_protocol_list(list);
+ if (!protocols) {
+ return 0;
+ }
+ const char *pr_name = protocol_type_to_str(tp);
+
+ int contains = 0;
+ SMARTLIST_FOREACH_BEGIN(protocols, proto_entry_t *, proto) {
+ if (strcasecmp(proto->name, pr_name))
+ continue;
+ SMARTLIST_FOREACH_BEGIN(proto->ranges, const proto_range_t *, range) {
+ if (range->high >= version) {
+ contains = 1;
+ goto found;
+ }
+ } SMARTLIST_FOREACH_END(range);
+ } SMARTLIST_FOREACH_END(proto);
+
+ found:
+ SMARTLIST_FOREACH(protocols, proto_entry_t *, ent, proto_entry_free(ent));
+ smartlist_free(protocols);
+ return contains;
+}
+
/** Return the canonical string containing the list of protocols
* that we support. */
+/// C_RUST_COUPLED: src/rust/protover/protover.rs `SUPPORTED_PROTOCOLS`
const char *
protover_get_supported_protocols(void)
{
@@ -367,6 +405,8 @@ encode_protocol_list(const smartlist_t *sl)
/* We treat any protocol list with more than this many subprotocols in it
* as a DoS attempt. */
+/// C_RUST_COUPLED: src/rust/protover/protover.rs
+/// `MAX_PROTOCOLS_TO_EXPAND`
static const int MAX_PROTOCOLS_TO_EXPAND = (1<<16);
/** Voting helper: Given a list of proto_entry_t, return a newly allocated
@@ -693,9 +733,15 @@ protocol_list_contains(const smartlist_t *protos,
* Note that this is only used to infer protocols for Tor versions that
* can't declare their own.
**/
+/// C_RUST_COUPLED: src/rust/protover/protover.rs `compute_for_old_tor`
const char *
protover_compute_for_old_tor(const char *version)
{
+ if (version == NULL) {
+ /* No known version; guess the oldest series that is still supported. */
+ version = "0.2.5.15";
+ }
+
if (tor_version_as_new_as(version,
FIRST_TOR_VERSION_TO_ADVERTISE_PROTOCOLS)) {
return "";
@@ -737,5 +783,5 @@ protover_free_all(void)
}
}
-#endif
+#endif /* !defined(HAVE_RUST) */
diff --git a/src/or/protover.h b/src/or/protover.h
index 7f1938e0c9..477274e293 100644
--- a/src/or/protover.h
+++ b/src/or/protover.h
@@ -15,6 +15,8 @@
* descriptors. Authorities should use this to decide whether to
* guess proto lines. */
/* This is a guess. */
+/// C_RUST_COUPLED: src/rust/protover/protover.rs
+/// `FIRST_TOR_VERSION_TO_ADVERTISE_PROTOCOLS`
#define FIRST_TOR_VERSION_TO_ADVERTISE_PROTOCOLS "0.2.9.3-alpha"
/** The protover version number that signifies HSDir support for HSv3 */
@@ -25,6 +27,8 @@
#define PROTOVER_HS_RENDEZVOUS_POINT_V3 2
/** List of recognized subprotocols. */
+/// C_RUST_COUPLED: src/rust/protover/ffi.rs `translate_to_rust`
+/// C_RUST_COUPLED: src/rust/protover/protover.rs `Proto`
typedef enum protocol_type_t {
PRT_LINK,
PRT_LINKAUTH,
@@ -47,6 +51,9 @@ char *protover_compute_vote(const smartlist_t *list_of_proto_strings,
const char *protover_compute_for_old_tor(const char *version);
int protocol_list_supports_protocol(const char *list, protocol_type_t tp,
uint32_t version);
+int protocol_list_supports_protocol_or_later(const char *list,
+ protocol_type_t tp,
+ uint32_t version);
void protover_free_all(void);
@@ -75,9 +82,11 @@ STATIC smartlist_t *parse_protocol_list(const char *s);
STATIC char *encode_protocol_list(const smartlist_t *sl);
STATIC const char *protocol_type_to_str(protocol_type_t pr);
STATIC int str_to_protocol_type(const char *s, protocol_type_t *pr_out);
-STATIC void proto_entry_free(proto_entry_t *entry);
+STATIC void proto_entry_free_(proto_entry_t *entry);
+#endif /* !defined(HAVE_RUST) && defined(TOR_UNIT_TESTS) */
-#endif
+#define proto_entry_free(entry) \
+ FREE_AND_NULL(proto_entry_t, proto_entry_free_, (entry))
#endif /* defined(PROTOVER_PRIVATE) */
diff --git a/src/or/protover_rust.c b/src/or/protover_rust.c
index 0c409b1681..26e21cc1c5 100644
--- a/src/or/protover_rust.c
+++ b/src/or/protover_rust.c
@@ -15,5 +15,5 @@
/* Define for compatibility, used in main.c */
void protover_free_all(void) {}
-#endif
+#endif /* defined(HAVE_RUST) */
diff --git a/src/or/relay.c b/src/or/relay.c
index 09f70793d3..f6528c6ea5 100644
--- a/src/or/relay.c
+++ b/src/or/relay.c
@@ -1158,7 +1158,7 @@ connected_cell_parse(const relay_header_t *rh, const cell_t *cell,
/** Drop all storage held by <b>addr</b>. */
STATIC void
-address_ttl_free(address_ttl_t *addr)
+address_ttl_free_(address_ttl_t *addr)
{
if (!addr)
return;
@@ -2425,7 +2425,7 @@ packed_cell_new(void)
/** Return a packed cell used outside by channel_t lower layer */
void
-packed_cell_free(packed_cell_t *cell)
+packed_cell_free_(packed_cell_t *cell)
{
if (!cell)
return;
@@ -2482,7 +2482,7 @@ cell_queue_append_packed_copy(circuit_t *circ, cell_queue_t *queue,
(void)exitward;
(void)use_stats;
- copy->inserted_time = (uint32_t) monotime_coarse_absolute_msec();
+ copy->inserted_timestamp = monotime_coarse_get_stamp();
cell_queue_append(queue, copy);
}
@@ -2746,7 +2746,13 @@ channel_flush_from_first_active_circuit, (channel_t *chan, int max))
/* this code is duplicated from some of the logic below. Ugly! XXXX */
tor_assert(destroy_queue->n > 0);
cell = cell_queue_pop(destroy_queue);
- channel_write_packed_cell(chan, cell);
+ /* Send the DESTROY cell. It is very unlikely that this fails but just
+ * in case, get rid of the channel. */
+ if (channel_write_packed_cell(chan, cell) < 0) {
+ /* The cell has been freed. */
+ channel_mark_for_close(chan);
+ continue;
+ }
/* Update the cmux destroy counter */
circuitmux_notify_xmit_destroy(cmux);
cell = NULL;
@@ -2789,9 +2795,10 @@ channel_flush_from_first_active_circuit, (channel_t *chan, int max))
/* Calculate the exact time that this cell has spent in the queue. */
if (get_options()->CellStatistics ||
get_options()->TestingEnableCellStatsEvent) {
- uint32_t msec_waiting;
- uint32_t msec_now = (uint32_t)monotime_coarse_absolute_msec();
- msec_waiting = msec_now - cell->inserted_time;
+ uint32_t timestamp_now = monotime_coarse_get_stamp();
+ uint32_t msec_waiting =
+ (uint32_t) monotime_coarse_stamp_units_to_approx_msec(
+ timestamp_now - cell->inserted_timestamp);
if (get_options()->CellStatistics && !CIRCUIT_IS_ORIGIN(circ)) {
or_circ = TO_OR_CIRCUIT(circ);
@@ -2822,8 +2829,13 @@ channel_flush_from_first_active_circuit, (channel_t *chan, int max))
DIRREQ_TUNNELED,
DIRREQ_CIRC_QUEUE_FLUSHED);
- /* Now send the cell */
- channel_write_packed_cell(chan, cell);
+ /* Now send the cell. It is very unlikely that this fails but just in
+ * case, get rid of the channel. */
+ if (channel_write_packed_cell(chan, cell) < 0) {
+ /* The cell has been freed at this point. */
+ channel_mark_for_close(chan);
+ continue;
+ }
cell = NULL;
/*
@@ -2858,22 +2870,13 @@ channel_flush_from_first_active_circuit, (channel_t *chan, int max))
return n_flushed;
}
-#if 0
-/** Indicate the current preferred cap for middle circuits; zero disables
- * the cap. Right now it's just a constant, ORCIRC_MAX_MIDDLE_CELLS, but
- * the logic in append_cell_to_circuit_queue() is written to be correct
- * if we want to base it on a consensus param or something that might change
- * in the future.
- */
-static int
-get_max_middle_cells(void)
-{
- return ORCIRC_MAX_MIDDLE_CELLS;
-}
-#endif /* 0 */
-
/** Add <b>cell</b> to the queue of <b>circ</b> writing to <b>chan</b>
- * transmitting in <b>direction</b>. */
+ * transmitting in <b>direction</b>.
+ *
+ * The given <b>cell</b> is copied over the circuit queue so the caller must
+ * cleanup the memory.
+ *
+ * This function is part of the fast path. */
void
append_cell_to_circuit_queue(circuit_t *circ, channel_t *chan,
cell_t *cell, cell_direction_t direction,
@@ -2882,10 +2885,6 @@ append_cell_to_circuit_queue(circuit_t *circ, channel_t *chan,
or_circuit_t *orcirc = NULL;
cell_queue_t *queue;
int streams_blocked;
-#if 0
- uint32_t tgt_max_middle_cells, p_len, n_len, tmp, hard_max_middle_cells;
-#endif
-
int exitward;
if (circ->marked_for_close)
return;
@@ -2900,93 +2899,14 @@ append_cell_to_circuit_queue(circuit_t *circ, channel_t *chan,
streams_blocked = circ->streams_blocked_on_p_chan;
}
- /*
- * Disabling this for now because of a possible guard discovery attack
- */
-#if 0
- /* Are we a middle circuit about to exceed ORCIRC_MAX_MIDDLE_CELLS? */
- if ((circ->n_chan != NULL) && CIRCUIT_IS_ORCIRC(circ)) {
- orcirc = TO_OR_CIRCUIT(circ);
- if (orcirc->p_chan) {
- /* We are a middle circuit if we have both n_chan and p_chan */
- /* We'll need to know the current preferred maximum */
- tgt_max_middle_cells = get_max_middle_cells();
- if (tgt_max_middle_cells > 0) {
- /* Do we need to initialize middle_max_cells? */
- if (orcirc->max_middle_cells == 0) {
- orcirc->max_middle_cells = tgt_max_middle_cells;
- } else {
- if (tgt_max_middle_cells > orcirc->max_middle_cells) {
- /* If we want to increase the cap, we can do so right away */
- orcirc->max_middle_cells = tgt_max_middle_cells;
- } else if (tgt_max_middle_cells < orcirc->max_middle_cells) {
- /*
- * If we're shrinking the cap, we can't shrink past either queue;
- * compare tgt_max_middle_cells rather than tgt_max_middle_cells *
- * ORCIRC_MAX_MIDDLE_KILL_THRESH so the queues don't shrink enough
- * to generate spurious warnings, either.
- */
- n_len = circ->n_chan_cells.n;
- p_len = orcirc->p_chan_cells.n;
- tmp = tgt_max_middle_cells;
- if (tmp < n_len) tmp = n_len;
- if (tmp < p_len) tmp = p_len;
- orcirc->max_middle_cells = tmp;
- }
- /* else no change */
- }
- } else {
- /* tgt_max_middle_cells == 0 indicates we should disable the cap */
- orcirc->max_middle_cells = 0;
- }
-
- /* Now we know orcirc->max_middle_cells is set correctly */
- if (orcirc->max_middle_cells > 0) {
- hard_max_middle_cells =
- (uint32_t)(((double)orcirc->max_middle_cells) *
- ORCIRC_MAX_MIDDLE_KILL_THRESH);
-
- if ((unsigned)queue->n + 1 >= hard_max_middle_cells) {
- /* Queueing this cell would put queue over the kill theshold */
- log_warn(LD_CIRC,
- "Got a cell exceeding the hard cap of %u in the "
- "%s direction on middle circ ID %u on chan ID "
- U64_FORMAT "; killing the circuit.",
- hard_max_middle_cells,
- (direction == CELL_DIRECTION_OUT) ? "n" : "p",
- (direction == CELL_DIRECTION_OUT) ?
- circ->n_circ_id : orcirc->p_circ_id,
- U64_PRINTF_ARG(
- (direction == CELL_DIRECTION_OUT) ?
- circ->n_chan->global_identifier :
- orcirc->p_chan->global_identifier));
- circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT);
- return;
- } else if ((unsigned)queue->n + 1 == orcirc->max_middle_cells) {
- /* Only use ==, not >= for this test so we don't spam the log */
- log_warn(LD_CIRC,
- "While trying to queue a cell, reached the soft cap of %u "
- "in the %s direction on middle circ ID %u "
- "on chan ID " U64_FORMAT ".",
- orcirc->max_middle_cells,
- (direction == CELL_DIRECTION_OUT) ? "n" : "p",
- (direction == CELL_DIRECTION_OUT) ?
- circ->n_circ_id : orcirc->p_circ_id,
- U64_PRINTF_ARG(
- (direction == CELL_DIRECTION_OUT) ?
- circ->n_chan->global_identifier :
- orcirc->p_chan->global_identifier));
- }
- }
- }
- }
-#endif /* 0 */
-
+ /* Very important that we copy to the circuit queue because all calls to
+ * this function use the stack for the cell memory. */
cell_queue_append_packed_copy(circ, queue, exitward, cell,
chan->wide_circ_ids, 1);
+ /* Check and run the OOM if needed. */
if (PREDICT_UNLIKELY(cell_queues_check_size())) {
- /* We ran the OOM handler */
+ /* We ran the OOM handler which might have closed this circuit. */
if (circ->marked_for_close)
return;
}
diff --git a/src/or/relay.h b/src/or/relay.h
index 2412dcb23c..95b8beb3b5 100644
--- a/src/or/relay.h
+++ b/src/or/relay.h
@@ -51,7 +51,9 @@ size_t packed_cell_mem_cost(void);
int have_been_under_memory_pressure(void);
/* For channeltls.c */
-void packed_cell_free(packed_cell_t *cell);
+void packed_cell_free_(packed_cell_t *cell);
+#define packed_cell_free(cell) \
+ FREE_AND_NULL(packed_cell_t, packed_cell_free_, (cell))
void cell_queue_init(cell_queue_t *queue);
void cell_queue_clear(cell_queue_t *queue);
@@ -94,7 +96,9 @@ typedef struct address_ttl_s {
char *hostname;
int ttl;
} address_ttl_t;
-STATIC void address_ttl_free(address_ttl_t *addr);
+STATIC void address_ttl_free_(address_ttl_t *addr);
+#define address_ttl_free(addr) \
+ FREE_AND_NULL(address_ttl_t, address_ttl_free_, (addr))
STATIC int resolved_cell_parse(const cell_t *cell, const relay_header_t *rh,
smartlist_t *addresses_out, int *errcode_out);
STATIC int connection_edge_process_resolved_cell(edge_connection_t *conn,
diff --git a/src/or/rendcache.c b/src/or/rendcache.c
index b98b2bccfa..6f56df6718 100644
--- a/src/or/rendcache.c
+++ b/src/or/rendcache.c
@@ -120,7 +120,7 @@ rend_cache_increment_allocation(size_t n)
/** Helper: free a rend cache failure intro object. */
STATIC void
-rend_cache_failure_intro_entry_free(rend_cache_failure_intro_t *entry)
+rend_cache_failure_intro_entry_free_(rend_cache_failure_intro_t *entry)
{
if (entry == NULL) {
return;
@@ -129,9 +129,9 @@ rend_cache_failure_intro_entry_free(rend_cache_failure_intro_t *entry)
}
static void
-rend_cache_failure_intro_entry_free_(void *entry)
+rend_cache_failure_intro_entry_free_void(void *entry)
{
- rend_cache_failure_intro_entry_free(entry);
+ rend_cache_failure_intro_entry_free_(entry);
}
/** Allocate a rend cache failure intro object and return it. <b>failure</b>
@@ -147,7 +147,7 @@ rend_cache_failure_intro_entry_new(rend_intro_point_failure_t failure)
/** Helper: free a rend cache failure object. */
STATIC void
-rend_cache_failure_entry_free(rend_cache_failure_t *entry)
+rend_cache_failure_entry_free_(rend_cache_failure_t *entry)
{
if (entry == NULL) {
return;
@@ -155,7 +155,7 @@ rend_cache_failure_entry_free(rend_cache_failure_t *entry)
/* Free and remove every intro failure object. */
digestmap_free(entry->intro_failures,
- rend_cache_failure_intro_entry_free_);
+ rend_cache_failure_intro_entry_free_void);
tor_free(entry);
}
@@ -163,9 +163,9 @@ rend_cache_failure_entry_free(rend_cache_failure_t *entry)
/** Helper: deallocate a rend_cache_failure_t. (Used with strmap_free(),
* which requires a function pointer whose argument is void*). */
STATIC void
-rend_cache_failure_entry_free_(void *entry)
+rend_cache_failure_entry_free_void(void *entry)
{
- rend_cache_failure_entry_free(entry);
+ rend_cache_failure_entry_free_(entry);
}
/** Allocate a rend cache failure object and return it. This function can
@@ -201,7 +201,7 @@ rend_cache_failure_remove(rend_service_descriptor_t *desc)
/** Helper: free storage held by a single service descriptor cache entry. */
STATIC void
-rend_cache_entry_free(rend_cache_entry_t *e)
+rend_cache_entry_free_(rend_cache_entry_t *e)
{
if (!e)
return;
@@ -217,19 +217,19 @@ rend_cache_entry_free(rend_cache_entry_t *e)
/** Helper: deallocate a rend_cache_entry_t. (Used with strmap_free(), which
* requires a function pointer whose argument is void*). */
static void
-rend_cache_entry_free_(void *p)
+rend_cache_entry_free_void(void *p)
{
- rend_cache_entry_free(p);
+ rend_cache_entry_free_(p);
}
/** Free all storage held by the service descriptor cache. */
void
rend_cache_free_all(void)
{
- strmap_free(rend_cache, rend_cache_entry_free_);
- digestmap_free(rend_cache_v2_dir, rend_cache_entry_free_);
- strmap_free(rend_cache_local_service, rend_cache_entry_free_);
- strmap_free(rend_cache_failure, rend_cache_failure_entry_free_);
+ strmap_free(rend_cache, rend_cache_entry_free_void);
+ digestmap_free(rend_cache_v2_dir, rend_cache_entry_free_void);
+ strmap_free(rend_cache_local_service, rend_cache_entry_free_void);
+ strmap_free(rend_cache_failure, rend_cache_failure_entry_free_void);
rend_cache = NULL;
rend_cache_v2_dir = NULL;
rend_cache_local_service = NULL;
@@ -304,7 +304,7 @@ rend_cache_purge(void)
{
if (rend_cache) {
log_info(LD_REND, "Purging HS v2 descriptor cache");
- strmap_free(rend_cache, rend_cache_entry_free_);
+ strmap_free(rend_cache, rend_cache_entry_free_void);
}
rend_cache = strmap_new();
}
@@ -316,7 +316,7 @@ rend_cache_failure_purge(void)
{
if (rend_cache_failure) {
log_info(LD_REND, "Purging HS v2 failure cache");
- strmap_free(rend_cache_failure, rend_cache_failure_entry_free_);
+ strmap_free(rend_cache_failure, rend_cache_failure_entry_free_void);
}
rend_cache_failure = strmap_new();
}
diff --git a/src/or/rendcache.h b/src/or/rendcache.h
index 5b13eadfa1..66e9785645 100644
--- a/src/or/rendcache.h
+++ b/src/or/rendcache.h
@@ -90,10 +90,18 @@ void rend_cache_increment_allocation(size_t n);
#ifdef RENDCACHE_PRIVATE
STATIC size_t rend_cache_entry_allocation(const rend_cache_entry_t *e);
-STATIC void rend_cache_entry_free(rend_cache_entry_t *e);
-STATIC void rend_cache_failure_intro_entry_free(rend_cache_failure_intro_t
- *entry);
-STATIC void rend_cache_failure_entry_free(rend_cache_failure_t *entry);
+STATIC void rend_cache_entry_free_(rend_cache_entry_t *e);
+#define rend_cache_entry_free(e) \
+ FREE_AND_NULL(rend_cache_entry_t, rend_cache_entry_free_, (e))
+STATIC void rend_cache_failure_intro_entry_free_(rend_cache_failure_intro_t
+ *entry);
+#define rend_cache_failure_intro_entry_free(e) \
+ FREE_AND_NULL(rend_cache_failure_intro_t, \
+ rend_cache_failure_intro_entry_free_, (e))
+STATIC void rend_cache_failure_entry_free_(rend_cache_failure_t *entry);
+#define rend_cache_failure_entry_free(e) \
+ FREE_AND_NULL(rend_cache_failure_t, \
+ rend_cache_failure_entry_free_, (e))
STATIC int cache_failure_intro_lookup(const uint8_t *identity,
const char *service_id,
rend_cache_failure_intro_t
@@ -108,7 +116,7 @@ STATIC void cache_failure_intro_add(const uint8_t *identity,
STATIC void validate_intro_point_failure(const rend_service_descriptor_t *desc,
const char *service_id);
-STATIC void rend_cache_failure_entry_free_(void *entry);
+STATIC void rend_cache_failure_entry_free_void(void *entry);
#ifdef TOR_UNIT_TESTS
extern strmap_t *rend_cache;
diff --git a/src/or/rendclient.c b/src/or/rendclient.c
index 3274819241..07fa33306d 100644
--- a/src/or/rendclient.c
+++ b/src/or/rendclient.c
@@ -459,7 +459,8 @@ directory_get_from_hs_dir(const char *desc_id,
hs_dir = hs_pick_hsdir(responsible_dirs, desc_id_base32);
if (!hs_dir) {
/* No suitable hs dir can be found, stop right now. */
- control_event_hs_descriptor_failed(rend_query, NULL, "QUERY_NO_HSDIR");
+ control_event_hsv2_descriptor_failed(rend_query, NULL,
+ "QUERY_NO_HSDIR");
control_event_hs_descriptor_content(rend_data_get_address(rend_query),
desc_id_base32, NULL, NULL);
return 0;
@@ -482,7 +483,7 @@ directory_get_from_hs_dir(const char *desc_id,
REND_DESC_COOKIE_LEN,
0)<0) {
log_warn(LD_BUG, "Could not base64-encode descriptor cookie.");
- control_event_hs_descriptor_failed(rend_query, hsdir_fp, "BAD_DESC");
+ control_event_hsv2_descriptor_failed(rend_query, hsdir_fp, "BAD_DESC");
control_event_hs_descriptor_content(rend_data_get_address(rend_query),
desc_id_base32, hsdir_fp, NULL);
return 0;
@@ -515,9 +516,10 @@ directory_get_from_hs_dir(const char *desc_id,
(rend_data->auth_type == REND_NO_AUTH ? "[none]" :
escaped_safe_str_client(descriptor_cookie_base64)),
routerstatus_describe(hs_dir));
- control_event_hs_descriptor_requested(rend_query,
+ control_event_hs_descriptor_requested(rend_data->onion_address,
+ rend_data->auth_type,
hs_dir->identity_digest,
- desc_id_base32);
+ desc_id_base32, NULL);
return 1;
}
@@ -1102,18 +1104,22 @@ rend_client_lookup_service_authorization(const char *onion_address)
return strmap_get(auth_hid_servs, onion_address);
}
+#define rend_service_authorization_free(val) \
+ FREE_AND_NULL(rend_service_authorization_t, \
+ rend_service_authorization_free_, (val))
+
/** Helper: Free storage held by rend_service_authorization_t. */
static void
-rend_service_authorization_free(rend_service_authorization_t *auth)
+rend_service_authorization_free_(rend_service_authorization_t *auth)
{
tor_free(auth);
}
/** Helper for strmap_free. */
static void
-rend_service_authorization_strmap_item_free(void *service_auth)
+rend_service_authorization_free_void(void *service_auth)
{
- rend_service_authorization_free(service_auth);
+ rend_service_authorization_free_(service_auth);
}
/** Release all the storage held in auth_hid_servs.
@@ -1124,7 +1130,7 @@ rend_service_authorization_free_all(void)
if (!auth_hid_servs) {
return;
}
- strmap_free(auth_hid_servs, rend_service_authorization_strmap_item_free);
+ strmap_free(auth_hid_servs, rend_service_authorization_free_void);
auth_hid_servs = NULL;
}
@@ -1199,7 +1205,7 @@ rend_parse_service_authorization(const or_options_t *options,
rend_service_authorization_free_all();
auth_hid_servs = parsed;
} else {
- strmap_free(parsed, rend_service_authorization_strmap_item_free);
+ strmap_free(parsed, rend_service_authorization_free_void);
}
return res;
}
diff --git a/src/or/rendcommon.c b/src/or/rendcommon.c
index 458a90058f..230da4be5c 100644
--- a/src/or/rendcommon.c
+++ b/src/or/rendcommon.c
@@ -37,7 +37,7 @@ rend_cmp_service_ids(const char *one, const char *two)
/** Free the storage held by the service descriptor <b>desc</b>.
*/
void
-rend_service_descriptor_free(rend_service_descriptor_t *desc)
+rend_service_descriptor_free_(rend_service_descriptor_t *desc)
{
if (!desc)
return;
@@ -419,7 +419,7 @@ rend_desc_v2_is_parsable(rend_encoded_v2_service_descriptor_t *desc)
/** Free the storage held by an encoded v2 service descriptor. */
void
-rend_encoded_v2_service_descriptor_free(
+rend_encoded_v2_service_descriptor_free_(
rend_encoded_v2_service_descriptor_t *desc)
{
if (!desc)
@@ -430,7 +430,7 @@ rend_encoded_v2_service_descriptor_free(
/** Free the storage held by an introduction point info. */
void
-rend_intro_point_free(rend_intro_point_t *intro)
+rend_intro_point_free_(rend_intro_point_t *intro)
{
if (!intro)
return;
diff --git a/src/or/rendcommon.h b/src/or/rendcommon.h
index c35d7272fd..1ed0f62609 100644
--- a/src/or/rendcommon.h
+++ b/src/or/rendcommon.h
@@ -24,11 +24,19 @@ void rend_process_relay_cell(circuit_t *circ, const crypt_path_t *layer_hint,
int command, size_t length,
const uint8_t *payload);
-void rend_service_descriptor_free(rend_service_descriptor_t *desc);
+void rend_service_descriptor_free_(rend_service_descriptor_t *desc);
+#define rend_service_descriptor_free(desc) \
+ FREE_AND_NULL(rend_service_descriptor_t, rend_service_descriptor_free_, \
+ (desc))
int rend_get_service_id(crypto_pk_t *pk, char *out);
-void rend_encoded_v2_service_descriptor_free(
+void rend_encoded_v2_service_descriptor_free_(
rend_encoded_v2_service_descriptor_t *desc);
-void rend_intro_point_free(rend_intro_point_t *intro);
+#define rend_encoded_v2_service_descriptor_free(desc) \
+ FREE_AND_NULL(rend_encoded_v2_service_descriptor_t, \
+ rend_encoded_v2_service_descriptor_free_, (desc))
+void rend_intro_point_free_(rend_intro_point_t *intro);
+#define rend_intro_point_free(intro) \
+ FREE_AND_NULL(rend_intro_point_t, rend_intro_point_free_, (intro))
int rend_valid_v2_service_id(const char *query);
int rend_valid_descriptor_id(const char *query);
diff --git a/src/or/rendservice.c b/src/or/rendservice.c
index 60234a5c1f..06166d7cf3 100644
--- a/src/or/rendservice.c
+++ b/src/or/rendservice.c
@@ -157,7 +157,7 @@ rend_num_services(void)
/** Helper: free storage held by a single service authorized client entry. */
void
-rend_authorized_client_free(rend_authorized_client_t *client)
+rend_authorized_client_free_(rend_authorized_client_t *client)
{
if (!client)
return;
@@ -172,15 +172,15 @@ rend_authorized_client_free(rend_authorized_client_t *client)
/** Helper for strmap_free. */
static void
-rend_authorized_client_strmap_item_free(void *authorized_client)
+rend_authorized_client_free_void(void *authorized_client)
{
- rend_authorized_client_free(authorized_client);
+ rend_authorized_client_free_(authorized_client);
}
/** Release the storage held by <b>service</b>.
*/
STATIC void
-rend_service_free(rend_service_t *service)
+rend_service_free_(rend_service_t *service)
{
if (!service)
return;
@@ -470,7 +470,7 @@ rend_service_parse_port_config(const char *string, const char *sep,
/** Release all storage held in a rend_service_port_config_t. */
void
-rend_service_port_config_free(rend_service_port_config_t *p)
+rend_service_port_config_free_(rend_service_port_config_t *p)
{
tor_free(p);
}
@@ -847,9 +847,9 @@ rend_config_service(const config_line_t *line_,
* after calling this routine, and may assume that correct cleanup has
* been done on failure.
*
- * Return an appropriate rend_service_add_ephemeral_status_t.
+ * Return an appropriate hs_service_add_ephemeral_status_t.
*/
-rend_service_add_ephemeral_status_t
+hs_service_add_ephemeral_status_t
rend_service_add_ephemeral(crypto_pk_t *pk,
smartlist_t *ports,
int max_streams_per_circuit,
@@ -1675,7 +1675,7 @@ rend_service_load_auth_keys(rend_service_t *s, const char *hfname)
memwipe(client_keys_str, 0, strlen(client_keys_str));
tor_free(client_keys_str);
}
- strmap_free(parsed_clients, rend_authorized_client_strmap_item_free);
+ strmap_free(parsed_clients, rend_authorized_client_free_void);
if (cfname) {
memwipe(cfname, 0, strlen(cfname));
@@ -1829,6 +1829,7 @@ rend_service_receive_introduction(origin_circuit_t *circuit,
time_t now = time(NULL);
time_t elapsed;
int replay;
+ ssize_t keylen;
/* Do some initial validation and logging before we parse the cell */
if (circuit->base_.purpose != CIRCUIT_PURPOSE_S_INTRO) {
@@ -1903,9 +1904,10 @@ rend_service_receive_introduction(origin_circuit_t *circuit,
}
/* check for replay of PK-encrypted portion. */
+ keylen = crypto_pk_keysize(intro_key);
replay = replaycache_add_test_and_elapsed(
intro_point->accepted_intro_rsa_parts,
- parsed_req->ciphertext, parsed_req->ciphertext_len,
+ parsed_req->ciphertext, MIN(parsed_req->ciphertext_len, keylen),
&elapsed);
if (replay) {
@@ -2221,7 +2223,7 @@ find_rp_for_intro(const rend_intro_cell_t *intro,
* rend_service_parse_intro().
*/
void
-rend_service_free_intro(rend_intro_cell_t *request)
+rend_service_free_intro_(rend_intro_cell_t *request)
{
if (!request) {
return;
@@ -3574,7 +3576,7 @@ directory_post_to_hs_dir(rend_service_descriptor_t *renddesc,
"directories to post descriptors to.");
control_event_hs_descriptor_upload(service_id,
"UNKNOWN",
- "UNKNOWN");
+ "UNKNOWN", NULL);
goto done;
}
}
@@ -3629,7 +3631,7 @@ directory_post_to_hs_dir(rend_service_descriptor_t *renddesc,
hs_dir->or_port);
control_event_hs_descriptor_upload(service_id,
hs_dir->identity_digest,
- desc_id_base32);
+ desc_id_base32, NULL);
tor_free(hs_dir_ip);
/* Remember successful upload to this router for next time. */
if (!smartlist_contains_digest(successful_uploads,
@@ -3726,7 +3728,7 @@ upload_service_descriptor(rend_service_t *service)
}
/* Free memory for descriptors. */
for (i = 0; i < smartlist_len(descs); i++)
- rend_encoded_v2_service_descriptor_free(smartlist_get(descs, i));
+ rend_encoded_v2_service_descriptor_free_(smartlist_get(descs, i));
smartlist_clear(descs);
/* Update next upload time. */
if (seconds_valid - REND_TIME_PERIOD_OVERLAPPING_V2_DESCS
@@ -3757,7 +3759,7 @@ upload_service_descriptor(rend_service_t *service)
}
/* Free memory for descriptors. */
for (i = 0; i < smartlist_len(descs); i++)
- rend_encoded_v2_service_descriptor_free(smartlist_get(descs, i));
+ rend_encoded_v2_service_descriptor_free_(smartlist_get(descs, i));
smartlist_clear(descs);
}
}
@@ -3912,6 +3914,10 @@ remove_invalid_intro_points(rend_service_t *service,
log_info(LD_REND, "Expiring %s as intro point for %s.",
safe_str_client(extend_info_describe(intro->extend_info)),
safe_str_client(service->service_id));
+ /* We might have put it in the retry list if so, undo. */
+ if (retry_nodes) {
+ smartlist_remove(retry_nodes, intro);
+ }
smartlist_add(service->expiring_nodes, intro);
SMARTLIST_DEL_CURRENT(service->intro_nodes, intro);
/* Intro point is expired, we need a new one thus don't consider it
diff --git a/src/or/rendservice.h b/src/or/rendservice.h
index 5946e31861..88da7b8665 100644
--- a/src/or/rendservice.h
+++ b/src/or/rendservice.h
@@ -117,7 +117,9 @@ typedef struct rend_service_t {
int max_streams_close_circuit;
} rend_service_t;
-STATIC void rend_service_free(rend_service_t *service);
+STATIC void rend_service_free_(rend_service_t *service);
+#define rend_service_free(s) \
+ FREE_AND_NULL(rend_service_t, rend_service_free_, (s))
STATIC char *rend_service_sos_poison_path(const rend_service_t *service);
STATIC int rend_service_verify_single_onion_poison(
const rend_service_t *s,
@@ -160,7 +162,11 @@ int rend_service_receive_introduction(origin_circuit_t *circuit,
int rend_service_decrypt_intro(rend_intro_cell_t *request,
crypto_pk_t *key,
char **err_msg_out);
-void rend_service_free_intro(rend_intro_cell_t *request);
+void rend_service_free_intro_(rend_intro_cell_t *request);
+#define rend_service_free_intro(req) do { \
+ rend_service_free_intro_(req); \
+ (req) = NULL; \
+ } while (0)
rend_intro_cell_t * rend_service_begin_parse_intro(const uint8_t *request,
size_t request_len,
uint8_t type,
@@ -183,20 +189,17 @@ void rend_service_init(void);
rend_service_port_config_t *rend_service_parse_port_config(const char *string,
const char *sep,
char **err_msg_out);
-void rend_service_port_config_free(rend_service_port_config_t *p);
-
-void rend_authorized_client_free(rend_authorized_client_t *client);
-
-/** Return value from rend_service_add_ephemeral. */
-typedef enum {
- RSAE_BADAUTH = -5, /**< Invalid auth_type/auth_clients */
- RSAE_BADVIRTPORT = -4, /**< Invalid VIRTPORT/TARGET(s) */
- RSAE_ADDREXISTS = -3, /**< Onion address collision */
- RSAE_BADPRIVKEY = -2, /**< Invalid public key */
- RSAE_INTERNAL = -1, /**< Internal error */
- RSAE_OKAY = 0 /**< Service added as expected */
-} rend_service_add_ephemeral_status_t;
-rend_service_add_ephemeral_status_t rend_service_add_ephemeral(crypto_pk_t *pk,
+void rend_service_port_config_free_(rend_service_port_config_t *p);
+#define rend_service_port_config_free(p) \
+ FREE_AND_NULL(rend_service_port_config_t, rend_service_port_config_free_, \
+ (p))
+
+void rend_authorized_client_free_(rend_authorized_client_t *client);
+#define rend_authorized_client_free(client) \
+ FREE_AND_NULL(rend_authorized_client_t, rend_authorized_client_free_, \
+ (client))
+
+hs_service_add_ephemeral_status_t rend_service_add_ephemeral(crypto_pk_t *pk,
smartlist_t *ports,
int max_streams_per_circuit,
int max_streams_close_circuit,
diff --git a/src/or/rephist.c b/src/or/rephist.c
index 51e800bc31..de4635ee59 100644
--- a/src/or/rephist.c
+++ b/src/or/rephist.c
@@ -1239,9 +1239,9 @@ rep_hist_load_mtbf_data(time_t now)
* totals? */
#define NUM_SECS_ROLLING_MEASURE 10
/** How large are the intervals for which we track and report bandwidth use? */
-#define NUM_SECS_BW_SUM_INTERVAL (4*60*60)
+#define NUM_SECS_BW_SUM_INTERVAL (24*60*60)
/** How far in the past do we remember and publish bandwidth use? */
-#define NUM_SECS_BW_SUM_IS_VALID (24*60*60)
+#define NUM_SECS_BW_SUM_IS_VALID (5*24*60*60)
/** How many bandwidth usage intervals do we remember? (derived) */
#define NUM_TOTALS (NUM_SECS_BW_SUM_IS_VALID/NUM_SECS_BW_SUM_INTERVAL)
@@ -1358,9 +1358,12 @@ bw_array_new(void)
return b;
}
+#define bw_array_free(val) \
+ FREE_AND_NULL(bw_array_t, bw_array_free_, (val))
+
/** Free storage held by bandwidth array <b>b</b>. */
static void
-bw_array_free(bw_array_t *b)
+bw_array_free_(bw_array_t *b)
{
if (!b) {
return;
@@ -1883,7 +1886,7 @@ predicted_ports_init(void)
* be used.
*/
static void
-predicted_ports_free(void)
+predicted_ports_free_all(void)
{
rephist_total_alloc -=
smartlist_len(predicted_ports_list)*sizeof(predicted_port_t);
@@ -2828,7 +2831,7 @@ HT_GENERATE2(bidimap, bidi_map_entry_t, node, bidi_map_ent_hash,
/* DOCDOC bidi_map_free */
static void
-bidi_map_free(void)
+bidi_map_free_all(void)
{
bidi_map_entry_t **ptr, **next, *ent;
for (ptr = HT_START(bidimap, &bidi_map); ptr; ptr = next) {
@@ -2848,7 +2851,7 @@ rep_hist_reset_conn_stats(time_t now)
mostly_read = 0;
mostly_written = 0;
both_read_and_written = 0;
- bidi_map_free();
+ bidi_map_free_all();
}
/** Stop collecting connection stats in a way that we can re-start doing
@@ -3037,9 +3040,12 @@ hs_stats_new(void)
return new_hs_stats;
}
+#define hs_stats_free(val) \
+ FREE_AND_NULL(hs_stats_t, hs_stats_free_, (val))
+
/** Free an hs_stats_t structure. */
static void
-hs_stats_free(hs_stats_t *victim_hs_stats)
+hs_stats_free_(hs_stats_t *victim_hs_stats)
{
if (!victim_hs_stats) {
return;
@@ -3451,8 +3457,8 @@ rep_hist_free_all(void)
tor_free(exit_bytes_read);
tor_free(exit_bytes_written);
tor_free(exit_streams);
- predicted_ports_free();
- bidi_map_free();
+ predicted_ports_free_all();
+ bidi_map_free_all();
if (circuits_for_buffer_stats) {
SMARTLIST_FOREACH(circuits_for_buffer_stats, circ_buffer_stats_t *, s,
diff --git a/src/or/replaycache.c b/src/or/replaycache.c
index 3d42deb90a..4a56bfd7d4 100644
--- a/src/or/replaycache.c
+++ b/src/or/replaycache.c
@@ -28,7 +28,7 @@
*/
void
-replaycache_free(replaycache_t *r)
+replaycache_free_(replaycache_t *r)
{
if (!r) {
log_info(LD_BUG, "replaycache_free() called on NULL");
diff --git a/src/or/replaycache.h b/src/or/replaycache.h
index 1cae3497ae..81a8d907fd 100644
--- a/src/or/replaycache.h
+++ b/src/or/replaycache.h
@@ -33,7 +33,9 @@ struct replaycache_s {
/* replaycache_t free/new */
-void replaycache_free(replaycache_t *r);
+void replaycache_free_(replaycache_t *r);
+#define replaycache_free(r) \
+ FREE_AND_NULL(replaycache_t, replaycache_free_, (r))
replaycache_t * replaycache_new(time_t horizon, time_t interval);
#ifdef REPLAYCACHE_PRIVATE
diff --git a/src/or/router.c b/src/or/router.c
index 8ad5d038ef..9c053cad46 100644
--- a/src/or/router.c
+++ b/src/or/router.c
@@ -174,7 +174,7 @@ expire_old_onion_keys(void)
tor_mutex_release(key_lock);
- fname = get_datadir_fname2("keys", "secret_onion_key.old");
+ fname = get_keydir_fname("secret_onion_key.old");
if (file_status(fname) == FN_FILE) {
if (tor_unlink(fname) != 0) {
log_warn(LD_FS, "Couldn't unlink old onion key file %s: %s",
@@ -183,7 +183,7 @@ expire_old_onion_keys(void)
}
tor_free(fname);
- fname = get_datadir_fname2("keys", "secret_onion_key_ntor.old");
+ fname = get_keydir_fname("secret_onion_key_ntor.old");
if (file_status(fname) == FN_FILE) {
if (tor_unlink(fname) != 0) {
log_warn(LD_FS, "Couldn't unlink old ntor onion key file %s: %s",
@@ -233,7 +233,7 @@ ntor_key_map_free_helper(void *arg)
}
/** Release all storage from a keymap returned by construct_ntor_key_map. */
void
-ntor_key_map_free(di_digest256_map_t *map)
+ntor_key_map_free_(di_digest256_map_t *map)
{
if (!map)
return;
@@ -378,8 +378,8 @@ rotate_onion_key(void)
or_state_t *state = get_or_state();
curve25519_keypair_t new_curve25519_keypair;
time_t now;
- fname = get_datadir_fname2("keys", "secret_onion_key");
- fname_prev = get_datadir_fname2("keys", "secret_onion_key.old");
+ fname = get_keydir_fname("secret_onion_key");
+ fname_prev = get_keydir_fname("secret_onion_key.old");
/* There isn't much point replacing an old key with an empty file */
if (file_status(fname) == FN_FILE) {
if (replace_file(fname, fname_prev))
@@ -399,8 +399,8 @@ rotate_onion_key(void)
}
tor_free(fname);
tor_free(fname_prev);
- fname = get_datadir_fname2("keys", "secret_onion_key_ntor");
- fname_prev = get_datadir_fname2("keys", "secret_onion_key_ntor.old");
+ fname = get_keydir_fname("secret_onion_key_ntor");
+ fname_prev = get_keydir_fname("secret_onion_key_ntor.old");
if (curve25519_keypair_generate(&new_curve25519_keypair, 1) < 0)
goto error;
/* There isn't much point replacing an old key with an empty file */
@@ -624,7 +624,7 @@ load_authority_keyset(int legacy, crypto_pk_t **key_out,
crypto_pk_t *signing_key = NULL;
authority_cert_t *parsed = NULL;
- fname = get_datadir_fname2("keys",
+ fname = get_keydir_fname(
legacy ? "legacy_signing_key" : "authority_signing_key");
signing_key = init_key_from_file(fname, 0, LOG_ERR, 0);
if (!signing_key) {
@@ -632,7 +632,7 @@ load_authority_keyset(int legacy, crypto_pk_t **key_out,
goto done;
}
tor_free(fname);
- fname = get_datadir_fname2("keys",
+ fname = get_keydir_fname(
legacy ? "legacy_certificate" : "authority_certificate");
cert = read_file_to_str(fname, 0, NULL);
if (!cert) {
@@ -932,22 +932,9 @@ init_keys(void)
}
if (init_keys_common() < 0)
return -1;
- /* Make sure DataDirectory exists, and is private. */
- cpd_check_t cpd_opts = CPD_CREATE;
- if (options->DataDirectoryGroupReadable)
- cpd_opts |= CPD_GROUP_READ;
- if (check_private_dir(options->DataDirectory, cpd_opts, options->User)) {
- log_err(LD_OR, "Can't create/check datadirectory %s",
- options->DataDirectory);
- return -1;
- }
- /* Check the key directory. */
- keydir = get_datadir_fname("keys");
- if (check_private_dir(keydir, CPD_CREATE, options->User)) {
- tor_free(keydir);
+
+ if (create_keys_directory(options) < 0)
return -1;
- }
- tor_free(keydir);
/* 1a. Read v3 directory authority key/cert information. */
memset(v3_digest, 0, sizeof(v3_digest));
@@ -971,7 +958,7 @@ init_keys(void)
}
/* 1b. Read identity key. Make it if none is found. */
- keydir = get_datadir_fname2("keys", "secret_id_key");
+ keydir = get_keydir_fname("secret_id_key");
log_info(LD_GENERAL,"Reading/making identity key \"%s\"...",keydir);
prkey = init_key_from_file(keydir, 1, LOG_ERR, 1);
tor_free(keydir);
@@ -999,7 +986,7 @@ init_keys(void)
return -1;
/* 2. Read onion key. Make it if none is found. */
- keydir = get_datadir_fname2("keys", "secret_onion_key");
+ keydir = get_keydir_fname("secret_onion_key");
log_info(LD_GENERAL,"Reading/making onion key \"%s\"...",keydir);
prkey = init_key_from_file(keydir, 1, LOG_ERR, 1);
tor_free(keydir);
@@ -1024,7 +1011,7 @@ init_keys(void)
}
}
- keydir = get_datadir_fname2("keys", "secret_onion_key.old");
+ keydir = get_keydir_fname("secret_onion_key.old");
if (!lastonionkey && file_status(keydir) == FN_FILE) {
/* Load keys from non-empty files only.
* Missing old keys won't be replaced with freshly generated keys. */
@@ -1037,14 +1024,14 @@ init_keys(void)
{
/* 2b. Load curve25519 onion keys. */
int r;
- keydir = get_datadir_fname2("keys", "secret_onion_key_ntor");
+ keydir = get_keydir_fname("secret_onion_key_ntor");
r = init_curve25519_keypair_from_file(&curve25519_onion_key,
keydir, 1, LOG_ERR, "onion");
tor_free(keydir);
if (r<0)
return -1;
- keydir = get_datadir_fname2("keys", "secret_onion_key_ntor.old");
+ keydir = get_keydir_fname("secret_onion_key_ntor.old");
if (tor_mem_is_zero((const char *)
last_curve25519_onion_key.pubkey.public_key,
CURVE25519_PUBKEY_LEN) &&
@@ -2513,7 +2500,7 @@ mark_my_descriptor_dirty(const char *reason)
/** How frequently will we republish our descriptor because of large (factor
* of 2) shifts in estimated bandwidth? Note: We don't use this constant
* if our previous bandwidth estimate was exactly 0. */
-#define MAX_BANDWIDTH_CHANGE_FREQ (20*60)
+#define MAX_BANDWIDTH_CHANGE_FREQ (3*60*60)
/** Check whether bandwidth has changed a lot since the last time we announced
* bandwidth. If so, mark our descriptor dirty. */
@@ -3698,6 +3685,7 @@ router_free_all(void)
crypto_pk_free(lastonionkey);
crypto_pk_free(server_identitykey);
crypto_pk_free(client_identitykey);
+
tor_mutex_free(key_lock);
routerinfo_free(desc_routerinfo);
extrainfo_free(desc_extrainfo);
diff --git a/src/or/router.h b/src/or/router.h
index 3351400911..696e983662 100644
--- a/src/or/router.h
+++ b/src/or/router.h
@@ -36,7 +36,9 @@ int get_onion_key_lifetime(void);
int get_onion_key_grace_period(void);
di_digest256_map_t *construct_ntor_key_map(void);
-void ntor_key_map_free(di_digest256_map_t *map);
+void ntor_key_map_free_(di_digest256_map_t *map);
+#define ntor_key_map_free(map) \
+ FREE_AND_NULL(di_digest256_map_t, ntor_key_map_free_, (map))
int router_initialize_tls_context(void);
int init_keys(void);
diff --git a/src/or/routerkeys.c b/src/or/routerkeys.c
index 7295c19653..af230f07bf 100644
--- a/src/or/routerkeys.c
+++ b/src/or/routerkeys.c
@@ -718,7 +718,7 @@ load_ed_keys(const or_options_t *options, time_t now)
/* First try to get the signing key to see how it is. */
{
char *fname =
- options_get_datadir_fname2(options, "keys", "ed25519_signing");
+ options_get_keydir_fname(options, "ed25519_signing");
sign = ed_key_init_from_file(
fname,
INIT_ED_KEY_NEEDCERT|
@@ -813,26 +813,15 @@ load_ed_keys(const or_options_t *options, time_t now)
flags |= INIT_ED_KEY_TRY_ENCRYPTED;
/* Check/Create the key directory */
- cpd_check_t cpd_opts = CPD_CREATE;
- if (options->DataDirectoryGroupReadable)
- cpd_opts |= CPD_GROUP_READ;
- if (check_private_dir(options->DataDirectory, cpd_opts, options->User)) {
- log_err(LD_OR, "Can't create/check datadirectory %s",
- options->DataDirectory);
- goto err;
- }
- char *fname = get_datadir_fname("keys");
- if (check_private_dir(fname, CPD_CREATE, options->User) < 0) {
- log_err(LD_OR, "Problem creating/checking key directory %s", fname);
- tor_free(fname);
- goto err;
- }
- tor_free(fname);
+ if (create_keys_directory(options) < 0)
+ return -1;
+
+ char *fname;
if (options->master_key_fname) {
fname = tor_strdup(options->master_key_fname);
flags |= INIT_ED_KEY_EXPLICIT_FNAME;
} else {
- fname = options_get_datadir_fname2(options, "keys", "ed25519_master_id");
+ fname = options_get_keydir_fname(options, "ed25519_master_id");
}
id = ed_key_init_from_file(
fname,
@@ -852,8 +841,8 @@ load_ed_keys(const or_options_t *options, time_t now)
id = tor_malloc_zero(sizeof(*id));
memcpy(&id->pubkey, &check_signing_cert->signing_key,
sizeof(ed25519_public_key_t));
- fname = options_get_datadir_fname2(options, "keys",
- "ed25519_master_id_public_key");
+ fname = options_get_keydir_fname(options,
+ "ed25519_master_id_public_key");
if (ed25519_pubkey_write_to_file(&id->pubkey, fname, "type0") < 0) {
log_warn(LD_OR, "Error while attempting to write master public key "
"to disk");
@@ -894,7 +883,7 @@ load_ed_keys(const or_options_t *options, time_t now)
INIT_ED_KEY_NEEDCERT|
INIT_ED_KEY_INCLUDE_SIGNING_KEY_IN_CERT);
char *fname =
- options_get_datadir_fname2(options, "keys", "ed25519_signing");
+ options_get_keydir_fname(options, "ed25519_signing");
ed25519_keypair_free(sign);
tor_cert_free(sign_cert);
sign = ed_key_init_from_file(fname,
@@ -1185,7 +1174,7 @@ log_master_signing_key_cert_expiration(const or_options_t *options)
int failed = 0;
time_t now = approx_time();
- fn = options_get_datadir_fname2(options, "keys", "ed25519_signing_cert");
+ fn = options_get_keydir_fname(options, "ed25519_signing_cert");
/* Try to grab our cached copy of the key. */
signing_key = get_master_signing_key_cert();
diff --git a/src/or/routerlist.c b/src/or/routerlist.c
index 0cbd1388cd..d8c8a81738 100644
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@ -143,6 +143,10 @@ DECLARE_TYPED_DIGESTMAP_FNS(dsmap_, digest_ds_map_t, download_status_t)
#define DSMAP_FOREACH(map, keyvar, valvar) \
DIGESTMAP_FOREACH(dsmap_to_digestmap(map), keyvar, download_status_t *, \
valvar)
+#define eimap_free(map, fn) MAP_FREE_AND_NULL(eimap, (map), (fn))
+#define rimap_free(map, fn) MAP_FREE_AND_NULL(rimap, (map), (fn))
+#define dsmap_free(map, fn) MAP_FREE_AND_NULL(dsmap, (map), (fn))
+#define sdmap_free(map, fn) MAP_FREE_AND_NULL(sdmap, (map), (fn))
/* Forward declaration for cert_list_t */
typedef struct cert_list_t cert_list_t;
@@ -159,7 +163,6 @@ static const routerstatus_t *router_pick_dirserver_generic(
smartlist_t *sourcelist,
dirinfo_type_t type, int flags);
static void mark_all_dirservers_up(smartlist_t *server_list);
-static void dir_server_free(dir_server_t *ds);
static int signed_desc_digest_is_recognized(signed_descriptor_t *desc);
static const char *signed_descriptor_get_body_impl(
const signed_descriptor_t *desc,
@@ -443,9 +446,12 @@ download_status_for_authority_id_and_sk,(const char *id_digest,
return dl;
}
+#define cert_list_free(val) \
+ FREE_AND_NULL(cert_list_t, cert_list_free_, (val))
+
/** Release all space held by a cert_list_t */
static void
-cert_list_free(cert_list_t *cl)
+cert_list_free_(cert_list_t *cl)
{
if (!cl)
return;
@@ -459,9 +465,9 @@ cert_list_free(cert_list_t *cl)
/** Wrapper for cert_list_free so we can pass it to digestmap_free */
static void
-cert_list_free_(void *cl)
+cert_list_free_void(void *cl)
{
- cert_list_free(cl);
+ cert_list_free_(cl);
}
/** Reload the cached v3 key certificates from the cached-certs file in
@@ -473,7 +479,7 @@ trusted_dirs_reload_certs(void)
char *contents;
int r;
- filename = get_datadir_fname("cached-certs");
+ filename = get_cachedir_fname("cached-certs");
contents = read_file_to_str(filename, RFTS_IGNORE_MISSING, NULL);
tor_free(filename);
if (!contents)
@@ -662,7 +668,7 @@ trusted_dirs_flush_certs_to_disk(void)
});
} DIGESTMAP_FOREACH_END;
- filename = get_datadir_fname("cached-certs");
+ filename = get_cachedir_fname("cached-certs");
if (write_chunks_to_file(filename, chunks, 0, 0)) {
log_warn(LD_FS, "Error writing certificates to disk.");
}
@@ -1339,7 +1345,7 @@ static int
signed_desc_append_to_journal(signed_descriptor_t *desc,
desc_store_t *store)
{
- char *fname = get_datadir_fname_suffix(store->fname_base, ".new");
+ char *fname = get_cachedir_fname_suffix(store->fname_base, ".new");
const char *body = signed_descriptor_get_body_impl(desc,1);
size_t len = desc->signed_descriptor_len + desc->annotations_len;
@@ -1410,8 +1416,8 @@ router_rebuild_store(int flags, desc_store_t *store)
log_info(LD_DIR, "Rebuilding %s cache", store->description);
- fname = get_datadir_fname(store->fname_base);
- fname_tmp = get_datadir_fname_suffix(store->fname_base, ".tmp");
+ fname = get_cachedir_fname(store->fname_base);
+ fname_tmp = get_cachedir_fname_suffix(store->fname_base, ".tmp");
chunk_list = smartlist_new();
@@ -1508,7 +1514,7 @@ router_rebuild_store(int flags, desc_store_t *store)
} SMARTLIST_FOREACH_END(sd);
tor_free(fname);
- fname = get_datadir_fname_suffix(store->fname_base, ".new");
+ fname = get_cachedir_fname_suffix(store->fname_base, ".new");
write_str_to_file(fname, "", 1);
r = 0;
@@ -1538,7 +1544,7 @@ router_reload_router_list_impl(desc_store_t *store)
int extrainfo = (store->type == EXTRAINFO_STORE);
store->journal_len = store->store_len = 0;
- fname = get_datadir_fname(store->fname_base);
+ fname = get_cachedir_fname(store->fname_base);
if (store->mmap) {
/* get rid of it first */
@@ -1565,7 +1571,7 @@ router_reload_router_list_impl(desc_store_t *store)
}
tor_free(fname);
- fname = get_datadir_fname_suffix(store->fname_base, ".new");
+ fname = get_cachedir_fname_suffix(store->fname_base, ".new");
/* don't load empty files - we wouldn't get any data, even if we tried */
if (file_status(fname) == FN_FILE)
contents = read_file_to_str(fname, RFTS_BIN|RFTS_IGNORE_MISSING, &st);
@@ -2839,7 +2845,10 @@ router_choose_random_node(smartlist_t *excludedsmartlist,
}
} SMARTLIST_FOREACH_END(node);
- if ((r = routerlist_find_my_routerinfo()))
+ /* If the node_t is not found we won't be to exclude ourself but we
+ * won't be able to pick ourself in router_choose_random_node() so
+ * this is fine to at least try with our routerinfo_t object. */
+ if ((r = router_get_my_routerinfo()))
routerlist_add_node_and_family(excludednodes, r);
router_add_running_nodes_to_smartlist(sl, need_uptime, need_capacity,
@@ -3164,7 +3173,7 @@ router_get_routerlist(void)
/** Free all storage held by <b>router</b>. */
void
-routerinfo_free(routerinfo_t *router)
+routerinfo_free_(routerinfo_t *router)
{
if (!router)
return;
@@ -3194,7 +3203,7 @@ routerinfo_free(routerinfo_t *router)
/** Release all storage held by <b>extrainfo</b> */
void
-extrainfo_free(extrainfo_t *extrainfo)
+extrainfo_free_(extrainfo_t *extrainfo)
{
if (!extrainfo)
return;
@@ -3206,9 +3215,12 @@ extrainfo_free(extrainfo_t *extrainfo)
tor_free(extrainfo);
}
+#define signed_descriptor_free(val) \
+ FREE_AND_NULL(signed_descriptor_t, signed_descriptor_free_, (val))
+
/** Release storage held by <b>sd</b>. */
static void
-signed_descriptor_free(signed_descriptor_t *sd)
+signed_descriptor_free_(signed_descriptor_t *sd)
{
if (!sd)
return;
@@ -3262,21 +3274,21 @@ signed_descriptor_from_routerinfo(routerinfo_t *ri)
/** Helper: free the storage held by the extrainfo_t in <b>e</b>. */
static void
-extrainfo_free_(void *e)
+extrainfo_free_void(void *e)
{
- extrainfo_free(e);
+ extrainfo_free_(e);
}
/** Free all storage held by a routerlist <b>rl</b>. */
void
-routerlist_free(routerlist_t *rl)
+routerlist_free_(routerlist_t *rl)
{
if (!rl)
return;
rimap_free(rl->identity_map, NULL);
sdmap_free(rl->desc_digest_map, NULL);
sdmap_free(rl->desc_by_eid_map, NULL);
- eimap_free(rl->extra_info_map, extrainfo_free_);
+ eimap_free(rl->extra_info_map, extrainfo_free_void);
SMARTLIST_FOREACH(rl->routers, routerinfo_t *, r,
routerinfo_free(r));
SMARTLIST_FOREACH(rl->old_routers, signed_descriptor_t *, sd,
@@ -3768,7 +3780,7 @@ routerlist_free_all(void)
smartlist_free(fallback_dir_servers);
trusted_dir_servers = fallback_dir_servers = NULL;
if (trusted_dir_certs) {
- digestmap_free(trusted_dir_certs, cert_list_free_);
+ digestmap_free(trusted_dir_certs, cert_list_free_void);
trusted_dir_certs = NULL;
}
}
@@ -4545,7 +4557,7 @@ signed_desc_digest_is_recognized(signed_descriptor_t *desc)
void
update_all_descriptor_downloads(time_t now)
{
- if (get_options()->DisableNetwork)
+ if (should_delay_dir_fetches(get_options(), NULL))
return;
update_router_descriptor_downloads(now);
update_microdesc_downloads(now);
@@ -4736,7 +4748,7 @@ dir_server_add(dir_server_t *ent)
/** Free storage held in <b>cert</b>. */
void
-authority_cert_free(authority_cert_t *cert)
+authority_cert_free_(authority_cert_t *cert)
{
if (!cert)
return;
@@ -4748,9 +4760,12 @@ authority_cert_free(authority_cert_t *cert)
tor_free(cert);
}
+#define dir_server_free(val) \
+ FREE_AND_NULL(dir_server_t, dir_server_free_, (val))
+
/** Free storage held in <b>ds</b>. */
static void
-dir_server_free(dir_server_t *ds)
+dir_server_free_(dir_server_t *ds)
{
if (!ds)
return;
@@ -5024,6 +5039,11 @@ launch_descriptor_downloads(int purpose,
log_debug(LD_DIR,
"There are enough downloadable %ss to launch requests.",
descname);
+ } else if (! router_have_minimum_dir_info()) {
+ log_debug(LD_DIR,
+ "We are only missing %d %ss, but we'll fetch anyway, since "
+ "we don't yet have enough directory info.",
+ n_downloadable, descname);
} else {
/* should delay */
@@ -5192,10 +5212,23 @@ update_consensus_router_descriptor_downloads(time_t now, int is_vote,
log_warn(LD_BUG, "Failed to re-parse a router.");
continue;
}
+ /* need to compute this now, since add_to_routerlist may free. */
+ char time_cert_expires[ISO_TIME_LEN+1];
+ format_iso_time(time_cert_expires, ri->cert_expiration_time);
+
r = router_add_to_routerlist(ri, &msg, 1, 0);
if (WRA_WAS_OUTDATED(r)) {
- log_warn(LD_DIR, "Couldn't add re-parsed router: %s",
+ log_warn(LD_DIR, "Couldn't add re-parsed router: %s. This isn't "
+ "usually a big deal, but you should make sure that your "
+ "clock and timezone are set correctly.",
msg?msg:"???");
+ if (r == ROUTER_CERTS_EXPIRED) {
+ char time_cons[ISO_TIME_LEN+1];
+ format_iso_time(time_cons, consensus->valid_after);
+ log_warn(LD_DIR, " (I'm looking at a consensus from %s; This "
+ "router's certificates began expiring at %s.)",
+ time_cons, time_cert_expires);
+ }
}
} SMARTLIST_FOREACH_END(sd);
routerlist_assert_ok(rl);
diff --git a/src/or/routerlist.h b/src/or/routerlist.h
index 8384c7eb8c..83f4d1002f 100644
--- a/src/or/routerlist.h
+++ b/src/or/routerlist.h
@@ -96,9 +96,13 @@ MOCK_DECL(signed_descriptor_t *,extrainfo_get_by_descriptor_digest,
const char *signed_descriptor_get_body(const signed_descriptor_t *desc);
const char *signed_descriptor_get_annotations(const signed_descriptor_t *desc);
routerlist_t *router_get_routerlist(void);
-void routerinfo_free(routerinfo_t *router);
-void extrainfo_free(extrainfo_t *extrainfo);
-void routerlist_free(routerlist_t *rl);
+void routerinfo_free_(routerinfo_t *router);
+#define routerinfo_free(router) \
+ FREE_AND_NULL(routerinfo_t, routerinfo_free_, (router))
+void extrainfo_free_(extrainfo_t *extrainfo);
+#define extrainfo_free(ei) FREE_AND_NULL(extrainfo_t, extrainfo_free_, (ei))
+void routerlist_free_(routerlist_t *rl);
+#define routerlist_free(rl) FREE_AND_NULL(routerlist_t, routerlist_free_, (rl))
void dump_routerlist_mem_usage(int severity);
void routerlist_remove(routerlist_t *rl, routerinfo_t *ri, int make_old,
time_t now);
@@ -191,7 +195,9 @@ dir_server_t *fallback_dir_server_new(const tor_addr_t *addr,
const char *id_digest, double weight);
void dir_server_add(dir_server_t *ent);
-void authority_cert_free(authority_cert_t *cert);
+void authority_cert_free_(authority_cert_t *cert);
+#define authority_cert_free(cert) \
+ FREE_AND_NULL(authority_cert_t, authority_cert_free_, (cert))
void clear_dir_servers(void);
void update_consensus_router_descriptor_downloads(time_t now, int is_vote,
networkstatus_t *consensus);
diff --git a/src/or/routerparse.c b/src/or/routerparse.c
index 65874ae068..f1895ce313 100644
--- a/src/or/routerparse.c
+++ b/src/or/routerparse.c
@@ -2701,8 +2701,10 @@ routerstatus_parse_entry_from_string(memarea_t *area,
rs->protocols_known = 1;
rs->supports_extend2_cells =
protocol_list_supports_protocol(tok->args[0], PRT_RELAY, 2);
- rs->supports_ed25519_link_handshake =
+ rs->supports_ed25519_link_handshake_compat =
protocol_list_supports_protocol(tok->args[0], PRT_LINKAUTH, 3);
+ rs->supports_ed25519_link_handshake_any =
+ protocol_list_supports_protocol_or_later(tok->args[0], PRT_LINKAUTH, 3);
rs->supports_ed25519_hs_intro =
protocol_list_supports_protocol(tok->args[0], PRT_HSINTRO, 4);
rs->supports_v3_hsdir =
diff --git a/src/or/routerset.c b/src/or/routerset.c
index 54e26ef943..a2599b316c 100644
--- a/src/or/routerset.c
+++ b/src/or/routerset.c
@@ -437,7 +437,7 @@ routerset_equal(const routerset_t *old, const routerset_t *new)
/** Free all storage held in <b>routerset</b>. */
void
-routerset_free(routerset_t *routerset)
+routerset_free_(routerset_t *routerset)
{
if (!routerset)
return;
diff --git a/src/or/routerset.h b/src/or/routerset.h
index d8819ef3fd..53e8c66c5e 100644
--- a/src/or/routerset.h
+++ b/src/or/routerset.h
@@ -40,7 +40,8 @@ void routerset_subtract_nodes(smartlist_t *out,
char *routerset_to_string(const routerset_t *routerset);
int routerset_equal(const routerset_t *old, const routerset_t *new);
-void routerset_free(routerset_t *routerset);
+void routerset_free_(routerset_t *routerset);
+#define routerset_free(rs) FREE_AND_NULL(routerset_t, routerset_free_, (rs))
int routerset_len(const routerset_t *set);
#ifdef ROUTERSET_PRIVATE
diff --git a/src/or/scheduler.c b/src/or/scheduler.c
index 510c16b217..cd047d5a75 100644
--- a/src/or/scheduler.c
+++ b/src/or/scheduler.c
@@ -171,6 +171,8 @@ STATIC smartlist_t *channels_pending = NULL;
*/
STATIC struct event *run_sched_ev = NULL;
+static int have_logged_kist_suddenly_disabled = 0;
+
/*****************************************************************************
* Scheduling system static function definitions
*
@@ -252,13 +254,32 @@ select_scheduler(void)
case SCHEDULER_KIST:
if (!scheduler_can_use_kist()) {
#ifdef HAVE_KIST_SUPPORT
- log_notice(LD_SCHED, "Scheduler type KIST has been disabled by "
- "the consensus or no kernel support.");
+ if (!have_logged_kist_suddenly_disabled) {
+ /* We should only log this once in most cases. If it was the kernel
+ * losing support for kist that caused scheduler_can_use_kist() to
+ * return false, then this flag makes sure we only log this message
+ * once. If it was the consensus that switched from "yes use kist"
+ * to "no don't use kist", then we still set the flag so we log
+ * once, but we unset the flag elsewhere if we ever can_use_kist()
+ * again.
+ */
+ have_logged_kist_suddenly_disabled = 1;
+ log_notice(LD_SCHED, "Scheduler type KIST has been disabled by "
+ "the consensus or no kernel support.");
+ }
#else /* !(defined(HAVE_KIST_SUPPORT)) */
log_info(LD_SCHED, "Scheduler type KIST not built in");
#endif /* defined(HAVE_KIST_SUPPORT) */
continue;
}
+ /* This flag will only get set in one of two cases:
+ * 1 - the kernel lost support for kist. In that case, we don't expect to
+ * ever end up here
+ * 2 - the consensus went from "yes use kist" to "no don't use kist".
+ * We might end up here if the consensus changes back to "yes", in which
+ * case we might want to warn the user again if it goes back to "no"
+ * yet again. Thus we unset the flag */
+ have_logged_kist_suddenly_disabled = 0;
new_scheduler = get_kist_scheduler();
scheduler_kist_set_full_mode();
goto end;
diff --git a/src/or/scheduler_kist.c b/src/or/scheduler_kist.c
index d1726ba345..e02926e478 100644
--- a/src/or/scheduler_kist.c
+++ b/src/or/scheduler_kist.c
@@ -461,7 +461,7 @@ kist_free_all(void)
/* Function of the scheduler interface: on_channel_free() */
static void
-kist_on_channel_free(const channel_t *chan)
+kist_on_channel_free_fn(const channel_t *chan)
{
free_socket_info_by_chan(&socket_table, chan);
}
@@ -525,9 +525,13 @@ kist_scheduler_schedule(void)
monotime_get(&now);
/* If time is really monotonic, we can never have now being smaller than the
- * last scheduler run. The scheduler_last_run at first is set to 0. */
+ * last scheduler run. The scheduler_last_run at first is set to 0.
+ * Unfortunately, not all platforms guarantee monotonic time so we log at
+ * info level but don't make it more noisy. */
diff = monotime_diff_msec(&scheduler_last_run, &now);
- IF_BUG_ONCE(diff < 0) {
+ if (diff < 0) {
+ log_info(LD_SCHED, "Monotonic time between now and last run of scheduler "
+ "is negative: %" PRId64 ". Setting diff to 0.", diff);
diff = 0;
}
if (diff < sched_run_interval) {
@@ -602,9 +606,12 @@ kist_scheduler_run(void)
* fails leading to the channel to be closed which triggers a release
* and free its entry in the socket table. And because of a engineering
* design issue, the error is not propagated back so we don't get an
- * error at this poin. So before we continue, make sure the channel is
+ * error at this point. So before we continue, make sure the channel is
* open and if not just ignore it. See #23751. */
if (!CHANNEL_IS_OPEN(chan)) {
+ /* Channel isn't open so we put it back in IDLE mode. It is either
+ * renegotiating its TLS session or about to be released. */
+ chan->scheduler_state = SCHED_CHAN_IDLE;
continue;
}
/* flush_result has the # cells flushed */
@@ -724,7 +731,7 @@ kist_scheduler_run(void)
static scheduler_t kist_scheduler = {
.type = SCHEDULER_KIST,
.free_all = kist_free_all,
- .on_channel_free = kist_on_channel_free,
+ .on_channel_free = kist_on_channel_free_fn,
.init = kist_scheduler_init,
.on_new_consensus = kist_scheduler_on_new_consensus,
.schedule = kist_scheduler_schedule,
diff --git a/src/or/shared_random.c b/src/or/shared_random.c
index b3f62a8fd8..7723ad4611 100644
--- a/src/or/shared_random.c
+++ b/src/or/shared_random.c
@@ -384,7 +384,7 @@ commit_encode(const sr_commit_t *commit, char *dst, size_t len)
static void
sr_cleanup(void)
{
- sr_state_free();
+ sr_state_free_all();
}
/* Using <b>commit</b>, return a newly allocated string containing the commit
@@ -897,7 +897,7 @@ sr_srv_encode(char *dst, size_t dst_len, const sr_srv_t *srv)
/* Free a commit object. */
void
-sr_commit_free(sr_commit_t *commit)
+sr_commit_free_(sr_commit_t *commit)
{
if (commit == NULL) {
return;
diff --git a/src/or/shared_random.h b/src/or/shared_random.h
index c0992489cb..675a8d8b06 100644
--- a/src/or/shared_random.h
+++ b/src/or/shared_random.h
@@ -113,7 +113,8 @@ sr_srv_t *sr_parse_srv(const smartlist_t *args);
char *sr_get_string_for_vote(void);
char *sr_get_string_for_consensus(const smartlist_t *votes,
int32_t num_srv_agreements);
-void sr_commit_free(sr_commit_t *commit);
+void sr_commit_free_(sr_commit_t *commit);
+#define sr_commit_free(sr) FREE_AND_NULL(sr_commit_t, sr_commit_free_, (sr))
void sr_srv_encode(char *dst, size_t dst_len, const sr_srv_t *srv);
/* Private methods (only used by shared_random_state.c): */
diff --git a/src/or/shared_random_state.c b/src/or/shared_random_state.c
index ae904cfda3..d6109b2de7 100644
--- a/src/or/shared_random_state.c
+++ b/src/or/shared_random_state.c
@@ -271,12 +271,15 @@ commit_add_to_state(sr_commit_t *commit, sr_state_t *state)
static void
commit_free_(void *p)
{
- sr_commit_free(p);
+ sr_commit_free_(p);
}
+#define state_free(val) \
+ FREE_AND_NULL(sr_state_t, state_free_, (val))
+
/* Free a state that was allocated with state_new(). */
static void
-state_free(sr_state_t *state)
+state_free_(sr_state_t *state)
{
if (state == NULL) {
return;
@@ -318,9 +321,12 @@ state_set(sr_state_t *state)
sr_state = state;
}
+#define disk_state_free(val) \
+ FREE_AND_NULL(sr_disk_state_t, disk_state_free_, (val))
+
/* Free an allocated disk state. */
static void
-disk_state_free(sr_disk_state_t *state)
+disk_state_free_(sr_disk_state_t *state)
{
if (state == NULL) {
return;
@@ -1286,7 +1292,7 @@ sr_state_srv_is_fresh(void)
/* Cleanup and free our disk and memory state. */
void
-sr_state_free(void)
+sr_state_free_all(void)
{
state_free(sr_state);
disk_state_free(sr_disk_state);
diff --git a/src/or/shared_random_state.h b/src/or/shared_random_state.h
index 866725c435..fdbbf4919a 100644
--- a/src/or/shared_random_state.h
+++ b/src/or/shared_random_state.h
@@ -119,7 +119,7 @@ void sr_state_unset_fresh_srv(void);
int sr_state_init(int save_to_disk, int read_from_disk);
int sr_state_is_initialized(void);
void sr_state_save(void);
-void sr_state_free(void);
+void sr_state_free_all(void);
time_t sr_state_get_start_time_of_current_protocol_run(time_t now);
unsigned int sr_state_get_phase_duration(void);
diff --git a/src/or/statefile.c b/src/or/statefile.c
index 97bd9cac36..cc114f0a2b 100644
--- a/src/or/statefile.c
+++ b/src/or/statefile.c
@@ -681,7 +681,7 @@ save_transport_to_state(const char *transport,
}
STATIC void
-or_state_free(or_state_t *state)
+or_state_free_(or_state_t *state)
{
if (!state)
return;
diff --git a/src/or/statefile.h b/src/or/statefile.h
index 574afb3622..b4cc4d1dc6 100644
--- a/src/or/statefile.h
+++ b/src/or/statefile.h
@@ -20,7 +20,8 @@ void or_state_free_all(void);
#ifdef STATEFILE_PRIVATE
STATIC config_line_t *get_transport_in_state_by_name(const char *transport);
-STATIC void or_state_free(or_state_t *state);
+STATIC void or_state_free_(or_state_t *state);
+#define or_state_free(st) FREE_AND_NULL(or_state_t, or_state_free_, (st))
STATIC or_state_t *or_state_new(void);
#endif
diff --git a/src/or/tor_api_internal.h b/src/or/tor_api_internal.h
index a69ba76420..10b6278b7b 100644
--- a/src/or/tor_api_internal.h
+++ b/src/or/tor_api_internal.h
@@ -16,5 +16,5 @@ struct tor_main_configuration_t {
char **argv;
};
-#endif
+#endif /* !defined(TOR_API_INTERNAL_H) */
diff --git a/src/or/torcert.c b/src/or/torcert.c
index befb39d6e8..bd677d1f4a 100644
--- a/src/or/torcert.c
+++ b/src/or/torcert.c
@@ -137,7 +137,7 @@ tor_cert_create(const ed25519_keypair_t *signing_key,
/** Release all storage held for <b>cert</b>. */
void
-tor_cert_free(tor_cert_t *cert)
+tor_cert_free_(tor_cert_t *cert)
{
if (! cert)
return;
@@ -453,7 +453,7 @@ or_handshake_certs_new(void)
/** Release all storage held in <b>certs</b> */
void
-or_handshake_certs_free(or_handshake_certs_t *certs)
+or_handshake_certs_free_(or_handshake_certs_t *certs)
{
if (!certs)
return;
diff --git a/src/or/torcert.h b/src/or/torcert.h
index c77ae2089d..0a8a252049 100644
--- a/src/or/torcert.h
+++ b/src/or/torcert.h
@@ -57,7 +57,8 @@ tor_cert_t *tor_cert_create(const ed25519_keypair_t *signing_key,
tor_cert_t *tor_cert_parse(const uint8_t *cert, size_t certlen);
-void tor_cert_free(tor_cert_t *cert);
+void tor_cert_free_(tor_cert_t *cert);
+#define tor_cert_free(cert) FREE_AND_NULL(tor_cert_t, tor_cert_free_, (cert))
int tor_cert_get_checkable_sig(ed25519_checkable_t *checkable_out,
const tor_cert_t *out,
@@ -83,7 +84,9 @@ rsa_ed25519_crosscert_check, (const uint8_t *crosscert,
const time_t reject_if_expired_before));
or_handshake_certs_t *or_handshake_certs_new(void);
-void or_handshake_certs_free(or_handshake_certs_t *certs);
+void or_handshake_certs_free_(or_handshake_certs_t *certs);
+#define or_handshake_certs_free(certs) \
+ FREE_AND_NULL(or_handshake_certs_t, or_handshake_certs_free_, (certs))
int or_handshake_certs_rsa_ok(int severity,
or_handshake_certs_t *certs,
tor_tls_t *tls,
diff --git a/src/or/transports.c b/src/or/transports.c
index 68d1354844..04b24b0f81 100644
--- a/src/or/transports.c
+++ b/src/or/transports.c
@@ -154,7 +154,7 @@ transport_new(const tor_addr_t *addr, uint16_t port,
/** Free the pluggable transport struct <b>transport</b>. */
void
-transport_free(transport_t *transport)
+transport_free_(transport_t *transport)
{
if (!transport)
return;
diff --git a/src/or/transports.h b/src/or/transports.h
index e368e447c3..1b2786472c 100644
--- a/src/or/transports.h
+++ b/src/or/transports.h
@@ -35,7 +35,8 @@ void sweep_transport_list(void);
MOCK_DECL(int, transport_add_from_config,
(const tor_addr_t *addr, uint16_t port,
const char *name, int socks_ver));
-void transport_free(transport_t *transport);
+void transport_free_(transport_t *transport);
+#define transport_free(tr) FREE_AND_NULL(transport_t, transport_free_, (tr))
transport_t *transport_get_by_name(const char *name);