aboutsummaryrefslogtreecommitdiff
path: root/src/or/circuitlist.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/or/circuitlist.c')
-rw-r--r--src/or/circuitlist.c59
1 files changed, 59 insertions, 0 deletions
diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c
index ad9b902ac6..fdb039ef0d 100644
--- a/src/or/circuitlist.c
+++ b/src/or/circuitlist.c
@@ -55,6 +55,7 @@
#include "or.h"
#include "channel.h"
+#include "channeltls.h"
#include "circpathbias.h"
#include "circuitbuild.h"
#include "circuitlist.h"
@@ -1994,6 +1995,61 @@ circuit_mark_all_dirty_circs_as_unusable(void)
SMARTLIST_FOREACH_END(circ);
}
+/**
+ * Report any queued cells on or_circuits as written in our bandwidth
+ * totals, for the specified channel direction.
+ *
+ * When we close a circuit or clear its cell queues, we've read
+ * data and recorded those bytes in our read statistics, but we're
+ * not going to write it. This discrepancy can be used by an adversary
+ * to infer information from our public relay statistics and perform
+ * attacks such as guard discovery.
+ *
+ * This function is in the critical path of circuit_mark_for_close().
+ * It must be (and is) O(1)!
+ *
+ * See https://trac.torproject.org/projects/tor/ticket/23512.
+ */
+void
+circuit_synchronize_written_or_bandwidth(const circuit_t *c,
+ circuit_channel_direction_t dir)
+{
+ uint64_t cells;
+ uint64_t cell_size;
+ uint64_t written_sync;
+ const channel_t *chan = NULL;
+ const or_circuit_t *or_circ;
+
+ if (!CIRCUIT_IS_ORCIRC(c))
+ return;
+
+ or_circ = CONST_TO_OR_CIRCUIT(c);
+
+ if (dir == CIRCUIT_N_CHAN) {
+ chan = c->n_chan;
+ cells = c->n_chan_cells.n;
+ } else {
+ chan = or_circ->p_chan;
+ cells = or_circ->p_chan_cells.n;
+ }
+
+ /* If we still know the chan, determine real cell size. Otherwise,
+ * assume it's a wide circid channel */
+ if (chan)
+ cell_size = get_cell_network_size(chan->wide_circ_ids);
+ else
+ cell_size = CELL_MAX_NETWORK_SIZE;
+
+ /* The missing written bytes are the cell counts times their cell
+ * size plus TLS per cell overhead */
+ written_sync = cells*(cell_size+TLS_PER_CELL_OVERHEAD);
+
+ /* Report the missing bytes as written, to avoid asymmetry.
+ * We must use time() for consistency with rephist, even though on
+ * some very old rare platforms, approx_time() may be faster. */
+ rep_hist_note_bytes_written(written_sync, time(NULL));
+}
+
/** Mark <b>circ</b> to be closed next time we call
* circuit_close_all_marked(). Do any cleanup needed:
* - If state is onionskin_pending, remove circ from the onion_pending
@@ -2045,6 +2101,9 @@ circuit_mark_for_close_, (circuit_t *circ, int reason, int line,
reason = END_CIRC_REASON_NONE;
}
+ circuit_synchronize_written_or_bandwidth(circ, CIRCUIT_N_CHAN);
+ circuit_synchronize_written_or_bandwidth(circ, CIRCUIT_P_CHAN);
+
if (reason & END_CIRC_REASON_FLAG_REMOTE)
reason &= ~END_CIRC_REASON_FLAG_REMOTE;